0

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

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

第一步的FlatFileItemWriter设置appendfalse,而后续步骤的编写者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
Item   TYPE ID 001        ::Other Item Info::      <---Written by Step 1, append false
Item   TYPE ID 001        ::Other Item Info::      <---Written by Step 1, append false
Item   TYPE ID 001        ::Other Item Info::      <---Written by Step 1, append false
Item   TYPE ID 001        ::Other Item 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
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
Item   TYPE ID 003        ::Other Item Info::      <---Written by Step 3, append true
Item   TYPE ID 003        ::Other Item 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()不会调用我的FlatFileHeaderCallbackwhenappend为真,因此 Header 仅在文件的第 1 行写入第一步,并且文件缺少“中间”标题:

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
Item   TYPE ID 001        ::Other Item Info::      <---Written by Step 1, append false
Item   TYPE ID 001        ::Other Item Info::      <---Written by Step 1, append false
Item   TYPE ID 001        ::Other Item Info::      <---Written by Step 1, append false
Item   TYPE ID 001        ::Other Item 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
Item   TYPE ID 002        ::Other Item 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
Item   TYPE ID 003        ::Other Item Info::      <---Written by Step 3, append true
Item   TYPE ID 003        ::Other Item Info::      <---Written by Step 3, append true
Item   TYPE ID 003        ::Other Item 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 的解决方案

为了解决这个问题,我放弃了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 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
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
Footer TYPE ID 003        ::Other Footer Info::    <---Written by Step 3, 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
Footer TYPE ID 003        ::Other Footer Info::    <---Written by Step 3, append true

我追踪到它的工作方式SimpleChunkProcessor。如果它收到一个空的项目列表,它不会调用 to 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()为 return 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. 即使有零个项目要写入,也要写一个标题。

我应该补充一点,页脚总是写在我需要它们的文件中,所以这些没有问题。

谢谢你。

4

0 回答 0