日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

日期格式化时注解@DateTimeFormat无效的问题分析

發布時間:2025/3/12 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 日期格式化时注解@DateTimeFormat无效的问题分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

日期格式化時注解@DateTimeFormat無效的問題分析

背景

有時候我們在寫接口時,需要把前臺傳來的日期String類型轉為Date類型

這時我們可能會用到@DateTimeFormat注解

在請求數據為非JSON格式時,這個注解是沒有問題的,可用的;

但是當請求數據為JSON格式時,問題就出現了

  • 此時如果請求參數沒有加@RequestBody注解,那么請求參數不會執行類型轉換操作,數據都是默認為空(基本類型比如int = 0, 對象引用比如Date date= null)
  • 此時如果請求參數有加@RequestBody注解,那么請求參數會執行JSON類型轉換操作,但是轉換會提示異常

所以文章題目中所說的有時無效,指的就是上面這兩種情況

目錄

本文分三步走,如下所示,其中會穿插著介紹@DateTimeFormat、@RequestBody、@JsonFormat注解

分析

1. 基礎代碼:

AnnationApplication.java:主程序兼控制器

package com.jalon.annation;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController;@SpringBootApplication @RestController public class AnnationApplication {public static void main(String[] args) {SpringApplication.run(AnnationApplication.class, args);}@PostMapping("/personPost")public Person personPost(Person person){System.out.println(person);return person;} }

Person.java 實體類

