Spring Batch:使用ClassifierCompositeItemWriter避免空文件写入表头
问题描述
项目采用Spring XML配置,使用ClassifierCompositeItemWriter根据某列数据分类,将数据写入四个不同文件(每个文件数据唯一)。当前遇到的问题是:当某个文件没有符合分类器的数据时,仍会写入表头,希望这类空文件保持纯空状态,不生成表头。
现有配置及代码如下:
XML配置
<bean id="someCvsWriter" class="org.springframework.batch.item.file.FlatFileItemWriter"> <property name="resource" value="file:csv/someReport.csv"/> <property name="shouldDeleteIfExists" value="true"/> <property name="encoding" value="UTF-8"/> <property name="lineAggregator" ref="someCustomLineAggregator"/> <property name="headerCallback" ref="someReportHeaderCallback" /> </bean>
HeaderCallback实现类
public class SomeReportFlatFileHeaderCallback implements FlatFileHeaderCallback { @Override public void writeHeader(Writer writer) throws IOException { writer.write("COL1, COL2, COL3"); } }
解决方案
方法1:扩展FlatFileItemWriter重写表头逻辑
直接扩展FlatFileItemWriter,内部跟踪是否有数据写入,仅在有数据时生成表头,无需额外依赖:
public class ConditionalHeaderFlatFileItemWriter<T> extends FlatFileItemWriter<T> { private boolean hasWrittenItems = false; @Override public void write(List<? extends T> items) throws Exception { if (!items.isEmpty()) { hasWrittenItems = true; super.write(items); } } @Override protected void writeHeader(Writer writer) throws IOException { // 仅当有数据写入时才输出表头 if (hasWrittenItems) { super.writeHeader(writer); } } @Override public void open(ExecutionContext executionContext) { super.open(executionContext); // 每次作业启动时重置标记 hasWrittenItems = false; } }
修改XML配置,替换原FlatFileItemWriter为自定义版本:
<bean id="someCvsWriter" class="com.yourpackage.ConditionalHeaderFlatFileItemWriter"> <property name="resource" value="file:csv/someReport.csv"/> <property name="shouldDeleteIfExists" value="true"/> <property name="encoding" value="UTF-8"/> <property name="lineAggregator" ref="someCustomLineAggregator"/> <property name="headerCallback" ref="someReportHeaderCallback" /> </bean>
方法2:自定义条件HeaderCallback(适合需复用原Header逻辑场景)
如果需要保留原HeaderCallback的逻辑,可通过计数Bean判断是否输出表头:
- 定义数据计数跟踪类
public class ItemCountTracker { private int count = 0; public void increment() { count++; } public boolean hasItems() { return count > 0; } public void reset() { count = 0; } }
- 实现条件HeaderCallback
public class ConditionalHeaderCallback implements FlatFileHeaderCallback { private FlatFileHeaderCallback delegate; private ItemCountTracker itemCountTracker; public ConditionalHeaderCallback(FlatFileHeaderCallback delegate, ItemCountTracker itemCountTracker) { this.delegate = delegate; this.itemCountTracker = itemCountTracker; } @Override public void writeHeader(Writer writer) throws IOException { if (itemCountTracker.hasItems()) { delegate.writeHeader(writer); } } }
- 包装原Writer实现计数
public class CountingItemWriter<T> implements ItemWriter<T> { private ItemWriter<T> delegate; private ItemCountTracker itemCountTracker; public CountingItemWriter(ItemWriter<T> delegate, ItemCountTracker itemCountTracker) { this.delegate = delegate; this.itemCountTracker = itemCountTracker; } @Override public void write(List<? extends T> items) throws Exception { if (!items.isEmpty()) { itemCountTracker.increment(); delegate.write(items); } } }
- 修改XML配置
<!-- 每个Writer对应独立的计数Bean,step作用域保证每次作业重置 --> <bean id="someItemCountTracker" class="com.yourpackage.ItemCountTracker" scope="step"/> <!-- 条件HeaderCallback依赖原Header和计数Bean --> <bean id="conditionalSomeHeaderCallback" class="com.yourpackage.ConditionalHeaderCallback"> <constructor-arg ref="someReportHeaderCallback"/> <constructor-arg ref="someItemCountTracker"/> </bean> <!-- 包装原Writer为计数Writer --> <bean id="countingSomeCvsWriter" class="com.yourpackage.CountingItemWriter"> <constructor-arg ref="someCvsWriter"/> <constructor-arg ref="someItemCountTracker"/> </bean> <!-- 更新原Writer的headerCallback为条件版本 --> <bean id="someCvsWriter" class="org.springframework.batch.item.file.FlatFileItemWriter"> <property name="resource" value="file:csv/someReport.csv"/> <property name="shouldDeleteIfExists" value="true"/> <property name="encoding" value="UTF-8"/> <property name="lineAggregator" ref="someCustomLineAggregator"/> <property name="headerCallback" ref="conditionalSomeHeaderCallback" /> </bean>
内容的提问来源于stack exchange,提问作者PAA
相关产品推荐
相关产品推荐

