我正在学习Spring Batch,并且正在做一个示例程序,在该程序中,我需要将值从一个步骤传递到另一个步骤。
场景:我有一个人员表,在其中从中提取人员详细信息,将几列保存到DTO(在步骤1的ItemWriter中),并将值从DTO传递到where子句中的另一个表,用于从中提取相关值(在第2步的ItemReader中)。最后,我将使用所有这些值生成一个CSV。
这是我的代码:
@Bean
public Job job() throws UnexpectedInputException, ParseException, NonTransientResourceException, Exception {
return jobBuilderFactory.get("readDBJob").incrementer(new RunIdIncrementer()).start(step1()).next(step2())
.build();
}
@Bean
public Step step1() {
return stepBuilderFactory.get("step1").<Person, Person>chunk(500000).reader(itemReader())
.writer(itemWriter()).listener(promotionListener()).build();
}
@Bean
public Step step2() throws UnexpectedInputException, ParseException, NonTransientResourceException, Exception {
return stepBuilderFactory.get("step2").<Person, Result>chunk(100)
.reader(readingObjectItemReader.cursorReader()).writer(itemWriterForStep2()).build();
}
第1步的ItemWriter:
@Bean
public ItemWriter<Person> itemWriter() {
return new ItemWriter<Person>() {
private StepExecution stepExecution;
List<personDTO> responseList = null;
@Override
public void write(List<? extends Person> items) throws Exception {
for (Person item : items) {
personDTO responseObject = new personDTO();
BeanUtils.copyProperties(item, responseObject);
if(responseObject != null && responseObject.getPersonId() != null) {
if(stepExecution.getExecutionContext().containsKey("personDtoObject")) {
responseList = (List<personDTO>) this.stepExecution.getExecutionContext().get("personDtoObject");
} else {
responseList = new ArrayList<personDTO>();
}
responseList.add(responseObject);
this.stepExecution.getExecutionContext().put("personDtoObject", responseList);
}
}
}
@BeforeStep
public void saveStepExecution(StepExecution stepExecution) { this.stepExecution = stepExecution; }
};
}
作业执行上下文:
@Bean
public Object promotionListener() {
ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
listener.setKeys(new String[] {"personDtoObject"});
listener.setStrict(true);
return listener;
}
这是我尝试在步骤2 ItemReader中访问值的方式
公共类ReadingObjectItemReader实现ItemReader {
@Autowired
DataSource dataSource;
private List<personDTO> personDtoList;
String value;
@Override
public personDetails read()
throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
return null;
}
@Bean
public JdbcCursorItemReader<personDetails> cursorReader() {
System.out.println("Values from the step 1 " + personDtoList);
....
}
@BeforeStep
public void retrieveSharedData(StepExecution stepExecution) {
JobExecution jobExecution = stepExecution.getJobExecution();
ExecutionContext jobContext = jobExecution.getExecutionContext();
personDtoList= (List<personDTO>) jobContext.get("personDtoObject");
}
}
[当我尝试在步骤2中访问personDtoList的值时,我得到的是null。我在步骤1完成之前验证了StepContext中的值,直到那里一切都看起来不错,但是当尝试在步骤2中访问它们时,我得到的是空值。
我查看了在线上可用的大多数资源,但无法弄清楚我要去哪里。任何帮助表示赞赏。
非常感谢您的帮助。
在步骤1的项目编写器中,您正在执行:
ExecutionContext stepContext = this.stepExecution.getExecutionContext();
stepContext.put("personDtoObject", responseList);
这意味着您将覆盖每个块的先前列表。您需要做的是从执行上下文中获取列表,并在覆盖键之前添加项目。您还需要在步骤边界(也就是第一个块和最后一个块)处添加一些健全性检查,以确保在将其放入执行上下文之前(尤其是最后一个块)将列表初始化并且该列表不是null
)。