package com.jalon.annation;import com.fasterxml.jackson.annotation.JacksonAnnotation; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Component;import java.util.Date;public class Person {private int age;@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date birth;@Overridepublic String toString() {return "Person{" +"age=" + age +", birth=" + birth +'}';}// 省略getter/setter }

2. 案例分析:

這里我們用的是PostMan進行測試,請求示例如下

所有示例全程都有@DateTimeFormat注解

示例1:

  • 請求方式:Post請求

  • 數據格式:非JSON格式,比如form-data

  • 請求資源:personPost(Person person),無@RequestBody注解

    具體請求內容和返回結果如下所示

可以看到,前臺返回正常(數據無誤),說明@DateTimeFormat有效,成功解析了日期字符串

這里返回的數據都是經過@ResponseBody處理過的,因為我們沒有配置返回數據的日期格式化,所以這里返回的日期格式是默認的

@ResponseBody對應于@RequestBody;

  • 前者負責將Java對象序列號成JSON數據進行返回
  • 后者負責解析請求過來的JSON數據,解析成對應的Java對象

我們再來看下后臺,打印如下:

Person{age=1, birth=Wed Jan 01 00:00:00 CST 2020}

可以看到,后臺打印正常(數據無誤,日期格式忽略,因為這里的date.toString用的Date的默認方法)

從上面的結果我們可以看到,@DateTimeFormat只是負責解析傳來的日期字符串,轉為對應的日期對象;

但是并不會修改原有的日期對象的格式(從前臺返回和后臺輸出可以看到,日期格式不受@DateTimeFormat的影響)

示例2:

  • 請求方式:Post請求

  • 數據格式:JSON格式,比如application/json

  • 請求資源:personPost(Person person),無@RequestBody注解

    具體請求內容和返回結果如下所示

可以看到,返回數據都為空(默認的初始值),說明數據都沒有傳過去,不止是date,連基本類型int都沒過去

我們再來看下后臺,打印如下

Person{age=0, birth=null} // 跟前臺返回的數據一致

可以看到,后臺解析到的數據也是空的,所以上面返回的當然是空的

原因就是默認的類型轉換器是沒有轉化成JSON格式的對應轉換類的,部分轉換器如下所示,(core.convert.support包)

解決:所以這里對應的解決辦法就是,自己創建一個JSON轉換器

但是實際上這個已經有實現了,只是沒有觸發,如下所示的構建工具(http.converter.json包),就是用來配置相關的json序列化和反序列化的

現在我們可以通過@RequestBody注解來觸發,它在接收到JSON格式的數據時,會自動調用對應的JSON轉換器

下面的示例3就是這個例子

加了@RequestBody后,默認只接受application/json格式的數據,如果傳入其他格式,會報415不支持的類型

示例3:

  • 請求方式:Post請求

  • 數據格式:JSON格式,比如application/json

  • 請求資源:personPost(@RequestBody Person person),有@RequestBody注解

    具體請求內容和返回結果如下所示

可以看到,報錯了,提示400,這種一般屬于客戶端錯誤(比如數據格式不正確,數據過大等)

我們再來看下后臺,打印如下

2021-05-15 13:48:41.578 WARN 38426 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.Date` from String "2020-01-01 00:00:00": not a valid representation (error: Failed to parse Date value '2020-01-01 00:00:00': Cannot parse date "2020- 01-01 00:00:00": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSX', parsing fails (leniency? null)); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException:Cannot deserialize value of type `java.util.Date` from String "2020-01-01 00:00:00": not a valid representation (error: Failed to parse Date value '2020-01-01 00:00:00': Cannot parse date "2020-01-01 00:00:00": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSX', parsing fails (leniency? null))at [Source: (PushbackInputStream); line: 3, column: 14] (through reference chain: com.jalon.annation.Person["birth"])]

這里我們提取關鍵的部分來看:

1. nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String "2020-01-01 00:00:00"2. Cannot parse date "2020-01-01 00:00:00": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSX'

首先這里跟示例2不同,這里起碼做了嘗試轉換,只是沒有找到對應的格式,所以轉換失敗了

可以看到,它并沒有按照上面我們的@DateTimeFormat注解去解析,而是按照’'yyyy-MM-dd’T’HH:mm:ss.SSSX"這個格式去解析

這里如果想投機的話,可以在前臺直接傳入’'yyyy-MM-dd’T’HH:mm:ss.SSSX’格式的數據,如下:

但是這種辦法對于前端很不友好(極其不好)

所以下面還是給出正常的解決辦法

解決:所以這里的解決辦法就是自己定義日期格式

  • 方案一:局部注解來解決,比如在date字段添加@JsonFormat()注解
// 這個注解用來解析JSON數據中的日期字符串,會序列化返回數據 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date birth;

局部的特點:靈活,但是配置繁瑣,不統一(每個字段都要加)

  • 方案二:全局配置來解決,比如配置一個Jackson2ObjectMapperBuilderCustomizer,然后自定義日期反序列化格式
package com.jalon.annation;import com.fasterxml.jackson.databind.deser.std.DateDeserializers; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;import java.text.SimpleDateFormat; import java.util.Date;@Configuration public class MyDateConvertCustoms implements Jackson2ObjectMapperBuilderCustomizer {@Overridepublic void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {// 覆蓋默認的Date反序列化,第一個參數為需要反序列化的類,第二個為具體的序列化格式jacksonObjectMapperBuilder.deserializerByType(Date.class,new DateDeserializers.DateDeserializer(DateDeserializers.DateDeserializer.instance, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), null));} }

全局的特點:不靈活,但是直觀清晰,配置統一

3. 結論分析:

主要根據請求的數據類型來對比

  • 請求非JSON數據,建議用@DateTimeFormat即可(比如get請求,當然get請求也可以請求JSON數據,只是不推薦)
  • 請求JSON數據,建議用@ReqeustBody來轉換數據,然后搭配局部注解@JsonFormat或者全局配置來修改默認的日期解析格式(默認"yyyy-MM-dd’T’HH:mm:ss.SSSX")

總結

注解相關:

  • @DateTimeFormat注解:適用于請求數據為非JSON數據,不會格式化返回數據
  • @JsonFormat注解:適用于請求數據為JSON數據(尤其有日期數據時),且需在請求方法的參數前加@RequestBody`注解,會格式化返回數據
  • @RequestBody注解:解析傳來的JSON數據,轉換成對應的Java對象
  • @ResponseBody注解:轉換Java對象為JSON數據,用來作為返回數據輸出到前端
  • 日期格式化相關:

  • 請求非JSON數據,建議用@DateTimeFormat即可,此時不會格式化返回數據(比如get請求,當然get請求也可以請求JSON數據,只是不推薦)
  • 請求JSON數據,建議用@ReqeustBody來轉換數據,然后搭配局部注解@JsonFormat(會格式化返回數據)或者全局配置來修改默認的日期解析格式(默認"yyyy-MM-dd’T’HH:mm:ss.SSSX");全局配置也可以格式化返回數據,需配置builder.serializerByType
  • 如果日期格式化出錯,先看傳來的數據是否為JSON數據(可以通過consumes來限制),然后再看有沒有對于的注解或日期格式化全局配置
  • 參考內容:

    • @RequestBody: https://blog.csdn.net/justry_deng/article/details/80972817/
    • @DateTimeFormat: https://segmentfault.com/a/1190000020423352

    后記

    學習之路漫漫,共勉之

    寫在最后:

    愿你的意中人亦是中意你之人

    總結

    以上是生活随笔為你收集整理的日期格式化时注解@DateTimeFormat无效的问题分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。