Spring Batch:如何在追加文件且无项目写入时写入文件头

问题描述

我正在尝试将项目写入由“类型 ID”捆绑的文件。该文件将包含不止一个这样的项目包。 每个共享相同类型 ID 的项目都必须有相应的页眉和页脚。

我将 Spring Batch 配置为有一个单独的 Step 来按类型 ID 读取数据库记录(使用 RepositoryItemReader,将类型 ID 作为方法参数传递给它)并将它们写入文件,以及他们的页眉和页脚,使用 FlatFileHeaderCallbackFlatFileFooterCallback

第一步的 FlatFileItemWriterappend 设置为 false,而后续步骤的作者将 append 设置为 true,因此它们不会覆盖之前的内容之前写入文件

我的文件应该是这样的:

Header TYPE ID 001        ::Other Header Info::    <---Written by Step 1,append false
Item   TYPE ID 001        ::Other Item Info::      <---Written by Step 1,append false
Footer TYPE ID 001        ::Other Footer Info::    <---Written by Step 1,append false
Header TYPE ID 002        ::Other Header Info::    <---Written by Step 2,append true
Item   TYPE ID 002        ::Other Item Info::      <---Written by Step 2,append true
Footer TYPE ID 002        ::Other Footer Info::    <---Written by Step 2,append true
Header TYPE ID 003        ::Other Header Info::    <---Written by Step 3,append true
Item   TYPE ID 003        ::Other Item Info::      <---Written by Step 3,append true
Footer TYPE ID 003        ::Other Footer Info::    <---Written by Step 3,append true

问题 1:附加

然而,当AbstractFileItemWriter.doopen()为真时,FlatFileHeaderCallback不会调用我的append,所以Header只写第一步,在文件的第1行,文件是缺少“中间”标题

Header TYPE ID 001        ::Other Header Info::    <---Written by Step 1,append false
Item   TYPE ID 002        ::Other Item Info::      <---Written by Step 2,append true

问题 1 的解决方

为了解决这个问题,我放弃了 FlatFileFooterCallback 并编写了自己的 FlatFileItemWriter,不管 append 是什么,它都会写入标题,但前提是写入的行数为零。到现在为止还挺好。它以我需要的格式生成文件,以及“中间”标题

public class MyFlatFileItemWriter extends FlatFileItemWriter<MyItem> {

    @Override
    public String doWrite(List<? extends MyItem> items) {
    StringBuilder lines = new StringBuilder();
    if (getoutputState().getLinesWritten() == 0) {
        lines.append(  <<MY HEADER CONTENT>>  ))
            .append(lineseparator);
    }
    Iterator<? extends MyItem> iterator = items.iterator();
    while (iterator.hasNext()) {
        MyItem item = iterator.next();
        lines.append(this.lineAggregator.aggregate(item)).append(this.lineseparator);
    }

    return lines.toString();
    }
}

问题 2:写入零项

一个要求是,即使数据库没有给定类型 ID 的项目,文件也必须具有与类型 ID 相对应的页眉和页脚(并且中间没有项目行)。它应该是这样的:

Header TYPE ID 001        ::Other Header Info::    <---Written by Step 1,append true

但是,只有页脚被写入。没有标题的迹象:

Footer TYPE ID 001        ::Other Footer Info::    <---Written by Step 1,append false
Footer TYPE ID 002        ::Other Footer Info::    <---Written by Step 2,append true

我追踪到 SimpleChunkProcessor 的工作方式。如果它收到一个空的项目列表,它不会调用 MyItemWriter.write(),因此当我有零个项目时,我的标题不可能被写出。

来自SimpleChunkProcessor

public final void process(StepContribution contribution,Chunk<I> inputs) throws Exception {
    this.initializeUserData(inputs);
    if (!this.isComplete(inputs)) {
        Chunk<O> outputs = this.transform(contribution,inputs);
        contribution.incrementFilterCount(this.getFilterCount(inputs,outputs));
        this.write(contribution,inputs,this.getAdjustedOutputs(inputs,outputs));
    }
}

也来自SimpleChunkProcessor

protected boolean isComplete(Chunk<I> inputs) {
    return inputs.isEmpty();
}

问题 2 的可能解决方

然而,SimpleChunkProcessor.isComplete() 是受保护的,所以我将其子类化,覆盖 isComplete() 以返回 false

    public class HeaderWritingChunkProcessor extends SimpleChunkProcessor<MyItem,MyItem> {

    public HeaderWritingChunkProcessor(ItemWriter<MyItem> itemWriter) {
        super(itemWriter);
    }

    @Override
    protected boolean isComplete(Chunk<MyItem> inputs) {
        return false;
    }
}

但是如何将我的 HeaderWritingChunkProcessor 放入我的应用程序中?我应该在我的步骤的配置中或其他地方设置它吗?

或者我是否错过了一个更简单的解决方案来实现我的两个核心要求?

  1. 即使在追加模式下也要写标题,而不仅仅是在文件的第 1 行。
  2. 即使要写入的项目为零,也要写入标题

我应该补充一点,页脚总是按照文件中我需要的方式编写,所以这些没有问题。

谢谢。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...