将行写入 csv 文件时,如何在 Spring 批处理中的 FlatFileItemWriter 中包含一个计数器

How to include a counter in FlatFileItemWriter in Spring Batch when writing rows to a csv file

因此,我正在使用 FlatFileItemWriter 从我可以从数据库中成功读取的数据写入一个 csv 文件。

我正在为如何写入与我正在写入文件的行相对应的整数(即行计数器)而苦苦挣扎。看起来很容易做,但很简单,我很难过。

一切正常(正在根据从数据库读取的数据生成文件)。但我似乎无法弄清楚如何以获取相应行数的方式实现我的 getCount() 方法。我认为这与利用 ChunkContext 有关,但我似乎无法弄清楚。

所以我的作业配置中的 bean 中有以下内容。

@Bean
public FlatFileItemWriter<Customer> customerItemWriter() throws Exception {

    FlatFileItemWriter<Customer> itemWriter = new FlatFileItemWriter<>();

    itemWriter.setLineAggregator(new CustomerLineAggregator());
    itemWriter.setResource(new FileSystemResource("/some/directory/file.csv"));
    itemWriter.afterPropertiesSet();

    return itemWriter;
}

我还有以下 LineAggregator 实现。

public class CustomerLineAggregator implements LineAggregator<Customer> {
    
    private ChunkContext chunkContext;
    
    @BeforeChunk
    private void beforeChunk(ChunkContext chunkContext) {
        this.setChunkContext(chunkContext);
    }
        
    @Override
    public String aggregate(Customer item) {
        
        return getCount() + "," + convertTime(item.getTime(), 3) + " ET," + item.getCustomerId() + "," + item.getLink() + "," + item.getName();
    }
    
    
    private String convertTime(String timeString, int offset) {
        
        LocalTime timeObject = LocalTime.parse(timeString);
        
        LocalTime timeOffsetObject = timeObject.plusHours(offset);
        
        return timeOffsetObject.toString();
        
    }
    
    private String getCount() {
        // how do I make use of the chunk context to infer the integer corresponding to the item assuming my chunk size is 1.
        return someCountString;
    }
    

    public ChunkContext getChunkContext() {
        return chunkContext;
    }

    public void setChunkContext(ChunkContext chunkContext) {
        this.chunkContext = chunkContext;
    }
    

}

预期的输出文件应如下所示:

1, 10:09 ET, 742, https://www.firm.com, John Doe
2, 12:30 ET, 235, http://www.firm.com, Jane Doe
3, 9:21 ET, 398, http://www.thomas.io, Thomas Chan
4, 14:38 ET, 104, http://www.googl.com, Cindy Chen

除了第一列,我可以成功生成以上内容,第一列只是每条记录的行数。我尝试过的任何操作都无法在作业运行之间自行重置。

您可以为此使用 ItemCountAware 界面。该接口由您的域对象(在您的情况下似乎是 Customer )实现,并且将在阅读时由扩展 AbstractItemCountingItemStreamItemReader.

的任何 reader 调用

因此,如果您的 reader 是其中之一,您可以获取项目的项目计数并根据需要在 LineAggregator 中使用它。

编辑:当 reader 不扩展 AbstractItemCountingItemStreamItemReader

时添加选项

您始终可以在 ItemReadListener#afterRead 中分配项目编号并在您的聚合器中使用它,例如:

class ItemNumberListener implements ItemReadListener<Customer> {
    int number;
    @Override
    public void afterRead(Customer customer) {
        customer.setNumber(number++);
    }
    // other methods from ItemReadListener
}

一旦到位,您就可以在您的步骤中注册此侦听器并在您的 LineAggregator 中使用项目编号。此方法适用于所有 readers(基于光标或基于分页)。

NB:如果你不能在Customer对象中添加一个字段+getter/setter(可能是一个你不能修改的class),你可以将它包裹在一个像 NumberAwareCustomer 这样的自定义对象并在您的批处理应用程序中使用该类型。