问题引入

今天在做项目时前端传过来的json对象给后端时后台出现如下报错信息:

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type java.time.LocalDateTime from String “2020-11-06 22:48:18”: Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException) Text ‘2020-11-06 22:48:18’ could not be parsed at index 10; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type java.time.LocalDateTime from String “2020-11-06 22:48:18”: Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException) Text ‘2020-11-06 22:48:18’ could not be parsed at index 10

报错信息主要是说 在将字符串’2020-11-06 22:48:18’反序列化成LocalDateTime对象时发生了异常。

原因

默认情况下jackson 只能将”2020-11-06T22:48:18”转成LocalDateTime对象,可是”2018-09-20T08:01:00”这种格式的时间不符合国人的习惯,所以我之前将返回给前端的时间格式改成了”2020-11-06 22:48:18”,即默认时间格式中的T被换成了空格

问题也就随之而来了,报错信息显示在反序列化时间字符串时,字符串索引位置10处(即原来的T被换成了空格,导致默认的LocalDateTime反序列化器解析时间字符串失败)无法被解析。

默认的LocalDateTime序列化器只能将默认的时间格式”2020-11-06T22:48:18”转成LocalDateTime,而被我们改过格式的”2020-11-06 22:48:18”是不能被默认的LocalDateTime反序列化器转成LocalDateTime的。

也就是说

我们修改了默认的LocalDateTime序列化器输出的时间格式,但却并没有同时修改与其对应的反序列化器,所以我们只需要再添加一个能够解析我们自定义的时间格式的LocalDateTime反序列化器即可。

解决办法

先看我们之前的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@Configuration
public class LocalDateTimeConverter implements Converter<String, LocalDateTime> {

/**
* 获取配置文件中时间格式
*/
@Value("${spring.mvc.format.date}")
private String format;

/**
* 将URL中携带的的时间参数转化为LocalDateTime对象
* @param s 时间参数字符串
* @return LocalDateTime对象
*/
@Override
public LocalDateTime convert(String s) {
DateTimeFormatter df = DateTimeFormatter.ofPattern(format);
LocalDateTime date = null;
try {
date = LocalDateTime.parse(s, df);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}

/**
* 负责将LocalDateTime对象转化为Json对象时按规定的格式进行序列化
* 将LocalDateTime对象转化为json格式的字符串时间
* 例如: 将LocalDateTime的creatTime实例转为{"creatTime":"2020-11-08 23:05:28"}
* @return LocalDateTimeSerializer 序列化器对象
*/
@Bean
public LocalDateTimeSerializer localDateTimeSerializer() {
return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(format));
}

/**
* @return Jackson2ObjectMapperBuilderCustomizer
*/
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
// 调用按类型序列化方法serializerByType()
return builder -> builder.serializerByType(LocalDateTime.class, localDateTimeSerializer());
}
}

修改后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@Configuration
public class LocalDateTimeConverter implements Converter<String, LocalDateTime> {

/**
* 获取配置文件中时间格式
*/
@Value("${spring.mvc.format.date}")
private String format;

/**
* 将URL中携带的的时间参数转化为LocalDateTime对象
* @param s 时间参数字符串
* @return LocalDateTime对象
*/
@Override
public LocalDateTime convert(String s) {
DateTimeFormatter df = DateTimeFormatter.ofPattern(format);
LocalDateTime date = null;
try {
date = LocalDateTime.parse(s, df);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}

/**
* 负责将LocalDateTime对象转化为Json对象时按规定的格式进行序列化
* 将LocalDateTime对象转化为json格式的字符串时间
* 例如: 将LocalDateTime的creatTime实例转为{"creatTime":"2020-11-08 23:05:28"}
* @return LocalDateTimeSerializer 序列化器对象
*/
@Bean
public LocalDateTimeSerializer localDateTimeSerializer() {
return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(format));
}

/**
* 负责将Json对象转化为LocalDateTime对象时按规定的格式进行反序列化
* 将json格式的字符串时间转化为LocalDateTime对象
* 例如: 将 {"creatTime":"2020-11-08 23:05:28"}转为LocalDateTime的实例
* @return LocalDateTimeDeserializer 反序列化器对象
*/
@Bean
public LocalDateTimeDeserializer localDateTimeDeserializer() {
return new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(format));
}

/**
* @return Jackson2ObjectMapperBuilderCustomizer
*/
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> builder
// 调用按类型序列化方法serializerByType()
// 参数1 要序列化的类 参数2 该类的序列化器
.serializerByType(LocalDateTime.class, localDateTimeSerializer())
// 调用按类型反序列化方法deserializerByType()
// 参数1 要反序列化的类 参数2 该类的反序列化器
.deserializerByType(LocalDateTime.class,localDateTimeDeserializer());
}
}