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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

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

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

日期格式化時(shí)注解@DateTimeFormat無(wú)效的問題分析

背景

有時(shí)候我們?cè)趯懡涌跁r(shí),需要把前臺(tái)傳來(lái)的日期String類型轉(zhuǎn)為Date類型

這時(shí)我們可能會(huì)用到@DateTimeFormat注解

在請(qǐng)求數(shù)據(jù)為非JSON格式時(shí),這個(gè)注解是沒有問題的,可用的;

但是當(dāng)請(qǐng)求數(shù)據(jù)為JSON格式時(shí),問題就出現(xiàn)了

  • 此時(shí)如果請(qǐng)求參數(shù)沒有加@RequestBody注解,那么請(qǐng)求參數(shù)不會(huì)執(zhí)行類型轉(zhuǎn)換操作,數(shù)據(jù)都是默認(rèn)為空(基本類型比如int = 0, 對(duì)象引用比如Date date= null)
  • 此時(shí)如果請(qǐng)求參數(shù)有加@RequestBody注解,那么請(qǐng)求參數(shù)會(huì)執(zhí)行JSON類型轉(zhuǎn)換操作,但是轉(zhuǎn)換會(huì)提示異常

所以文章題目中所說(shuō)的有時(shí)無(wú)效,指的就是上面這兩種情況

目錄

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

分析

1. 基礎(chǔ)代碼:

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 實(shí)體類

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進(jìn)行測(cè)試,請(qǐng)求示例如下

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

示例1:

  • 請(qǐng)求方式:Post請(qǐng)求

  • 數(shù)據(jù)格式:非JSON格式,比如form-data

  • 請(qǐng)求資源:personPost(Person person),無(wú)@RequestBody注解

    具體請(qǐng)求內(nèi)容和返回結(jié)果如下所示

可以看到,前臺(tái)返回正常(數(shù)據(jù)無(wú)誤),說(shuō)明@DateTimeFormat有效,成功解析了日期字符串

這里返回的數(shù)據(jù)都是經(jīng)過@ResponseBody處理過的,因?yàn)槲覀儧]有配置返回?cái)?shù)據(jù)的日期格式化,所以這里返回的日期格式是默認(rèn)的

@ResponseBody對(duì)應(yīng)于@RequestBody;

  • 前者負(fù)責(zé)將Java對(duì)象序列號(hào)成JSON數(shù)據(jù)進(jìn)行返回
  • 后者負(fù)責(zé)解析請(qǐng)求過來(lái)的JSON數(shù)據(jù),解析成對(duì)應(yīng)的Java對(duì)象

我們?cè)賮?lái)看下后臺(tái),打印如下:

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

可以看到,后臺(tái)打印正常(數(shù)據(jù)無(wú)誤,日期格式忽略,因?yàn)檫@里的date.toString用的Date的默認(rèn)方法)

從上面的結(jié)果我們可以看到,@DateTimeFormat只是負(fù)責(zé)解析傳來(lái)的日期字符串,轉(zhuǎn)為對(duì)應(yīng)的日期對(duì)象;

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

示例2:

  • 請(qǐng)求方式:Post請(qǐng)求

  • 數(shù)據(jù)格式:JSON格式,比如application/json

  • 請(qǐng)求資源:personPost(Person person),無(wú)@RequestBody注解

    具體請(qǐng)求內(nèi)容和返回結(jié)果如下所示

可以看到,返回?cái)?shù)據(jù)都為空(默認(rèn)的初始值),說(shuō)明數(shù)據(jù)都沒有傳過去,不止是date,連基本類型int都沒過去

我們?cè)賮?lái)看下后臺(tái),打印如下

Person{age=0, birth=null} // 跟前臺(tái)返回的數(shù)據(jù)一致

可以看到,后臺(tái)解析到的數(shù)據(jù)也是空的,所以上面返回的當(dāng)然是空的

原因就是默認(rèn)的類型轉(zhuǎn)換器是沒有轉(zhuǎn)化成JSON格式的對(duì)應(yīng)轉(zhuǎn)換類的,部分轉(zhuǎn)換器如下所示,(core.convert.support包)

解決:所以這里對(duì)應(yīng)的解決辦法就是,自己創(chuàng)建一個(gè)JSON轉(zhuǎn)換器

但是實(shí)際上這個(gè)已經(jīng)有實(shí)現(xiàn)了,只是沒有觸發(fā),如下所示的構(gòu)建工具(http.converter.json包),就是用來(lái)配置相關(guān)的json序列化和反序列化的

現(xiàn)在我們可以通過@RequestBody注解來(lái)觸發(fā),它在接收到JSON格式的數(shù)據(jù)時(shí),會(huì)自動(dòng)調(diào)用對(duì)應(yīng)的JSON轉(zhuǎn)換器

下面的示例3就是這個(gè)例子

加了@RequestBody后,默認(rèn)只接受application/json格式的數(shù)據(jù),如果傳入其他格式,會(huì)報(bào)415不支持的類型

示例3:

  • 請(qǐng)求方式:Post請(qǐng)求

  • 數(shù)據(jù)格式:JSON格式,比如application/json

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

    具體請(qǐng)求內(nèi)容和返回結(jié)果如下所示

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

我們?cè)賮?lái)看下后臺(tái),打印如下

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"])]

這里我們提取關(guān)鍵的部分來(lái)看:

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不同,這里起碼做了嘗試轉(zhuǎn)換,只是沒有找到對(duì)應(yīng)的格式,所以轉(zhuǎn)換失敗了

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

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

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

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

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

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

局部的特點(diǎn):靈活,但是配置繁瑣,不統(tǒng)一(每個(gè)字段都要加)

  • 方案二:全局配置來(lái)解決,比如配置一個(gè)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) {// 覆蓋默認(rèn)的Date反序列化,第一個(gè)參數(shù)為需要反序列化的類,第二個(gè)為具體的序列化格式jacksonObjectMapperBuilder.deserializerByType(Date.class,new DateDeserializers.DateDeserializer(DateDeserializers.DateDeserializer.instance, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), null));} }

全局的特點(diǎn):不靈活,但是直觀清晰,配置統(tǒng)一

3. 結(jié)論分析:

主要根據(jù)請(qǐng)求的數(shù)據(jù)類型來(lái)對(duì)比

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

總結(jié)

注解相關(guān):

  • @DateTimeFormat注解:適用于請(qǐng)求數(shù)據(jù)為非JSON數(shù)據(jù),不會(huì)格式化返回?cái)?shù)據(jù)
  • @JsonFormat注解:適用于請(qǐng)求數(shù)據(jù)為JSON數(shù)據(jù)(尤其有日期數(shù)據(jù)時(shí)),且需在請(qǐng)求方法的參數(shù)前加@RequestBody`注解,會(huì)格式化返回?cái)?shù)據(jù)
  • @RequestBody注解:解析傳來(lái)的JSON數(shù)據(jù),轉(zhuǎn)換成對(duì)應(yīng)的Java對(duì)象
  • @ResponseBody注解:轉(zhuǎn)換Java對(duì)象為JSON數(shù)據(jù),用來(lái)作為返回?cái)?shù)據(jù)輸出到前端
  • 日期格式化相關(guān):

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

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

    后記

    學(xué)習(xí)之路漫漫,共勉之

    寫在最后:

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

    總結(jié)

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

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。