[英]Using Spring Batch to parse date from file into LocalDateTime
我正在尝试使用 Spring Batch 读取带有日期的 CSV 文件,但是我无法将日期解析为LocalDateTime
对象:
字段“日期”上的对象“目标”中的字段错误:拒绝值 [2017-07-20 04:15:25.0]; 代码 [typeMismatch.target.date,typeMismatch.date,typeMismatch.java.time.LocalDateTime,typeMismatch]; 参数 [org.springframework.context.support.DefaultMessageSourceResolvable: 代码 [target.date,date]; 参数 []; 默认消息 [日期]]; 默认消息 [无法将“java.lang.String”类型的属性值转换为属性“date”所需的类型“java.time.LocalDateTime”; 嵌套异常是 java.lang.IllegalStateException:无法将“java.lang.String”类型的值转换为属性“date”所需的类型“java.time.LocalDateTime”:找不到匹配的编辑器或转换策略]
Main.java
:
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringBatchDateParseConfig.class);
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job job = context.getBean("job", Job.class);
JobParameters jobParameters = new JobParametersBuilder().toJobParameters();
try {
JobExecution jobExecution = jobLauncher.run(job, jobParameters);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
SpringBatchDateParseConfig.java
:
@Configuration
@EnableBatchProcessing
public class SpringBatchDateParseConfig {
@Inject
private JobBuilderFactory jobBuilderFactory;
@Inject
private StepBuilderFactory stepBuilderFactory;
@Bean
public Step step1() {
return stepBuilderFactory.get("step1")
.<TestClass, TestClass>chunk(2)
.reader(testClassItemReader())
.writer(testClassItemWriter())
.build();
}
@Bean
public Job job(Step step1) {
return jobBuilderFactory.get("job")
.start(step1)
.build();
}
@Bean
FlatFileItemReader<TestClass> testClassItemReader() {
FlatFileItemReader<TestClass> flatFileItemReader = new FlatFileItemReader<>();
flatFileItemReader.setResource(new ClassPathResource("test.csv"));
flatFileItemReader.setLinesToSkip(1);
DefaultLineMapper defaultLineMapper = new DefaultLineMapper();
DelimitedLineTokenizer delimitedLineTokenizer = new DelimitedLineTokenizer();
delimitedLineTokenizer.setNames(new String[]{"foo", "bar", "date"});
BeanWrapperFieldSetMapper<TestClass> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
fieldSetMapper.setTargetType(TestClass.class);
defaultLineMapper.setLineTokenizer(delimitedLineTokenizer);
defaultLineMapper.setFieldSetMapper(fieldSetMapper);
flatFileItemReader.setLineMapper(defaultLineMapper);
return flatFileItemReader;
}
@Bean
ItemWriter<TestClass> testClassItemWriter() {
return new ItemWriter<TestClass>() {
@Override
public void write(List<? extends TestClass> items) throws Exception {
for (TestClass TestClass : items) {
System.out.println(TestClass.toString());
}
}
};
}
}
TestClass.java
:
public class TestClass {
private String foo;
private String bar;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME, pattern = "yyyy-MM-dd H:m:s.S")
private LocalDateTime date;
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
public LocalDateTime getDate() {
return date;
}
public void setDate(LocalDateTime date) {
this.date = date;
}
}
test.csv
:
foo,bar,date
asdf,fdsa,2017-07-20 04:15:25.0
qwerty,ytrewq,2017-07-20 04:15:25.0
我错过了什么吗?
您可以覆盖BeanWrapperFieldSetMapper<T>
initBinder
方法:
public class BeanWrapperFieldSetMapperCustom<T> extends BeanWrapperFieldSetMapper<T> {
@Override
protected void initBinder(DataBinder binder) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.isNotEmpty(text)) {
setValue(LocalDate.parse(text, formatter));
} else {
setValue(null);
}
}
@Override
public String getAsText() throws IllegalArgumentException {
Object date = getValue();
if (date != null) {
return formatter.format((LocalDate) date);
} else {
return "";
}
}
});
}
}
请使用标准方法进行数据转换:
您可以轻松扩展和自定义支持的数据类型
@Configuration
@EnableBatchProcessing
public class SpringBatchDateParseConfig {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public ConversionService testConversionService() {
DefaultConversionService testConversionService = new DefaultConversionService();
DefaultConversionService.addDefaultConverters(testConversionService);
testConversionService.addConverter(new Converter<String, LocalDateTime>() {
@Override
public LocalDateTime convert(String text) {
return LocalDateTime.parse(text, DateTimeFormatter.ISO_DATE_TIME);
}
});
return testConversionService;
}
@Bean
public FieldSetMapper<TestClass> testClassRowMapper(ConversionService testConversionService) {
BeanWrapperFieldSetMapper<TestClass> mapper = new BeanWrapperFieldSetMapper<>();
mapper.setConversionService(testConversionService);
mapper.setTargetType(TestClass.class);
return mapper;
}
@Bean
FlatFileItemReader<TestClass> testClassItemReader(FieldSetMapper<TestClass> testClassRowMapper) {
return new FlatFileItemReaderBuilder<TestClass>().delimited()
.delimiter(",")
.names(new String[]{"foo", "bar", "date"})
.linesToSkip(1)
.resource(new ClassPathResource("test.csv"))
.fieldSetMapper(testClassRowMapper)
.build();
}
@Bean
public Step step1(FieldSetMapper<TestClass> testClassRowMapper) {
return stepBuilderFactory.get("step1")
.<TestClass, TestClass>chunk(2)
.reader(testClassItemReader(testClassRowMapper))
.writer(testClassItemWriter())
.build();
}
@Bean
public Job job(Step step1) {
return jobBuilderFactory.get("job")
.start(step1)
.build();
}
@Bean
ItemWriter<TestClass> testClassItemWriter() {
return new ItemWriter<TestClass>() {
@Override
public void write(List<? extends TestClass> items) throws Exception {
for (TestClass TestClass : items) {
System.out.println(TestClass.toString());
}
}
};
}
}
我使用了 Pavel 的解决方案,因为将 Power 赋予 ConversionService 对我来说似乎是一个更清晰的解决方案。
我的 CSV 中的日期格式如下:10.01.20 所以模式是:“dd.MM.yy”,我需要从中创建 LocalDate 对象。
这是我的自定义 ConversionService:
public ConversionService createConversionService() {
DefaultConversionService conversionService = new DefaultConversionService();
DefaultConversionService.addDefaultConverters(conversionService);
conversionService.addConverter(new Converter<String, LocalDate>() {
@Override
public LocalDate convert(String text) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yy");
return LocalDate.parse(text, formatter);
}
});
return conversionService;
}
然后我将此自定义 ConversionService 添加到我在 ItemReader 中使用的 BeanWrapperFieldSetMapper。
fieldSetMapper.setConversionService(createConversionService());
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.