我目前正在为应用程序设置文件导入服务,这将允许用户通过REST上传csv文件。作业的导入将通过Spring Batch完成,因为根据未来的处理要求和检查,这些作业可能会长时间运行。
根据我的说法,以下设置对于Spring Boot和Spring Batch是正确的,但代码不会编译。
主BatchConfiguration文件:
@Configuration
@EnableBatchProcessing
public class PatientBatchConfiguration {
@Autowired
private JobBuilderFactory jobBuilders;
@Autowired
private StepBuilderFactory stepBuilders;
@Autowired
private PatientFieldSetMapper fieldSetMapper;
@Autowired
private PatientItemWriter writer;
@Bean
public Job importPatientsFromUpload(){
return jobBuilders.get("importPatientsFromUpload")
.start(step())
.build();
}
@Bean
public Step step(){
return stepBuilders.get("step")
.<Patient,Patient>chunk(1)
.reader(reader(null))
.writer(writer)
.build();
}
@Bean
@StepScope
public ItemReader<Patient> reader(@Value("#{jobParameters['fileName']}") String filePath) {
FlatFileItemReader<Patient> itemReader = new FlatFileItemReader<Patient>();
itemReader.setLineMapper(lineMapper());
itemReader.setResource(new FileSystemResource(filePath));
return itemReader;
}
private LineMapper<Patient> lineMapper() {
DefaultLineMapper<Patient> lineMapper = new DefaultLineMapper<Patient>();
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setNames(new String[]{"name","surname","idNumber","dob", "email", "cell"});
lineMapper.setLineTokenizer(lineTokenizer);
lineMapper.setFieldSetMapper(fieldSetMapper);
return lineMapper;
}
}
FieldSetMapper代码:
@Component
public class PatientFieldSetMapper implements FieldSetMapper<Patient> {
@Override
public Patient mapFieldSet(FieldSet fieldSet) throws BindException {
if(fieldSet == null){
return null;
}
Patient patient = new Patient();
patient.setName(fieldSet.readString("name"));
patient.setSurname(fieldSet.readString("surname"));
patient.setIdNo(fieldSet.readString("idNumber"));
patient.setDob(0L);
patient.setEmail(fieldSet.readString("email"));
patient.setCell(fieldSet.readString("cell"));
return patient;
}
}
PatientItemWriter代码:
@Component
public class PatientItemWriter implements ItemWriter<Patient> {
@Autowired
PatientRepository patientRepository;
@Override
public void write(List<? extends Patient> list) throws Exception {
for(Patient patient: list) {
patientRepository.save(patient);
}
}
}
堆栈跟踪:
Caused by: java.lang.IllegalArgumentException: Path must not be null
at org.springframework.util.Assert.notNull(Assert.java:115) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.core.io.FileSystemResource.<init>(FileSystemResource.java:75) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at com.example.batch.patient.PatientBatchConfiguration.reader(PatientBatchConfiguration.java:59) ~[classes/:na]
at com.example.batch.patient.PatientBatchConfiguration.step(PatientBatchConfiguration.java:49) ~[classes/:na]
最后是application.properties文件
spring.batch.job.enabled=false
spring.batch.job.enabled = false位于属性文件中的原因是,在用户上传文件后,将从控制器调用作业importPatientsFromUpload,没有它,作业将在启动时运行。
我遇到的问题是FileSystemResource无法创建,因为路径不能为null。但是我知道只要用@StepScope注释一个方法,就会创建一个代理bean,这将允许我使用在运行时传递的jobParameter来创建一个新的文件系统资源。我已经在网上看到了各种使用jobParameters的例子,但由于某些原因,bean似乎没有正确创建。我不确定这是否与我使用Spring Boot或其他错误有关。
任何帮助将不胜感激。提前谢谢。
回复Gaël的更新
PatientItemReader代码:
@Component
@StepScope
public class PatientItemReader implements ItemReader<Patient> {
@Autowired
private PatientFieldSetMapper fieldSetMapper;
private FlatFileItemReader<Patient> itemReader;
@Override
public Patient read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
return itemReader.read();
}
public PatientItemReader(@Value("#{jobParameters[filePath]}") String filePath) {
itemReader = new FlatFileItemReader<Patient>();
DefaultLineMapper<Patient> lineMapper = new DefaultLineMapper<Patient>();
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setNames(new String[]{"name","surname","idNumber","dob", "email", "cell"});
lineMapper.setLineTokenizer(lineTokenizer);
lineMapper.setFieldSetMapper(fieldSetMapper);
itemReader.setLineMapper(lineMapper);
itemReader.setResource(new FileSystemResource(filePath));
}
}
答案 0 :(得分:2)
我想问题是你在Spring之外创建了一个读者,并在执行此操作时传递了null
值:
@Bean
public Step step(){
...
.reader(reader(null))
...
}
你应该做这样的事情,以便使用像后期绑定这样的Spring功能:
@Autowired
private ItemReader<Patient> reader;
@Bean
public Step step(){
...
.reader(reader)
...
}
正如你为作家所做的那样。
答案 1 :(得分:0)
当你使用@Bean时,它意味着你希望Spring容器来管理你的实例。所以,在这一步:
@Bean
public Step step() {...}
如果您想让读者实例构建一个步骤实例,则不能像reader(null)
一样使用。您应该将阅读器设置为步骤的参数,然后Spring容器将注入阅读器实例。这是严格的代码:
@Bean
public Step step(ItemReader<Patient> reader){
return stepBuilders.get("step")
.<Patient,Patient>chunk(1)
.reader(reader)
.writer(writer)
.build();
}