如何在Apache Camel Bindy解析CSV时跳过无效记录?
解决Camel Bindy解析CSV时跳过无效记录的问题
问题背景
当前路由处理CSV文件时,因第二条记录的sellRate字段为非数值"Test",Bindy解析时抛出NumberFormatException,导致整个文件处理中断,所有记录都无法正常处理。需要实现跳过无效记录、正常处理其余有效记录的逻辑。
方案一:修改Bindy类,在实体转换阶段校验
将数值类型字段改为String,在转换业务实体时做格式校验,避免Bindy解析阶段抛出异常:
1. 更新ExchangeRateBindy类
@Data @CsvRecord(separator = "\\*", skipFirstLine = false) public class ExchangeRateBindy { @DataField(pos = 1) private String currencyId; @DataField(pos = 2) private String currencyName; @DataField(pos = 3) private String buyRate; @DataField(pos = 4) private String midRate; @DataField(pos = 5, defaultValue = "0") private String sellRate; private static final Logger log = LoggerFactory.getLogger(ExchangeRateBindy.class); public Optional<ExchangeRate> toExchangeRate() { try { // 尝试转换所有数值字段 double buy = Double.parseDouble(buyRate); double mid = Double.parseDouble(midRate); double sell = Double.parseDouble(sellRate); return Optional.of(ExchangeRate.builder() .currencyId(currencyId) .currencyName(currencyName) .buyRate(buy) .midRate(mid) .sellRate(sell) .build()); } catch (NumberFormatException e) { log.error("Invalid numeric value in record: {}", this, e); return Optional.empty(); } } }
2. 调整路由逻辑
添加split(body())拆分每条记录单独处理,转换时判断有效性,无效则跳过:
from("file:" + baseInputPath + "/exchangerates?noop=true") .idempotentConsumer(header(CAMEL_FILE_NAME), FileIdempotentRepository.fileIdempotentRepository(new File( baseInputPath + "/tracker/exchangeratefiles.txt"))) .log("Processing exchange rate file: ${header.CamelFileName}") .unmarshal().bindy(BindyType.Csv, ExchangeRateBindy.class) .split(body()) // 拆分CSV记录为单个实体 .process(exchange -> { ExchangeRateBindy bindyRecord = exchange.getIn().getBody(ExchangeRateBindy.class); // 仅保存转换成功的有效记录 bindyRecord.toExchangeRate().ifPresent(exchangeRateService::save); });
方案二:路由中捕获解析异常,直接跳过无效记录
保留Bindy类的数值类型定义,通过Camel的异常处理机制捕获解析异常,跳过单条无效记录:
调整路由结构
from("file:" + baseInputPath + "/exchangerates?noop=true") .idempotentConsumer(header(CAMEL_FILE_NAME), FileIdempotentRepository.fileIdempotentRepository(new File( baseInputPath + "/tracker/exchangeratefiles.txt"))) .log("Processing exchange rate file: ${header.CamelFileName}") .unmarshal().bindy(BindyType.Csv, ExchangeRateBindy.class) .split(body()) // 拆分每条记录单独处理 .doTry() .process(exchange -> { ExchangeRateBindy exchangeRateBindy = exchange.getIn().getBody(ExchangeRateBindy.class); exchangeRateService.save(exchangeRateBindy.toExchangeRate()); }) .doCatch(NumberFormatException.class) .log("Skipping invalid exchange rate record: ${body}") // 记录无效日志 .end(); // 结束异常处理块
关键说明
- 必须使用
split(body()):如果不拆分记录,Bindy解析整个文件时遇到第一条无效记录就会抛出异常,导致整个文件无法处理;拆分后每条记录独立解析,单条异常不影响其他记录。 doCatch块仅捕获当前记录的解析异常,处理完后继续执行下一条记录的处理逻辑。
内容的提问来源于stack exchange,提问作者Christian
相关产品推荐
相关产品推荐

