Apache Camel反序列化异常时如何保留原始文件?
我来帮你搞定这个问题!你的核心困扰在于:处理流程中修改了Exchange的Body内容,导致解析异常触发时,没办法拿到原始文件的数据来移动——现在写入异常目录的其实是反序列化后的对象字符串,而非原始文件内容。
下面给你两种可行的解决方案,按需选择:
方案1:直接操作原始文件(推荐)
Camel的File组件会自动在Exchange的Header里带上原始文件的关键信息,比如CamelFileAbsolutePath(文件绝对路径)、CamelFileName(文件名)、CamelFileParent(父目录路径)。我们完全可以利用这些信息直接移动原始文件,不用通过Body重新写入,既高效又能100%保留原始数据。
修改你的doCatch块配置:
<doCatch id="_ParsingException"> <exception>org.apache.camel.component.bean.MethodNotFoundException</exception> <exception>org.apache.camel.NoTypeConversionAvailableException</exception> <!-- 直接借助Header里的原始文件信息移动,无需修改Body --> <toD id="_MoveErrorFile" uri="file:${header.CamelFileParent}/FATAL?fileName=${header.CamelFileName}&fileExist=Override"/> </doCatch>
这里fileExist=Override是为了防止异常目录已有同名文件时报错,你可以根据实际需求调整这个参数。
如果需要更灵活的文件操作(比如创建目录、校验文件状态),也可以写一个简单的Processor来处理:
import org.apache.camel.Exchange; import java.io.File; public class ErrorFileMover { public void moveOriginalFile(Exchange exchange) { // 从Header获取原始文件的关键信息 String originalFilePath = exchange.getIn().getHeader(Exchange.FILE_PATH, String.class); String fatalDirPath = exchange.getIn().getHeader(Exchange.FILE_PARENT, String.class) + File.separator + "FATAL"; File originalFile = new File(originalFilePath); File fatalDir = new File(fatalDirPath); // 确保异常目录存在 if (!fatalDir.exists()) { fatalDir.mkdirs(); } // 移动原始文件到异常目录 boolean isMoved = originalFile.renameTo(new File(fatalDir, originalFile.getName())); if (!isMoved) { throw new RuntimeException("Failed to move error file: " + originalFilePath); } } }
然后在doCatch里调用这个Processor:
<doCatch id="_ParsingException"> <exception>org.apache.camel.component.bean.MethodNotFoundException</exception> <exception>org.apache.camel.NoTypeConversionAvailableException</exception> <process ref="errorFileMover"/> </doCatch>
记得在Spring上下文里注册这个Bean:
<bean id="errorFileMover" class="com.yourpackage.ErrorFileMover"/>
方案2:提前保存原始文件内容到Header
如果你更倾向于通过Body写入异常文件,可以在处理流程的最开始,把原始文件的内容存到一个自定义Header中。这样就算后续修改了Body,异常时也能从Header里恢复原始数据。
调整你的doTry块:
<doTry id="_CheckException"> <!-- 先把原始文件内容保存到自定义Header,用byte[]避免编码问题 --> <setHeader headerName="OriginalFileContent"> <convertBodyTo type="byte[]"/> </setHeader> <!-- 继续后续的转码和反序列化操作 --> <camel:convertBodyTo charset="ISO-8859-1" id="_ConvertEncoding" type="java.lang.String"/> <camel:unmarshal id="_FileParsing"> <camel:bindy classType="com.ktds.openmzn.dao.KRFixedFormat" locale="korea" type="Fixed"/> </camel:unmarshal> <doCatch id="_ParsingException"> <exception>org.apache.camel.component.bean.MethodNotFoundException</exception> <exception>org.apache.camel.NoTypeConversionAvailableException</exception> <!-- 从Header恢复原始文件内容作为Body --> <setBody> <simple>${header.OriginalFileContent}</simple> </setBody> <toD id="_MoveErrorFile" uri="file:${header.CamelFileParent}/FATAL"/> </doCatch> </doTry>
这里用byte[]来保存原始内容,是为了避免字符串编码转换导致的原始数据失真,尤其适合非纯文本的固定长度文件。
为什么你之前的方式不行?
你之前在doCatch里再次调用convertBodyTo,但此时Exchange的Body已经是反序列化失败后的对象(或者转码后的字符串),早就不是原始文件的内容了——所以最终写入异常目录的自然是解析后的格式,而非原始文件。
内容的提问来源于stack exchange,提问作者이성규

