根据项目的属性作为条件,将数据路由到项目编写器中的多个文件

时间:2012-09-17 04:46:44

标签: spring-batch

我在阅读器中收到了一个项目列表。

在每个项目对象中都有一个名为Code的属性,它具有我手头未知的几个可能的值。

1)根据每个项目中Code的值,我想在与Code相关的输出文件中写出该特定项目。对于例如如果我当前项目的Code是“abc”,则该项应写入编写器中的abc.txt。

2)如果当前项目中存在Code“xyz”,且该文件不存在,则应创建一个新文件,该项目应转到该文件。

3)对于基于Code创建的所有此类多个文件,我还想添加页眉和页脚回调以输入一些详细信息,例如每个文件中的项目数。

是否有可能有一位满足3项要求的作家?

我知道使用multiresourceitemwriter,可以在多个输出文件之间划分数据。但据我所知,这种划分是基于物品的数量。对于例如file1中的前10个项目,file2中的下10个项目,依此类推。

但是如何根据我的问题中提到的项属性将数据路由到输出文件?

我很熟悉Spring Batch,只需要一些指导,因为这是我第一次遇到这类问题。

感谢阅读!

5 个答案:

答案 0 :(得分:9)

如果我理解你的问题,你需要一些物品。

首先,实现Classifier接口

的分类器
public class ItemCodeClassifier {
    @Classifier
    public String classify(Item item) {
        return item.getCode().getKey();// returns "abc", "xyz"
    }
}

其次是使用上述方法的路由器实现

<bean id="classifier"  class="org.springframework.batch.classify.BackToBackPatternClassifier">
    <property name="routerDelegate">
        <bean class="ItemCodeClassifier" />
    </property>
    <property name="matcherMap">
        <map>
        <entry key="abc" value-ref="abcItemWriter" />
        <entry key="xyz" value-ref="xyzItemWriter" />
        </map>
    </property>
</bean>

最后,ClassifierCompositeItemWriter

<bean id="ItemWriter" class="org.springframework.batch.item.support.ClassifierCompositeItemWriter">
<property name="classifier" ref="classifier" />
</bean

没有编译上面但希望它有所帮助。

答案 1 :(得分:3)

以下解决方案适合我。编写了代码并且工作正常。

首先,您需要一个分类器。实现Classifier接口或使用@Classifier注释classify()方法。

这里我使用了注释。

Messages
  message_id_0
    from: user_id_0
    to:   user_id_1
    type: "private"
    message: "a private message"
  message_id_1
    from: user_id_0
    type: "public"
    message: "a public message"

添加分类器bean

public class MyClassifier {
    @Classifier
    public String classify(Policy pol) {
        return pol.getPolCode;// returns "01", "02"
    }
}

添加您的编写器bean,如下所示

<bean id="myClassifier"  class="org.springframework.batch.classify.BackToBackPatternClassifier">
    <property name="routerDelegate">
        <bean class="MyClassifier" />
    </property>
    <property name="matcherMap">
        <map>
        <entry key="01" value-ref="pol01ItemWriter" />
        <entry key="02" value-ref="pol02ItemWriter" />
        </map>
    </property>
</bean>

上面的代码可能会抛出WriterNotOpenException。为此,您需要将batch:stream添加到步骤。

<bean id="ItemWriter" class="org.springframework.batch.item.support.ClassifierCompositeItemWriter">
    <property name="myClassifier" ref="myClassifier" />
</bean>

答案 2 :(得分:0)

另一种选择是建立3个包含由其代码分隔的元素的列表。 然后,使用不同的步骤将这些列表写入文件系统。

一个优点是您的元素已准备好写入,因此您可以使用大缓冲区来增加写入的吞吐量(当然,根据您的硬件)。

如果您必须生成的文件数是动态的,我建议您按顺序编写它们以避免任何多线程问题。

您无法动态路由元素。 因此,我们的想法是创建一个由您自己路由的元素列表,然后处理这些列表。

答案 3 :(得分:0)

用于JDBC编写器的Java Config

这是我为jdbc writer完成的方式。我们可以为Flatfile Writer设置类似的配置

 @Bean
    public ItemWriter<Person> itemWriter(DataSource dataSource) {
        BackToBackPatternClassifier classifier = new BackToBackPatternClassifier();
        classifier.setRouterDelegate(new AggGroupClassifier());
        classifier.setMatcherMap(new HashMap<String, ItemWriter<? extends Person>>() {
            {
                put("A", writerA(dataSource));
                put("B", writerB(dataSource));
                put("C", writerC(dataSource));

            }
        });
        ClassifierCompositeItemWriter<Person> writer = new ClassifierCompositeItemWriter<Person>();
        writer.setClassifier(classifier);
        return writer;      
        }


public class AggGroupClassifier {

    @Classifier
    public String classify(Person person) {
        return person.getAgeGroup();

    }
}

答案 4 :(得分:-2)

今天早上我遇到了同样的问题。最后我发现当前ClassifierCompositeItemWriter不支持FlatFileItemWriter作为Spring批次最新版本2.1.9版本中的委托ItemWriter。

WriterNotOpenException如下所示:

org.springframework.batch.item.WriterNotOpenException: Writer must be open before it can be written to
    at org.springframework.batch.item.file.FlatFileItemWriter.write(FlatFileItemWriter.java:236)
    at org.springframework.batch.item.support.ClassifierCompositeItemWriter.write(ClassifierCompositeItemWriter.java:65)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:171)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:150)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:269)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:194)
    at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:74)
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:386)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
    at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:264)
    at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:76)
    at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:367)
    at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:214)
    at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:143)
    at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:250)
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:195)
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:135)
    at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61)
    at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60)
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144)
    at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124)
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135)
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:281)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120)
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:48)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:114)