SpringBoot中对LocalDateTime进⾏格式化并解析
【1】格式化后台传给前端的⽇期
⾸先第⼀点需要知道的是springboot默认依赖的json框架是jackson。当使⽤@ResponseBody注解返回json格式数据时就是该框架在起作⽤。
SpringBoot对Date/DateTime配置
如果字段属性是Date⽽⾮LocalDateTime时,通常我们会在application.properties⾥⾯配置如下:
spring.mvc.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.jackson.serialization.write-dates-as-timestamps=false
如下图所⽰,spring.jackson开头的配置会被JacksonProperties类获取进⾏使⽤。当返回json格式的时候,Jackson就会根据配置⽂件中⽇期格式化的配置对结果进⾏处理。
但是如果字段属性为LocalDateTime呢?这种配置就失去了作⽤。
第⼀种⽅式:配置localDateTimeSerializer
这时候建议配置如下:
/**
* Created by jianggc at 2020/7/1.
*/
@Configuration
public class LocalDateTimeSerializerConfig {
@Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")
private String pattern;
// localDateTime 序列化器
@Bean
public LocalDateTimeSerializer localDateTimeSerializer() {
return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern));
}
// localDateTime 反序列化器
@Bean
public LocalDateTimeDeserializer localDateTimeDeserializer() {
return new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(pattern));
}
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
/
/ return new Jackson2ObjectMapperBuilderCustomizer() {
// @Override
// public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
jacksonObjectMapperBuilder.featuresToDisable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// jacksonObjectMapperBuilder.serializerByType(LocalDateTime.class, localDateTimeSerializer());
// jacksonObjectMapperBuilder.deserializerByType(LocalDateTime.class,localDateTimeDeserializer());
// }
// };
//这种⽅式同上
return builder -> {
builder.serializerByType(LocalDateTime.class, localDateTimeSerializer());
builder.deserializerByType(LocalDateTime.class,localDateTimeDeserializer());
builder.simpleDateFormat(pattern);
};
}
}
第⼆种⽅式:@JsonFormat
这种配置⽅式⾃然是全局的,如果想针对某个字段特殊处理,可以在类字段上⾯添加注解@JsonFormat:
@JsonFormat( pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date createdDate;
@JsonFormat( pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createdTime;
【2】前台传String格式⽇期给后台
如下所⽰,前台传参2020-08-30 11:11:11,后台使⽤LocalDateTime 接收。通常会报错类似如下:
nested exception is onvert.ConversionFailedException:
Failed to convert from type [java.lang.String] to type [java.time.LocalDateTime ]
很显然是在参数绑定的时候没有到合适的转换器把String转换为对应的格式。
①配置全局的⽇期转换器localDateTimeConvert
@Bean
public Converter<String, LocalDateTime> localDateTimeConvert() {
return new Converter<String, LocalDateTime>() {
@Override
public LocalDateTime convert(String source) {
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTime = null;
try {
//2020-01-01 00:00:00
switch (source.length()){
case 10:
logger.debug("传过来的是⽇期格式:{}",source);
source=source+" 00:00:00";
break;
case 13:
logger.debug("传过来的是⽇期⼩时格式:{}",source);
source=source+":00:00";
break;
case 16:
logger.debug("传过来的是⽇期⼩时:分钟格式:{}",source);
source=source+":00";
break;
}
dateTime = LocalDateTime.parse(source, df);
} catch (Exception e) {
<(e.getMessage(),e);
}
return dateTime;
}
};
}
实现原理简要描述
在进⾏参数绑定的时候,会使⽤WebDataBinder对象。⽽创建WebDataBinder对象时,会遍历DefaultDataBinderFactory.initializer,使⽤其WebBindingInitializer initializer对WebDataBinder对象进⾏初始化。
初始化⽅法具体可见ConfigurableWebBindingInitializer.initBinder(WebDataBinder binder),源码如下:
public void initBinder(WebDataBinder binder) {
binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
if (this.directFieldAccess) {
binder.initDirectFieldAccess();
}
//设置messageCodesResolver
if (ssageCodesResolver != null) {
binder.ssageCodesResolver);
}
//设置bindingErrorProcessor
if (this.bindingErrorProcessor != null) {
binder.setBindingErrorProcessor(this.bindingErrorProcessor);
}
//设置validator
if (this.validator != null && Target() != null && this.validator.Target().getClass())) {
binder.setValidator(this.validator);
}
//设置conversionService
if (versionService != null) {
binder.versionService);
}
if (this.propertyEditorRegistrars != null) {
PropertyEditorRegistrar[] var2 = this.propertyEditorRegistrars;
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
PropertyEditorRegistrar propertyEditorRegistrar = var2[var4];
}
}
}
⽽conversionService中包含了许多的convert-类型格式化器。在WebDataBinder进⾏参数绑定的时候就会使⽤不同的格式化器即不同的convert进⾏参数类型转换。
关于参数绑定的过程,有兴趣的可以跟踪DataBinder.doBind⽅法,在这个过程中会对前台传输的值进⾏类型转换为⽬标参数需要的类型。⾃定义的localDateTimeConvert也是在这⾥被⽤到的。
到我们⾃定义的converter
springboot架构图调⽤convert进⾏类型转换:
可以看到转换后的结果为:
②配置⽇期格式化器
/**
* yyyy-MM-dd HH:mm:ss String-localDateTime
* @return
*/
@Bean
public Formatter<LocalDateTime> localDateTimeFormatter() {
return new Formatter<LocalDateTime>() {
@Override
public LocalDateTime parse(String text, Locale locale) throws ParseException {
return LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
@Override
public String print(LocalDateTime localDateTime, Locale locale) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return formatter.format(localDateTime);
}
};
}
⾃定义的格式化器会在SpringBoot启动时⾃动化配置过程中被加⼊,具体可以参考如下代码。
WebMvcAutoConfiguration.mvcConversionService:
@Bean
@Override
public FormattingConversionService mvcConversionService() {
WebConversionService conversionService = new WebConversionService(DateFormat());
addFormatters(conversionService);
return conversionService;
}
【3】convert是什么时候添加到ConversionService中的?
① SpringBoot启动的时候运⾏run⽅法
其会⾛到figureEnvironment⽅法处:
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
//从这⾥跟踪
ConversionService conversionService = SharedInstance();
environment.setConversionService((ConfigurableConversionService)conversionService);
}
}
②尝试获取ConversionService
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论