Item processing
物料处理
ItemReader 和 ItemWriter 接口对于其特定的
任务,但是如果你想在编写之前插入业务逻辑怎么办?两者兼而有之
读写就是用复合模式:创建一个ItemWriter包含
另一个ItemWriter或ItemReader包含另一个ItemReader.以下内容
代码显示了一个示例:
public class CompositeItemWriter<T> implements ItemWriter<T> {
    ItemWriter<T> itemWriter;
    public CompositeItemWriter(ItemWriter<T> itemWriter) {
        this.itemWriter = itemWriter;
    }
    public void write(Chunk<? extends T> items) throws Exception {
        //Add business logic here
       itemWriter.write(items);
    }
    public void setDelegate(ItemWriter<T> itemWriter){
        this.itemWriter = itemWriter;
    }
}
前面的类包含另一个ItemWriter它在拥有后委托给它
提供了一些业务逻辑。这种模式可以很容易地用于ItemReader如
好吧,也许是为了根据
主要ItemReader.如果您需要控制对write你自己。
但是,如果您只想“转换”传入的项目,则在它之前
实际写好,你不需要write你自己。您可以修改该项目。为此
场景,Spring Batch 提供了ItemProcessor接口,如下所示
接口定义显示:
public interface ItemProcessor<I, O> {
    O process(I item) throws Exception;
}
一ItemProcessor很简单。给定一个对象,转换它并返回另一个对象。这
提供的对象可能属于同一类型,也可能不是同一类型。关键是业务逻辑可能
在流程中应用,完全由开发人员创建它
逻辑。一ItemProcessor可以直接连接到一个步骤中。例如,假设ItemReader提供类型Foo并且需要将其转换为类型Bar在被写出来之前。以下示例显示了ItemProcessor执行
转换:
public class Foo {}
public class Bar {
    public Bar(Foo foo) {}
}
public class FooProcessor implements ItemProcessor<Foo, Bar> {
    public Bar process(Foo foo) throws Exception {
        //Perform simple transformation, convert a Foo to a Bar
        return new Bar(foo);
    }
}
public class BarWriter implements ItemWriter<Bar> {
    public void write(Chunk<? extends Bar> bars) throws Exception {
        //write bars
    }
}
在前面的示例中,有一个名为Foo,一个名为Bar和类
叫FooProcessor遵守ItemProcessor接口。转变是
简单,但任何类型的转换都可以在这里完成。这BarWriter写Bar对象,如果提供了任何其他类型,则抛出异常。同样,FooProcessor抛出异常,如果有任何异常,但Foo被提供。这FooProcessor然后可以注入到Step,如以下示例所示:
<job id="ioSampleJob">
    <step name="step1">
        <tasklet>
            <chunk reader="fooReader" processor="fooProcessor" writer="barWriter"
                   commit-interval="2"/>
        </tasklet>
    </step>
</job>@Bean
public Job ioSampleJob(JobRepository jobRepository) {
	return new JobBuilder("ioSampleJob", jobRepository)
				.start(step1())
				.build();
}
@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
	return new StepBuilder("step1", jobRepository)
				.<Foo, Bar>chunk(2, transactionManager)
				.reader(fooReader())
				.processor(fooProcessor())
				.writer(barWriter())
				.build();
}
之间的区别ItemProcessor和ItemReader或ItemWriter那是一个ItemProcessor对于Step.
链接 ItemProcessors
执行单个转换在许多情况下都很有用,但如果要执行,该怎么办
“链接”在一起多个ItemProcessor实现?您可以使用
前面提到的复合模式。要更新之前的单个
转换,示例,Foo转换为Bar,将其转换为Foobar并写出,如下例所示:
public class Foo {}
public class Bar {
    public Bar(Foo foo) {}
}
public class Foobar {
    public Foobar(Bar bar) {}
}
public class FooProcessor implements ItemProcessor<Foo, Bar> {
    public Bar process(Foo foo) throws Exception {
        //Perform simple transformation, convert a Foo to a Bar
        return new Bar(foo);
    }
}
public class BarProcessor implements ItemProcessor<Bar, Foobar> {
    public Foobar process(Bar bar) throws Exception {
        return new Foobar(bar);
    }
}
public class FoobarWriter implements ItemWriter<Foobar>{
    public void write(Chunk<? extends Foobar> items) throws Exception {
        //write items
    }
}
一个FooProcessor和BarProcessor可以“链接”在一起以给出结果Foobar,如以下示例所示:
CompositeItemProcessor<Foo,Foobar> compositeProcessor =
                                      new CompositeItemProcessor<Foo,Foobar>();
