Java Spring批处理读写器数据传输未按预期工作
我创建了一个通用的Spring批处理作业,用于处理数据并存储到CSV中。我需要从读卡器中获得一些数据,并将其传递给编写器,我正试图使用JobExecution执行这些数据。然而令人惊讶的是,代码似乎首先调用getWriter()而不是getReader()函数。 我的配置如下。有人能解释一下为什么会发生这种情况,以及是否有其他方法可以将数据从读卡器传递给写卡器Java Spring批处理读写器数据传输未按预期工作,java,spring,spring-batch,batch-processing,Java,Spring,Spring Batch,Batch Processing,我创建了一个通用的Spring批处理作业,用于处理数据并存储到CSV中。我需要从读卡器中获得一些数据,并将其传递给编写器,我正试图使用JobExecution执行这些数据。然而令人惊讶的是,代码似乎首先调用getWriter()而不是getReader()函数。 我的配置如下。有人能解释一下为什么会发生这种情况,以及是否有其他方法可以将数据从读卡器传递给写卡器 @Bean @StepScope public ItemReader<Map<String, Object>>
@Bean
@StepScope
public ItemReader<Map<String, Object>> getDataReader() throws Exception {
return springBatchReader.getReader();
}
@Bean
@StepScope
public FlatFileItemWriter<Map<String, Object>> getDataWriter() throws Exception {
return (FlatFileItemWriter<Map<String, Object>>) springBatchWriter.getWriter();
}
@Bean
public Job SpringBatchJob(Step generateReport) throws Exception {
return jobBuilderFactory.get("SpringBatchJob" + System.currentTimeMillis())
.preventRestart()
.incrementer(new RunIdIncrementer())
.flow(generateReport)
.end()
.build();
}
@Bean
public Step generateReport() throws Exception {
return stepBuilderFactory.get("generateReport").<Map<String, Object>, Map<String, Object>>chunk(batchSize)
.reader(getDataReader()).writer(getDataWriter()).build();
}
@Bean
@步进镜
public ItemReader getDataReader()引发异常{
返回springBatchReader.getReader();
}
@豆子
@步进镜
公共FlatFileItemWriter getDataWriter()引发异常{
return(FlatFileItemWriter)springBatchWriter.getWriter();
}
@豆子
公共作业SpringBatchJob(步骤生成器报告)引发异常{
返回jobBuilderFactory.get(“SpringBatchJob”+System.currentTimeMillis())
.防止重新启动()
.incrementer(新的RunIdIncrementer())
.流量(发电机报告)
(完)
.build();
}
@豆子
公共步骤generateReport()引发异常{
返回stepBuilderFactory.get(“generateReport”).chunk(batchSize)
.reader(getDataReader()).writer(getDataWriter()).build();
}
我想从读卡器传递到写卡器的数据是CSV的列名因为我的阅读器运行变量SQL查询(传递SQL查询作为命令行参数运行),因此结果集/列不是静态的,并且根据给定的查询而变化。向编写器提供要为setHeaderCallback中的特定执行编写的列名是将数据从读卡器发送到编写器的基本原理。
Reader simple运行给定的查询并将数据放入Map,而不是任何POJO,因为数据的性质是可变的。在这里,映射的键表示列名,而相应的对象保存该列的值。因此,本质上我希望writer setHeaderCallback能够访问所传递映射的键,或者以某种方式将键从读取器传递给writer
编写器代码如下:
public FlatFileItemWriter<Map<String, Object>> getWriter() throws Exception {
String reportName = getReportName();
saveToContext(reportName, reportPath);
FileSystemResource resource = new FileSystemResource(String.join(File.separator, reportPath, getReportName()));
FlatFileItemWriter<Map<String, Object>> flatFileItemWriter = new FlatFileItemWriter<>();
flatFileItemWriter.setResource(resource);
//NEED HELP HERE..HOW TO SET THE HEADER TO BE THE KEYS OF THE MAP
//flatFileItemWriter.setHeaderCallback();
flatFileItemWriter.setLineAggregator(new DelimitedLineAggregator<Map<String, Object>>() {
{
setDelimiter(delimiter);
setFieldExtractor(
new PassThroughFieldExtractor<>()
);
}
});
flatFileItemWriter.afterPropertiesSet();
return flatFileItemWriter;
}
public FlatFileItemWriter getWriter()引发异常{
字符串reportName=getReportName();
saveToContext(reportName、reportPath);
FileSystemResource=newfilesystemresource(String.join(File.separator,reportPath,getReportName());
FlatFileItemWriter FlatFileItemWriter=新FlatFileItemWriter();
flatFileItemWriter.setResource(资源);
//此处需要帮助..如何将标题设置为地图的键
//flatFileItemWriter.setHeaderCallback();
flatFileItemWriter.setLineAggregator(新的DelimitedLineAggregator(){
{
setDelimiter(定界符);
赛特菲尔德提取器(
新的passthroughFieldDextractor()
);
}
});
flatFileItemWriter.AfterPropertieSet();
返回flatFileItemWriter;
}
这些方法的执行顺序并不重要。您不应该寻找一种使用执行上下文将数据从读取器传递到写入器的方法,SpringBatch提供的面向块的Tasklet实现将为您实现这一点
执行上下文可用于将数据从一个步骤传递到另一个步骤,但不能在同一步骤内从读取器传递到写入器
编辑:根据评论更新答案:
您的问题是您正在调用saveToContext(reportName,reportPath)。此方法在配置时调用,而不是在运行时调用
您真正需要的是通过作业参数提供列名,或者将它们放在带有步骤的执行上下文中,然后使用配置了这些头的步骤范围的头回调
您可以在此处找到一个示例:。此示例适用于线型映射器,但也可以对headerCallback执行相同的操作。如果不想使用作业参数方法,可以创建一个确定列名并将其放入执行上下文的tasklet步骤,然后使用执行上下文中的这些名称配置步骤作用域标头回调,如:
@Bean
@StepScope
public FlatFileHeaderCallback headerCallback(@Value("#{jobExecutionContext['columnNames']}") String columnNames) {
return new FlatFileHeaderCallback() {
@Override
public void writeHeader(Writer writer) throws IOException {
// use columnNames here
}
};
}
谢谢你,马哈茂德。然而,您能否就如何将面向块的Tasklet用于此目的(更新我在问题中试图做的事情的细节)提供一些指导。对于手头的任务,我在网上找到的资源似乎有点混乱。谢谢您已经在使用面向块的tasklet。因此,它将处理从读卡器到写卡器的项目传递。您可以检查,但本质上,项目是通过变量传递的:Chunk inputs=chunkProvider.provide();进程(输入)代码>更新了用例细节问题Mahmoud。请您建议是否有任何替代方法可用,无需明确传递数据。对Spring batch来说是相当新的!谢谢你的更新。最初的问题有误导性,缺少关于动态获取标题回调的列名的要求的关键细节。你可以更新这个问题,而不是创建一个新的问题,我问你这些列名来自哪里。总之,没问题。我用更多的细节和例子更新了答案。