You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 01:25:02