如何使用Spring Batch的Item Reader完成汇率文件垂直映射读取
答案
完全可以实现,Spring Batch支持自定义ItemReader逻辑适配这种特殊结构的汇率文件。
实现思路
因为文件仅包含2行内容(第一行货币标识、第二行对应汇率),默认逐行映射为单个业务对象的FlatFileItemReader不能直接满足需求,我们可以自定义ItemReader实现读取+配对逻辑,全程适配动态列数的扩展需求,后续新增货币不需要修改读取层代码。
具体实现步骤
1. 定义业务实体类
先创建存储货币汇率的实体类:
import java.math.BigDecimal; public class CurrencyRate { // 货币标识 private String currencyCode; // 对应汇率 private BigDecimal rate; // 此处省略getter、setter方法 }
2. 自定义ItemReader实现
自定义Reader一次性加载文件的两行内容,完成货币与汇率的配对,再逐个返回实体对象:
import org.springframework.batch.item.ItemReader; import org.springframework.core.io.Resource; import java.io.BufferedReader; import java.io.InputStreamReader; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class CurrencyRateItemReader implements ItemReader<CurrencyRate> { // 存储配对完成的汇率列表 private List<CurrencyRate> currencyRateList; // 读取游标 private int cursor = 0; public CurrencyRateItemReader(Resource rateFile) { this.currencyRateList = loadAndMapRateFile(rateFile); } private List<CurrencyRate> loadAndMapRateFile(Resource rateFile) { List<CurrencyRate> resultList = new ArrayList<>(); try (BufferedReader br = new BufferedReader(new InputStreamReader(rateFile.getInputStream()))) { // 读取第一行货币标识 String currencyLine = br.readLine(); if (currencyLine == null || currencyLine.isBlank()) { return resultList; } List<String> currencyCodeList = Arrays.stream(currencyLine.split(",")) .map(String::trim) .toList(); // 读取第二行汇率数值 String rateLine = br.readLine(); if (rateLine == null || rateLine.isBlank()) { return resultList; } List<String> rateStrList = Arrays.stream(rateLine.split(",")) .map(String::trim) .toList(); // 按索引配对,超出最小长度的异常列自动忽略 int validSize = Math.min(currencyCodeList.size(), rateStrList.size()); for (int i = 0; i < validSize; i++) { CurrencyRate rate = new CurrencyRate(); rate.setCurrencyCode(currencyCodeList.get(i)); rate.setRate(new BigDecimal(rateStrList.get(i))); resultList.add(rate); } } catch (Exception e) { throw new RuntimeException("汇率文件读取失败", e); } return resultList; } @Override public CurrencyRate read() { // 游标遍历完成后返回null通知Spring Batch读取结束 if (cursor < currencyRateList.size()) { return currencyRateList.get(cursor++); } return null; } }
3. 注册到Spring Batch上下文
在Batch配置类中注入自定义Reader即可,后续可以和常规Reader一样对接处理器、写入器使用:
import org.springframework.batch.item.ItemReader; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; @Configuration public class BatchConfig { @Bean public ItemReader<CurrencyRate> currencyRateItemReader( // 替换为你的汇率文件实际路径 @Value("${rate.file.path:classpath:exchange_rate.csv}") Resource rateFile ) { return new CurrencyRateItemReader(rateFile); } }
补充说明
如果不想完全自定义Reader,也可以扩展FlatFileItemReader,通过skippedLinesCallback先读取第一行的货币列表存到执行上下文中,再自定义LineMapper处理第二行的汇率值完成配对,不过自定义ItemReader的方式逻辑更直观,维护成本更低,也天然支持动态扩展的列数。
内容的提问来源于stack exchange,提问作者Hesitha Wijayasinghe
相关产品推荐
相关产品推荐

