将单个参数而不是列表传递给ItemWriter接口的Write()方法

时间:2017-07-24 14:59:46

标签: java spring spring-batch batch-processing

我使用Spring Batch从CSV文件中读取数据,然后将其保存到数据库中。到目前为止一切都很好,除了我的输入文件包含混合数据(多个表的多列)。

我创建了一个类CsvFileLine,它将包含整行文件,并实现了接口ItemReader<CsvFileLine>,然后实现了接口ItemProcessor<List<CsvFileLine>, ProcessorResult>,我将向其传递{{ {1}}它返回我创建的CsvFileLine类型的对象,其中包含3 ProcessorResult ArrayList<>ClassAClassB

我现在的问题是,当我需要实现接口ClassC时,方法ItemWriter<ProcessorResult>需要一个扩展其他类的项目列表,而我打算传递一个包含该对象的ProcessorResult对象4个包含必要数据的ArrayLists。

有谁能建议我如何处理这个案子?有没有工作只传递1个参数?

2 个答案:

答案 0 :(得分:1)

感谢您的澄清。如果我理解正确,您说文件中的每一行都包含ClassAClassBClassC各一个实例。我假设对于这个例子,但即使有不同的关系,解决方案也会类似。

设置Spring Batch作业的关键是考虑什么构成“项目”以及您希望发生什么。您还需要了解框架如何将每个接口的输出作为下一个输入的输入。 (Spring很不错documentation)。 ItemReader的返回类型作为单例传递给ItemProcessor。因此,在您的情况下,ItemProcessor实际应该是ItemProcessor<CsvFileLine, ProcessorResult>而不是您拥有的ItemProcessor<List<CsvFileLine>, ProcessorResult>。从ItemProcessorItemWriter的切换有点棘手。 ItemWriter实现应该从List获取ItemProcessor返回类型。 ItemWriter需要List,因为Spring Batch组ItemProcessor一起输出到事务中。在您的情况下,您可以ItemWriter<List<ProcessorResult>>

有了这个基础,我们可以改变ProcessorResult的结构,然后编写器很容易实现。它不是包含所有文件中数据的ProcessorResult,而是包含来自一行的数据:

public class ProcessorResult {
    private ClassA classA;
    private ClassB classB;
    private ClassC classC;
    // Constructor and getters omitted for brevity
}

ItemProcessor需要一个CsvFileLine并将其转换为一个ProcessorResult

public class ExampleProcessor implements ItemProcessor<CsvFileLine, ProcessorResult> {

  public ProcessorResult process(CsvFileLine line){
    // mapping into ProcessorResult goes here
  }

ItemWriter需要List个,需要将它们保存到数据库中。它可能看起来像这样:

public class ExampleItemWriter implements ItemWriter<List<ProcessorResult>{

  private ClassADao classADao;
  private ClassBDao classBDao;
  private ClassCDao classCDao;

  public void write(List<? extends ProcessorResult> items){
     for(ProcessorResult result : items){
        classADao.save(result.getClassA());
        classBDao.save(result.getClassB());
        classCDao.save(result.getClassC());
     }
  }
}

请注意,传递给List的{​​{1}}中的每个元素都会映射回ItemWriter中的单个项目。通常,这也是文件中的一行。要使用Spring Batch,您必须确保ItemReader的返回类型是ItemReader的输入类型。同时,ItemProcessor的输入是ItemWriter返回的List类型的输入。您在这里的阅读器,处理器和编写器不遵循该模式,框架将无法使用它们。一些小的改动应该允许你使用你在框架中编写的代码。

最后,我会注意到你可能在没有ItemProcessor的情况下这样做。您可以拥有ItemProcessorItemReader<ProcessorResult>并在ItemWriter<ProcessorResult>中进行映射。因此,您将逻辑从当前ItemReader转移到ItemProcessor。然后在LineMapper<ProcessorResult>中使用它,然后一切都直接从读者传递到作者。这超出了你的问题的范围,我更喜欢XML配置,所以我会留下它。

答案 1 :(得分:0)

由于您已选择以使用Spring Batch及其ItemWriter,因此您需要明确了解域对象如何映射到“项目”。

假设您的ProcessorResult构成一个“项目”,只需使用大小为1的列表调用ItemWriter.write()

标准Java API为您Collections.singletonList()提供了方便的功能。

 itemWriter.write(Collections.singletonList(processorResult));