我正在尝试编写一个春季批处理作业,该作业从数据库中读取数据并写入FlatFile。
我需要在FlatFile的标题中写入total records, total lines
。
为此,可以使用Writer中的headerCallback属性。
问题陈述:
我在处理器的ExecutionContext
中设置值,并尝试在Writer的headerCallback中检索值。
但是在headerCallback中将值作为null
获取。
使用ExecutionContextPromotionListener
进行了尝试,也使用SpEL将值直接注入headerCallback中。详细信息如下:
作业配置:
<batch:job id="fooBatchJob">
<batch:step id="step1">
<batch:tasklet>
<batch:chunk reader="fooJdbcItemReader" writer="fooFileItemWriter" processor="fooProcessor"
commit-interval="100">
</batch:chunk>
</batch:tasklet>
<batch:listeners>
<batch:listener ref="execContextPromotionListener"/>
</batch:listeners>
</batch:step>
</batch:job>
<!-- Listeners -->
<bean id="execContextPromotionListener" class="org.springframework.batch.core.listener.ExecutionContextPromotionListener">
<property name="strict" value="TRUE"/>
<property name="keys">
<list>
<value>TOTAL_RECORDS</value>
<value>TOTAL_LINES</value>
</list>
</property>
</bean>
使用ItemReader中查询的值填充TOTAL_RECORDS和TOTAL_LINES的值。
我在处理器中设置值,如下所示:
public class FooProcessor implements ItemProcessor<MyObj,MyObj>, StepExecutionListener {
private StepExecution stepExecution;
public MyObj process(MyObj item) throws Exception {
if(item != null && item.getRecordType().equals("HEADER")) {
this.stepExecution.getExecutionContext().put("TOTAL_RECORDS", item.getMetaData().getTotalRecordsCount());
this.stepExecution.getExecutionContext().put("TOTAL_LINES", item.getMetaData().getTotalLines());
// below lines printed for debugging:
System.out.println("TOTAL_RECORDS:"+this.stepExecution.getExecutionContext().getInt("TOTAL_RECORDS"));
System.out.println("TOTAL_LINES:"+this.stepExecution.getExecutionContext().getInt("TOTAL_LINES"));
return null;
}
return item;
}
@Override
public void beforeStep(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
return null;
}
}
现在,这是Writer配置:
<bean id="fooFileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
<property name="resource" value="file:output/result-file.asc"/>
<property name="shouldDeleteIfExists" value="true" />
<property name="headerCallback" ref="myHeaderFooter"/>
<property name="footerCallback" ref="myHeaderFooter"/>
<property name="lineAggregator">
<bean
class="com.domain.batch.transform.FooLineAggregator">
</bean>
</property>
</bean>
<!-- Header and Footer Callback -->
<bean id="myHeaderFooter" class="com.domain.batch.transform.MyHeaderFooter" scope="step">
<property name="stepExecution" value="#{stepExecution}" />
<property name="totalRecords" value="#{jobExecutionContext['TOTAL_RECORDS']}"/>
</bean>
以下是MyHeaderFooter.java的清单:
public class MyHeaderFooter implements FlatFileHeaderCallback, FlatFileFooterCallback {
private StepExecution stepExecution;
private Integer totalRecords;
private static final String ITEM_END_INDICATOR = "RE";
private static final String SPACE_DELIMITER = " ";
private static final String LINE_SEPARATOR = System.lineSeparator();
@Override
public void writeHeader(Writer writer) throws IOException {
// printing out null
System.out.println("Total records from jobExecContext : "+totalRecords);
ExecutionContext executionContext = stepExecution.getJobExecution().getExecutionContext();
// printing out null
System.out.println("Total Records :"+ executionContext.get("TOTAL_RECORDS"));
// printing out null
System.out.println("Total Lines:"+ executionContext.get("TOTAL_LINES"));
// Below lines commented out for brevity
//String header = buildHeader(...);
//writer.write(header);
}
@Override
public void writeFooter(Writer writer) throws IOException {
String footer = "footer data....";
writer.write(footer);
}
public void setStepExecution(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
public void setTotalRecords(Integer totalRecords) {
this.totalRecords = totalRecords;
}
}
不知道我在做什么配置错误。
任何发现问题的线索都会有所帮助。
最佳答案
打开writeHeader
时将调用fooFileItemWriter
方法。那时尚未开始读取,处理和写入。因此,您要求的信息尚不可用。
请注意,如果您想在页脚行中写这些信息,它将起作用。
有一个与此类似的问题,我在这里添加以供参考:Passing variables to process。