List itemProcessors = new ArrayList();
itemProcessors.add(new FooProcessor());
itemProcessors.add(new BarProcessor());
compositeProcessor.setDelegates(itemProcessors);
与前面的示例一样,您可以将复合处理器配置为Step:
<job id="ioSampleJob">
    <step name="step1">
        <tasklet>
            <chunk reader="fooReader" processor="compositeItemProcessor" writer="foobarWriter"
                   commit-interval="2"/>
        </tasklet>
    </step>
</job>
<bean id="compositeItemProcessor"
      class="org.springframework.batch.item.support.CompositeItemProcessor">
    <property name="delegates">
        <list>
            <bean class="..FooProcessor" />
            <bean class="..BarProcessor" />
        </list>
    </property>
</bean>@Bean
public Job ioSampleJob(JobRepository jobRepository) {
	return new JobBuilder("ioSampleJob", jobRepository)
				.start(step1())
				.build();
}
@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
	return new StepBuilder("step1", jobRepository)
				.<Foo, Foobar>chunk(2, transactionManager)
				.reader(fooReader())
				.processor(compositeProcessor())
				.writer(foobarWriter())
				.build();
}
@Bean
public CompositeItemProcessor compositeProcessor() {
	List<ItemProcessor> delegates = new ArrayList<>(2);
	delegates.add(new FooProcessor());
	delegates.add(new BarProcessor());
	CompositeItemProcessor processor = new CompositeItemProcessor();
	processor.setDelegates(delegates);
	return processor;
}
过滤记录
项目处理器的一个典型用途是在将记录传递给
这ItemWriter.过滤是一种不同于跳过的作。跳过表示
记录无效,而筛选指示记录不应无效
写。
例如,考虑读取包含三种不同类型
记录:要插入的记录、要更新的记录和要删除的记录。如果记录删除
系统不支持,我们不希望将任何可删除的记录发送到
这ItemWriter.然而,由于这些记录实际上并不是坏记录,我们希望
过滤掉它们而不是跳过它们。因此,ItemWriter只会收到
可插入和可更新的记录。
若要筛选记录,可以返回null从ItemProcessor.该框架检测
结果是null并避免将该项添加到传递到
这ItemWriter.从ItemProcessor结果为
跳。
验证输入
ItemReaders 和 ItemWriters 一章讨论了分析输入的多种方法。
如果每个主要实现不是“格式正确”,则都会抛出一个异常。这FixedLengthTokenizer如果缺少数据范围,则引发异常。同样地
尝试访问RowMapper或FieldSetMapper不存在或
的格式与预期的格式不同,会导致引发异常。所有
这些类型的异常在read返回。但是,它们没有解决
退回的物品是否有效的问题。例如,如果其中一个字段
是一个时代,它不能是负数的。它可以正确解析,因为它存在并且
是一个数字,但它不会引起异常。由于已经有太多的
验证框架,Spring Batch 不会尝试提供另一个。相反,它
提供了一个简单的接口,称为Validator,您可以通过任意数量的
框架,如以下接口定义所示:
public interface Validator<T> {
    void validate(T value) throws ValidationException;
}
合同是validate如果对象无效,方法会抛出异常
如果有效,则正常返回。Spring Batch 提供了一个ValidatingItemProcessor,如以下 bean 定义所示:
<bean class="org.springframework.batch.item.validator.ValidatingItemProcessor">
    <property name="validator" ref="validator" />
</bean>
<bean id="validator" class="org.springframework.batch.item.validator.SpringValidator">
	<property name="validator">
		<bean class="org.springframework.batch.sample.domain.trade.internal.validator.TradeValidator"/>
	</property>
</bean>@Bean
public ValidatingItemProcessor itemProcessor() {
	ValidatingItemProcessor processor = new ValidatingItemProcessor();
	processor.setValidator(validator());
	return processor;
}
@Bean
public SpringValidator validator() {
	SpringValidator validator = new SpringValidator();
	validator.setValidator(new TradeValidator());
	return validator;
}
您还可以使用BeanValidatingItemProcessor验证注释为
Bean Validation API (JSR-303) 注解。例如,考虑以下类型Person:
class Person {
    @NotEmpty
    private String name;
    public Person(String name) {
     this.name = name;
    }
    public String getName() {
     return name;
    }
    public void setName(String name) {
     this.name = name;
    }
}
您可以通过声明BeanValidatingItemProcessor你的豆子
应用程序上下文,并将其注册为面向块的步骤中的处理器:
@Bean
public BeanValidatingItemProcessor<Person> beanValidatingItemProcessor() throws Exception {
    BeanValidatingItemProcessor<Person> beanValidatingItemProcessor = new BeanValidatingItemProcessor<>();
    beanValidatingItemProcessor.setFilter(true);
    return beanValidatingItemProcessor;
}