环境:jdk1.8、maven、springboot
问题:前端通过json传了一个日期:date:2019-03-01(我限制不了前端开发给到后端的日期为固定格式,有些人就是这么不配合),
而springboot中默认使用jackson做json序列化和反序列化,后台接收数据时将日期字符串转成LocalDateTime时,会报错:
1 Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.time.LocalDateTime` from String "2019-03-01":Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException) Text '2019-03-01' could not be parsed at index 10
2
3 at [Source: (PushbackInputStream); line: 1, column: 10] (through reference chain: com.XXX.vo.XXXExtVo["date"])
4 at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:67)
5 at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:1549)
6 at com.fasterxml.jackson.databind.DeserializationContext.handleWeirdStringValue(DeserializationContext.java:911)
7 at com.fasterxml.jackson.datatype.jsr310.deser.JSR310DeserializerBase._handleDateTimeException(JSR310DeserializerBase.java:80)
8 at com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer.deserialize(LocalDateTimeDeserializer.java:84)
9 at com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer.deserialize(LocalDateTimeDeserializer.java:39)
解决过程:
1.通过百度,参考了大神的解决方法:https://blog.csdn.net/a13794479495/article/details/83892829
2.maven引入依赖
1 <dependency>
2 <groupId>com.fasterxml.jackson.datatype</groupId>
3 <artifactId>jackson-datatype-jsr310</artifactId>
4 <version>2.9.7</version>
5 </dependency>
3.增加配置类:LocalDateTimeSerializerConfig
1 @Configuration
2 public class LocalDateTimeSerializerConfig {
3 @Bean
4 public ObjectMapper serializingObjectMapper() {
5 JavaTimeModule module = new JavaTimeModule();
6 LocalDateTimeDeserializer dateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
7 module.addDeserializer(LocalDateTime.class, dateTimeDeserializer);
8 return Jackson2ObjectMapperBuilder.json().modules(module)
9 .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).build();
10 }
11 }
4.由于自定义的LocalDateTimeDeserializer反序列化器只能设置一种格式:yyyy-MM-dd HH:mm:ss,所以我遇到的问题还是没有解决
5.对程序进行debug,发现反序列化操作是由LocalDateTimeDeserializer中的deserialize()方法进行反序列化操作的:
1 public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
2 if (parser.hasTokenId(6)) {//核心代码
3 String string = parser.getText().trim();
4 if (string.length() == 0) {
5 return null;
6 } else {
7 try {
8 if (this._formatter == DEFAULT_FORMATTER && string.length() > 10 && string.charAt(10) == 'T') {
9 return string.endsWith("Z") ? LocalDateTime.ofInstant(Instant.parse(string), ZoneOffset.UTC) : LocalDateTime.parse(string, DEFAULT_FORMATTER);
10 } else {
11 return LocalDateTime.parse(string, this._formatter);
12 }
13 } catch (DateTimeException var12) {
14 return (LocalDateTime)this._handleDateTimeException(context, var12, string);
15 }
16 }
17 } else {
18 if (parser.isExpectedStartArrayToken()) {
19 JsonToken t = parser.nextToken();
20 if (t == JsonToken.END_ARRAY) {
21 return null;
22 }
23
24 .........
25 .........
26 .........
27
28 return (LocalDateTime)this._handleUnexpectedToken(context, parser, "Expected array or string.", new Object[0]);
29 }
30 }
31 }
6.自定义一个MyLocalDateTimeDeserializer反序列化器(复制原来LocalDateTimeDeserializer类中的所有代码,粘贴到自定义的MyLocalDateTimeDeserializer中,修改构造器名及静态域中的相关代码)
7.然后修改MyLocalDateTimeDeserializer中的deserialize()方法
1 //这里只是简单的根据前端传过来的日期字符串进行简单的处理,然后再进行类型转换
2 //这段代码中有很多漏洞,只是针对常用格式做了简单处理,请慎用!或自己做更全面的考虑并相应的修改!(只是提供了这样一种解决思路)
3 public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
4 if (parser.hasTokenId(6)) {
5 String string = parser.getText().trim().replace("/", "-");//yyyy/MM/dd替换为yyyy-MM-dd
6 if (string.length() == 0) {
7 return null;
8 }
9 try {
10 if (this._formatter == DEFAULT_FORMATTER && string.length() > 10 && string.charAt(10) == 'T') {
11 return string.endsWith("Z") ? LocalDateTime.ofInstant(Instant.parse(string), ZoneOffset.UTC) : LocalDateTime.parse(string, DEFAULT_FORMATTER);
12 } else if (string.length() > 10 && string.charAt(10) == 'T') { //处理yyyy-MM-ddTHH:mm:ss.sssZ的格式
13 return string.endsWith("Z") ? LocalDateTime.ofInstant(Instant.parse(string), ZoneOffset.UTC) : LocalDateTime.parse(string, DEFAULT_FORMATTER);
14 } else if (string.length() == 10) {//处理yyyy-MM-dd的格式
15 return LocalDateTime.parse(string + " 00:00:00", this._formatter);
16 } else {//配置第三步的时候,设置了时间格式为:yyyy-MM-dd HH:mm:ss
17 return LocalDateTime.parse(string, this._formatter);
18 }
19 } catch (DateTimeException var12) {
20 return this._handleDateTimeException(context, var12, string);
21 }
22 } else {
23 if (parser.isExpectedStartArrayToken()) {
24 ..........
25 ..........
26 ..........
27 ..........
8.在之前第三步的 LocalDateTimeSerializerConfig 配置文件中,修改第六行的代码为:
MyLocalDateTimeDeserializer dateTimeDeserializer = new MyLocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
9.重启服务,验证是否问题解决。
此文仅为记录个人实践中遇到的问题及解决思路。如有雷同,仅可参考!
来源:oschina
链接:https://my.oschina.net/u/4353951/blog/3592698