目录
1 时间格式化
1.1 出参格式化(Json)
创建一个测试类:
@Data
public class TestResponse {
@ApiModelProperty("未格式化时间")
private LocalDateTime localDateTime;
@ApiModelProperty("未格式化时间")
private LocalDate localDate;
@ApiModelProperty("未格式化时间")
private Date date;
}
restApi:
@GetMapping("test")
@ApiOperation("响应测试")
public TestResponse test(){
TestResponse response = new TestResponse();
response.setDate(new Date());
response.setLocalDateTime(LocalDateTime.now());
response.setLocalDate(LocalDate.now());
return response;
}
响应参数带Time的采用的是“ yyyy-MM-dd’T’HH:mm:ss.SSS ”格式,并且DATE默认使用的是UTC时间,比北京时间慢。

1.1.1 局部配置
在字段上加上注解@JsonFormat
@ApiModelProperty("已格式化时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;
@ApiModelProperty("已格式化时间")
@JsonFormat(pattern = "yyyy年MM月dd日")
private LocalDate localDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") //date默认使用UTC时间,北京时间得+8
@ApiModelProperty("已格式化时间")
private Date date;

@JsonFormat是jakson自带注解(spring家族默认使用jakson进行序列化与反序列化),常用属性如下:
| 属性 | 作用 |
|---|---|
| pattern | 格式化模板,如时间的’yyyy-MM-dd HH:mm:ss |
| shape | 决定数据类型,如NUMBER、ARRAY,默认为ANY,任何类型 |
| locale | 语言环境 |
| timezone | 时区,默认为UTC |

在JSR310FormattedSerializerBase类createContextual方法中会检查序列化器,首先会获取目标对象字段上的JsonFormat,如果JsonFormat 不为空,会读取其属性值。根据属性值创建DateTimeFormatter对象,并将其设置为序列化器模板。
最终通过HttpMessageConverter接口实现类的子类MappingJackson2HttpMessageConverter输出响应。MappingJackson2HttpMessageConverter为默认的Json转换类。

也就是更改了LocalDateSerializer、LocalDateTimeSerializer:


1.1.2 全局配置
注释掉@JsomFormat:

1.1.2.1 yml配置文件中进行全局配置
spring:
jackson:
# 全局配置,但是对LocalDateTime和LocalDate无效
date-format: yyyy-MM-dd HH:mm:ss
# 时区
time-zone: GMT+8
重启,可以看到我们在配置文件中设置的格式与时区注入进了ObjectMapper.

因为未对LocalDateSerializer和LocalDateTimeSerializer进行改动,结果只对date生效。

1.1.2.2 编写配置类进行全局配置(推荐)
先取消上一步的配置

手写ObjectMapper配置类:
@Configuration
public class DateTimeConfiguration {
@Bean
public ObjectMapper initObjectMapper(){
ObjectMapper objectMapper=new ObjectMapper();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
//JavaTimeModule 是jackson通过jsr310引入的JAVA8格式化类,没有此Module,序列化后的值会比较乱
objectMapper.registerModule(new JavaTimeModule());
return objectMapper;
}
}
运行结果同之前YML中配置一样:

所以LocalDateSerializer和LocalDateTimeSerializer中也得按我们需要的格式进行序列化:
@Bean
public ObjectMapper initObjectMapper(){
//自定义ObjectMapper配置并注册BEAN
ObjectMapper objectMapper=new ObjectMapper();
JavaTimeModule javaTimeModule=new JavaTimeModule();
//针对LocalDateTime和LocalDate
javaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
//针对Date类
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
//JavaTimeModule 是jackson通过jsr310引入的JAVA8格式化类,没有此Module,序列化后的值会比较乱
objectMapper.registerModule(javaTimeModule);
return objectMapper;
}
上面localdate字段未被全局序列化覆盖,因为字段上加了注解,说明局部优先于全局:

去掉注解:


也可以通过Jackson2ObjectMapperBuilder来构建新的ObjectMapper实例设置序列化与反序列化方式:
@Configuration
public class DateTimeConfiguration {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
//通过ObjectMapper构造器构建实例
return builder -> {
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); //date格式,序列化和反序列化都是它
//序列化
builder.serializerByType(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒")));
builder.serializerByType(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
//反序列化
builder.deserializerByType(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒")));
builder.deserializerByType(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
};
}
// @Bean
// public ObjectMapper initObjectMapper(){ //自定义ObjectMapper配置并注册BEAN
// ObjectMapper objectMapper=new ObjectMapper();
// JavaTimeModule javaTimeModule=new JavaTimeModule();
// //针对LocalDateTime和LocalDate
// javaTimeModule.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
// javaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
// //针对Date类
// objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// //JavaTimeModule 是jackson通过jsr310引入的JAVA8格式化类,没有此Module,序列化后的值会比较乱
// objectMapper.registerModule(javaTimeModule);
// return objectMapper;
// }
}
1.2 入参格式化
1.2.1 json参数
创建测试接口
@PostMapping("body")
@ApiOperation("json请求测试")
public TestResponse body(@RequestBody TestResponse testResponse){
log.info("打印的body:{}",testResponse);
return testResponse;
}


因为LocalDateTimeDeserializer与LocalDateDeserializer默认格式模板分别为’yyyy-MM-ddTHH:mm:ss 、'yyyy-MM-dd '.


我们按照默认格式传输自然没问题:


1.2.1.1 局部配置
同样,我们也可以像局部序列化一样局部反序列化时间。
还是使用@JsonFormat注解(序列化与反序列化一致),此时,标了注解字段全局序列化配置失效:
@ApiModelProperty("已格式化时间")
@JsonFormat(pattern = "yyyy年MM月dd日HH时mm分ss秒")
private LocalDateTime localDateTime;
@ApiModelProperty("已格式化时间")
@JsonFormat(pattern = "yyyy年MM月dd日")
private LocalDate localDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS") //date默认使用UTC时间,北京时间得+8
@ApiModelProperty("已格式化时间")
private Date date;
同序列化时相同,JSR310DateTimeDeserializerBase反序列化时也是读取注解中的属性值,创建新的JsonDeserializer(包括LocalDateTimeDeserializer、LocalDateDeserializer等)

1.2.1.2 全局配置
序列化我们用了全局配置,反序列化自然也应该使用全局配置
去掉注解:

再已有全局配置加上反序列化方式:
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> {
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); //date格式,序列化和反序列化都是它
//序列化
builder.serializerByType(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒")));
builder.serializerByType(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
//反序列化
builder.deserializerByType(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒")));
builder.deserializerByType(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
};
}

自然也可以自定义并注册ObjectMapper到BEAN
@Bean
public ObjectMapper initObjectMapper(){
//自定义ObjectMapper配置并注册BEAN
ObjectMapper objectMapper=new ObjectMapper();
JavaTimeModule javaTimeModule=new JavaTimeModule();
//针对LocalDateTime和LocalDate
//序列化
javaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
//反序列化
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
//针对Date类 序列化和反序列化都是它
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
//JavaTimeModule 是jackson通过jsr310引入的JAVA8格式化类,没有此Module,序列化后的值会比较乱
objectMapper.registerModule(javaTimeModule);
return objectMapper;
}
// @Bean
// public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
// return builder -> {
// builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); //date格式,序列化和反序列化都是它
// //序列化
// builder.serializerByType(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒")));
// builder.serializerByType(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
// //反序列化
// builder.deserializerByType(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒")));
// builder.deserializerByType(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
// };
// }
1.2.2 非json参数
将接口改入参改成非JSON类型
@PostMapping("param")
@ApiOperation("普通参数请求测试")
public TestResponse body(TestResponse testResponse){
try {
log.info("打印的param:{}",testResponse);
} catch (Exception e) {
e.printStackTrace();
}
return testResponse;
}


此时我们配置的json反序列化方式是无效的
1.2.2.1 局部配置
我们再字段上加上注解@DateTimeFormat
@ApiModelProperty("已格式化时间")
@DateTimeFormat(pattern = "yyyy年MM月dd日HH时mm分ss秒")
private LocalDateTime localDateTime;
@ApiModelProperty("已格式化时间")
@DateTimeFormat(pattern = "yyyy年MM月dd日")
private LocalDate localDate;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
@ApiModelProperty("已格式化时间")

本文详细介绍了Spring Boot中时间格式化和空值格式化的处理方法,包括Json时间出参格式化,涉及局部和全局配置,以及Json和非Json参数的入参格式化。对于空值格式化,文章讨论了如何将空值转换为特定格式,并解决了自定义转换器后时间序列化和反序列化失效的问题。
最低0.47元/天 解锁文章
1094

被折叠的 条评论
为什么被折叠?



