场景
正常接口返回时,会有一些字段是Date或者是LocalDateTime等值,默认是Jackson序列化处理,Date和LocalDateTime会被序列化成带T的时间格式。
其中created是Date类型,updated是LocalDateTime类型
处理Date
Date、Calender视为一类
响应参数
单个配置Date类型反序列化成指定格式的字符串可以使用@JsonFormat注解指定
@JsonFormat优先级比全局配置优先级高。如全局配置
date-format: yyyy-MM-dd HH:mm:ss
,注解配置pattern = "yyyy-MM-dd"
,实际按照注解的格式返回。
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date created;
复制
全局配置
配上jackson的spring配置文件,根据date-format格式会自动格式化Date数据类型。
配置上全局参数相当于Date、Calendar等类型的序列化默认值格式使用我们配置的格式。但是这个对LocalDateTime无效。
spring:
jackson:
# 设置 java.util.Date, Calendar 序列化、反序列化的格式
date-format: yyyy-MM-dd HH:mm:ss
# 当地时区
locale: zh
# 设置全局时区
time-zone: GMT+8
# 设置空如何序列化
defaultPropertyInclusion: always
serialization:
# 禁止将 java.util.Date, Calendar 序列化为数字(时间戳)
WRITE_DATES_AS_TIMESTAMPS: false
# 格式化输出
indent_output: false
# 序列化时,对象为 null,是否抛异常
fail_on_empty_beans: false
deserialization:
#允许对象忽略json中不存在的属性
fail_on_unknown_properties: false
复制
接收参数
Param参数
在需要接收的时间类型的param参数的位置加上@DateTimeFormat注解并设置对应的解析格式。
接收Param参数不管是Date还是LocalDateTime都需要在参数上加上@DateTimeFormat注解来自定义解析格式。必须加,全局配置无法覆盖
如果是用对象来接收param参数也是要在对象的属性上使用@DateTimeFormat的。
@RequestMapping("/ok")
public Object test(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date date) {
...
}
复制
对象属性
@Data
public class MyDate {
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date date;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Calendar calendar;
}
复制
Body参数
正常如果使用@JsonFormat注解的参数或者全局配置,可以自动转换Body参数,不需要额外的操作。
@RequestMapping("/ok")
public Object test(@RequestBody MyDate date) {
}
// 实体类上使用JsonFormat注解或者使用全局配置
@Data
public class MyDate {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date date;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Calendar calendar;
}
复制
处理LocalDateTime
LocalDateTime、LocalDate、LocalTime可以视为一类。
响应参数
LocalDateTime的单个响应参数的配置逻辑和Date逻辑一致。
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime updated;
复制
全局配置
自定义Jackson2ObjectMapperBuilderCustomizer实例注入到Spring中,添加LocalDateTime的时间处理模块。
添加了全局化配置后,LocalDateTime等类型就相当于自定义了默认格式化格式。
@Slf4j
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
return builder -> {
// 全局配置序列化返回 JSON 处理
JavaTimeModule javaTimeModule = new JavaTimeModule();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
// LocalDateTime默认格式化: yyyy-MM-ddTHH:mm:ss.SSS
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(dateTimeFormatter));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(dateTimeFormatter));
// LocalDate默认格式化: yyyy-MM-dd
// LocalDate默认比较符合习惯可以不改
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(dateFormatter));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateFormatter));
// LocalTime默认格式化: HH:mm:ss.SSS
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter));
builder.modules(javaTimeModule);
builder.timeZone(TimeZone.getDefault());
};
}
}
复制
接收参数
接收参数和Date类型的逻辑完全一样,不论Param参数还是Body参数。
@RequestMapping("/ok")
public Object test(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime date) {
...
}
复制
Spring转换器全局配置
对于Date和LocalDateTime的统一处理还可以在WebMvcConfigurer上添加MappingJackson2HttpMessageConverter转换器来解决,将自定义的一些转换器统一进行添加来支持接口响应的转换。
使用这个配置后,相当于Date的全局配置+LocalDateTime的全局配置。更推荐上面的方式
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
// 全局配置序列化返回 JSON 处理
JavaTimeModule javaTimeModule = new JavaTimeModule();
String pattern = "yyyy-MM-dd HH:mm:ss";
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(dateTimeFormatter));
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(dateFormatter));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(dateTimeFormatter));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateFormatter));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter));
// 禁止时间字段序列化成时间戳
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().modules(javaTimeModule)
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).build();
// 序列化对象null值不抛异常
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// date时间格式化
objectMapper.setDateFormat(new SimpleDateFormat(pattern));
converter.setObjectMapper(objectMapper);
converters.add(0, converter);
}
}
复制