springboot中json轉換LocalDateTime失敗的bug解決過程


環境: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.重啟服務,驗證是否問題解決。

 

 

此文僅為記錄個人實踐中遇到的問題及解決思路。如有雷同,僅可參考!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM