问题描述
我正在尝试将项目写入由“类型 ID”捆绑的文件。该文件将包含不止一个这样的项目包。 每个共享相同类型 ID 的项目都必须有相应的页眉和页脚。
我将 Spring Batch 配置为有一个单独的 Step
来按类型 ID 读取数据库记录(使用 RepositoryItemReader
,将类型 ID 作为方法参数传递给它)并将它们写入文件,以及他们的页眉和页脚,使用 FlatFileHeaderCallback
和 FlatFileFooterCallback
。
第一步的 FlatFileItemWriter
将 append
设置为 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
放入我的应用程序中?我应该在我的步骤的配置中或其他地方设置它吗?
或者我是否错过了一个更简单的解决方案来实现我的两个核心要求?
我应该补充一点,页脚总是按照文件中我需要的方式编写,所以这些没有问题。
谢谢。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)