当前位置: 首页 > 知识库问答 >
问题:

Spring Batch Reader Writer数据传输未按预期工作

白芷阳
2023-03-14

我已经创建了一个通用的Spring批处理作业,用于处理数据并存储到CSV中。我需要从读取器传递到写入器的一些数据,这是我试图使用JobExecution来做的。然而令人惊讶的是,代码似乎首先调用getWriter()而不是getReader()函数。下面给出了我的配置。有人能解释为什么会发生这种情况,以及是否有其他方法将数据从读取器传递到写入器。

@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();
}

我想从读取器传递到写入器的数据是CSV的列名。由于我的阅读器运行变量SQL查询(将SQL查询作为命令行参数传递),因此结果集/列不是静态的,并且根据给定的查询而变化。在setHeaderCallback中为编写器提供要为特定执行编写的列名是从读取器发送数据到编写器的基本原理。

Reader simple运行给定的查询,并将数据放入map ,而不是任何POJO中,因为数据是可变的。在这里,映射的键表示列名,而相应的对象保存该列的值。因此,本质上,我希望编写器setHeaderCallback能够访问传递的映射的键,或者以某种方式将键从读取器传递给编写器。

编写器代码如下:

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;
    } 

共有1个答案

锺离锦
2023-03-14

这些方法的执行顺序并不重要。您不应该寻找使用执行上下文将数据从读取器传递到写入器的方法,Spring Batch提供的面向块的Tasklet实现将为您提供这种方法。

执行上下文可以用于将数据从一个步骤传递到另一个步骤,但不能在同一步骤中从读取器传递到写入器。

编辑:根据评论更新答案:

您可以在这里找到一个示例:https://stackoverflow.com/a/56719077/5019386。此示例用于lineMapper,但您可以对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
        }
    };
}
 类似资料:
  • 我正在尝试在生产支持分支(即V3.1)上使用maven应用outOfOrder迁移。3.1分支有12个迁移3.1.0.13.1.0.12。前11个已经应用,在我的开发环境中,我已经应用了下一个版本3.3的两个迁移。信息如下所示: 我在 V3.1 分支中的 mvn 构建输出文件夹中运行以下命令: mvn 飞行方式:迁移 -Dflyway.outOfOrder=真 -P 我得到以下输出: [错误]未能

  • 我正在使用spring Roo并希望访问Controller类中的一个bean,该类在ApplicationContext.xml中具有以下配置: 配置类本身是: 在我的Controller中,我认为一个简单的Autowired注释应该可以完成这项工作 在启动过程中,spring在setSkipWeeks方法中打印消息。不幸的是,每当我在控制器中调用config.getSkipWeeks()时,它

  • 当我运行以下程序时,它只打印 然而,从Java 8的equalsIgnoreCase文档中我们发现: 如果以下至少一项为真,则两个字符c1和c2被视为相同的忽略情况: •对每个字符应用java.lang.character.ToUpperCase(char)方法会产生相同的结果 所以我的问题是为什么这个程序不打印 在这两种操作中,都使用了大写字符。

  • 我试图使用来传输我根据前面的问题设置的自定义标头。 我在文件中读到... 我的属性包括:

  • 我正在和selenium一起工作,刮一些数据。 有一个按钮在页面上,我正在点击说“Custom_Cols”。这个按钮为我打开了一个窗口,我可以在那里选择我的列。 我的问题是为什么新窗口上的元素不可见,即使我正在等待元素的可见。补充一下,我已经尝试增加延迟时间,但我还是会偶尔出现这个错误。 我的密码在这里