国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

查漏補缺@DateTimeFormat到底干了些啥

開發 前端
Spring中的轉換器、格式化器是整個Spring技術棧體系中非常重要的一份子,是眾多高級特性的基礎支撐。

[[385892]]

本文轉載自微信公眾號「BAT的烏托邦」,作者YourBatman。轉載本文請聯系BAT的烏托邦公眾號。

本文提綱

版本約定

  • Spring Framework:5.3.x
  • Spring Boot:2.4.x

正文

Spring中的轉換器、格式化器是整個Spring技術棧體系中非常重要的一份子,是眾多高級特性的基礎支撐。

作為一個Spring的使用者,也許你工作了好幾年都只接觸到@DateTimeFormat這個注解才感知到Spring是有格式化能力的;也許你在使用xml配置、Spring MVC時全然不知自動化封裝的流程,也就感知不到Converter轉換器模塊的存在;也許你還一直不確定@DateTimeFormat能標注在哪些類型上,每次使用時都得用谷歌百度一下......

作為一個Spring的開發者,以上不應該再成為問題。而是能說會道,滾瓜爛熟。下面將本文補充內容傳遞給你,坐穩發車嘍。

@DateTimeFormat注解到底做了什么?

不用猜,很多程序員同學知道/使用@DateTimeFormat注解是在Spring MVC場景,甚至只是在此場景:前端傳一個日期時間格式的值,后端使用Date/LocalDateTime接收此值時使用。

Request的請求實體形如這樣:

  1. @Data 
  2. public class Person{ 
  3.   
  4.  @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss"
  5.  private LocalDateTime arriveTime; 

這么一來,前端傳入"2021-03-07 21:00:00"這種格式的字符串就能被自動封裝進arriveTime了。

說明:String -> LocalDateTime arriveTime屬于Parser功能(也稱作輸入),此注解在xxx -> String輸出時(Printer功能)也會生效的?

使用了@DateTimeFormat這么久,你是否知道它并不屬于spring-web/spring-webmvc模塊的類,而是屬于spring-context:org.springframework.format.annotation.DateTimeFormat。換句話講:@DateTimeForma它屬于基礎設施類,并不是只能用于web層,而是可用于所有有需要轉換的地方。

通過上篇文章 我們知道了,@DateTimeFormat和@NumberFormat注解的功能底層是依賴于AnnotationFormatterFactory以及格式化器注冊中心FormatterRegistry核心API去完成的。那么這個流程是怎樣的呢?

可能這么說還是覺得比較抽象,那么我嘗試畫了一幅流程圖,可助你掌握這部分的核心工作原理(執行流程):

該流程可釋義為:通過格式化器注冊中心FormatterRegistry的API向其注冊注解工廠AnnotationFormatterFactory以支持格式化注解。但是,底層其實都(為每個FieldType類型)適配為了Converter才注冊到FormatterRegistry進去的。換句話講:FormatterRegistry(其實是ConverterRegistry)底層管理的永遠是一些簡單的Converter轉換器們,這便也符合了越底層越抽象,越上層越具體的設計原則,是一種良好的設計方案。

值得注意:ConverterRegistry管理的底層這些Converter是分為三大類的喲。1:1、1:N、N:N?

向注冊中心注冊完成后,轉換服務就具備了AnnotationFormatterFactory所支持的類型FieldType <-> String互相轉換的能力了。當然嘍,讓其能執行轉換動作還有個前提條件是FieldType上必須標注有AnnotationFormatterFactory指定的注解類型才行,這個時候@DateTimeFormat就發揮作用啦。

這么來看,@DateTimeFormat注解自己其實并未做什么,只是純被當做Field上的一個元數據被用作參與判斷、格式化時所需參數的指定,此注解它是面向開發者的。真正做了“很多事”的其實是AnnotationFormatterFactory和FormatterRegistry等底層核心API,它們在初始化階段就默默全部完成,而這一切(較為復雜)的邏輯對開發者是完全透明的。

JSR 310日期時間注冊員

上篇文章 介紹了Spring格式化器倒排思想,其具體體現在FormatterRegistrar接口的設計,上文用“比較古老”的支持java.util.Date類型的DateFormatterRegistrar打了個樣,體驗了一把倒排設計的好處。

我們知道在Java領域日期時間類型分為三大領域:老Date體系、JSR 310體系、Joda-time體系。這不FormatterRegistrar接口的繼承體系三個實現類剛好與之對應:

A哥不建議在開發中再以任何理由再使用Date類型,而是用JSR 310取以代之。因此接下來,就看看DateTimeFormatterRegistrar注冊員為我們做了哪些事。

DateTimeFormatterRegistrar:JSR 310注冊員

Since 4.0。在Spring下使用以支持JSR 310日期時間的格式化/轉換。

我們知道,JSR 310對日期時間的格式化其實已經非常完善了,具體都體現在java.time.format.DateTimeFormatter這個Java原生API里。Spring針對于JSR 310日期時間類型格式化只是在DateTimeFormatter的基礎上做了簡單封裝和適配,讓它使用起來的姿勢盡量和Date/JodaTime保持一致,以便對開發者更加友好,代碼結構設計上也能夠趨近于統一。

本系列前面文章介紹過的DateTimeFormatterFactory便是對DateTimeFormatter的簡單包裝,用于生產格式化器實例的工廠。此處的DateTimeFormatterRegistrar就使用它倆來進行一系列注冊動作,因此可理解為他是更上層的封裝形式。

源碼分析

下面從源碼下手一探究竟。

截圖里示例出該實現類支持的類型,這里用自定義的枚舉類來更抽象的方式定義為三類了,即日期、時間、日期時間。這三大類其實包含了JSR 310類型的主要API,包括:LocalDate、LocalTime、LocalDateTime、ZonedDateTime、OffsetDateTime、OffsetTime共計6個API。對比一下這不正就是Jsr310DateTimeFormatAnnotationFormatterFactory所支持的六大類型么,如下截圖所示:

說明:該份截圖是說明@DateTimeFormat只能標注在JSR 310日期時間的這6種類型上才有效哦。

其實,在任何時候Spring都不建議你直接使用原生的DateTimeFormatter這個API,而是用其封裝過的org.springframework.format.datetime.standard.DateTimeFormatterFactory來獲得一個DateTimeFormatter實例,以便使用起來更具統一性和靈活性。

這不DateTimeFormatterRegistrar它就是這么來干的:

這是唯一構造器:3個類型對應的DateTimeFormatter均由Spring封裝過的DateTimeFormatterFactory工廠來“動態”產生,而非直接綁定。由于DateTimeFormatter被設計為不可變,若初始化時就綁定上,后面將無法做定制化設置。這也是引入DateTimeFormatterFactory來做定制化參數“緩存”的又一作用~

由于使用DateTimeFormatterFactory而并非直接使用DateTimeFormatter,就可以很方便的對不同類型做參數定制化,如下方法們,它們是作用在DateTimeFormatterFactory上的,從而可以確保多個條件共存:

當然,最重要的當屬對FormatterRegistrar 接口方法 的實現邏輯:

①:這個 步驟類似于上文講述DateFormatterRegistrar時調用其public靜態方法addDateConverters(registry),作用為注冊基礎轉換器(如Date -> Calendar,Date -> Long的Converter轉換器),從而提供基本的轉換能力。值得注意的是:DateTimeConverters.registerConverters(registry)內部調用了DateFormatterRegistrar.addDateConverters(registry),并且額外增加了LocalDate、Calendar、Long、Instant等等的Converter轉換器(如ZonedDateTimeToLocalDateConverter、LongToInstantConverter等等),后者是前者的超集。

無獨有偶:jodaTime的JodaTimeConverters.registerConverters(registry)內部必然也調用了DateFormatterRegistrar.addDateConverters(registry)嘍,感興趣可自己去瞅瞅確認下?

②:生成每個類型對應的格式化器。簡單的講就是通過DateTimeFormatterFactory創建出對應的格式化器DateTimeFormatter③:這一步的作用在源碼中的注釋部分解釋得很清楚了,這一大段代碼的作用是使用ISO_LOCAL_*這種變種格式化器來代替執行,效果是性能提升2倍

?說明:這個做法在前文提到的Jsr310DateTimeFormatAnnotationFormatterFactory里getPrinter()生成格式化器時也被用到了用以成倍提升轉換性能?

④:對于不需要特殊提速的類型,注冊綁定上專用的格式化器org.springframework.format.Formatter即可。如PeriodFormatter、DurationFormatter等

⑤:讓@DateTimeFormat注解對JSR 310日期時間提供支持。關于格式化注解方面的知識,請向上爬2層樓 or 點擊文首/文末推薦鏈接均可進入文章進行詳細了解,加深記憶。

代碼示例

下面介紹DateTimeFormatterRegistrar注冊員的使用示例,其中包括API使用方式,以及面向注解的使用方式。

API使用方式

此類使用方式一般門檻較高,需要對底層API有較熟了解才能運用自如,一般是需要在Spring基礎上做二次開發的小伙伴才會用到,用個簡單示例了解一下用法:

  1. @Test 
  2. public void test1() { 
  3.     FormattingConversionService conversionService = new FormattingConversionService(); 
  4.     // 注冊員負責添加格式化器以支持Date系列的轉換 
  5.     new DateTimeFormatterRegistrar().registerFormatters((FormatterRegistry) conversionService); 
  6.  
  7.     // 1、普通使用(API方式) 
  8.     LocalDateTime now = LocalDateTime.now(); 
  9.     System.out.println("當前時間:" + now); 
  10.     System.out.println("LocalDateTime轉為LocalDate:" + conversionService.convert(now, LocalDate.class)); 
  11.     System.out.println("LocalDateTime轉為LocalTime:" + conversionService.convert(now, LocalTime.class)); 
  12.  
  13.     // 時間戳轉Instant 
  14.     long currMills = System.currentTimeMillis(); 
  15.     System.out.println("當前時間戳:" + currMills); 
  16.     System.out.println("時間戳轉Instant:" + conversionService.convert(currMills, Instant.class)); 

運行程序,輸出:

  1. 當前時間:2021-03-07T21:19:39.752 
  2. LocalDateTime轉為LocalDate:2021-03-07 
  3. LocalDateTime轉為LocalTime:21:19:39.752 
  4. 當前時間戳:1615123179763 
  5. 時間戳轉Instant:2021-03-07T13:19:39.763Z 

完美。

通過這個示例,現在知道為啥前端傳個時間戳,后端不用Long而使用Instant也能“接得住”不報錯了吧~

注解使用方式

見與Spring MVC整合使用方式章節,詳細解釋。

JodaTimeFormatterRegistrar:joda-time注冊員

@deprecated as of 5.3,請使用Java標準的JSR 310日期時間代替

Tips:JodaDateTimeFormatAnnotationFormatterFactoryy也一樣在5.3版本被標記為過期了?

jodaTime曾經乃是絕對的王者,拯救Java日期時間于水火,直到JSR 310體系的出現。同樣的那句話送給你:建議不要在(新)項目中以任何理由去使用jodaTime,而是和Date一樣完全放棄,使用JSR 310足矣。

說明:現在不建議再使用JodaTime并非卸磨殺驢,而是JSR 310就是jodaTime的作者/組織捐贈給Java的(你看那語法,多像!),所以現在叫功成身退更為恰當?

由于jodaTime不像Date一樣有那么重的歷史包袱(關鍵Date還是JDK內置的核心類),并且它和JSR 310一脈相承,因此在可預見的將來它將徹底告別Java舞臺,逐漸消亡。所以呢,我個人認為,再去學習jodaTime(包括周邊)已再無必要,so此part就暫且略過嘍。

總結

作為“失聯”很久的“第一篇”文章,本文沒有太多新內容,主要是對前兩篇收個尾,為下一場做足鋪墊。本文雖為補充性內容,但“含金量”依舊還是有的,希望對你有所幫助,敬請期待本系列接下來的精彩內容。

本文思考題

本文所屬專欄:Spring類型轉換,后臺回復專欄名即可獲取全部內容,已被https://yourbatman.cn收錄。

看完了不一定懂,看懂了不一定會。來,文末3個思考題幫你復盤:

@DateTimeFormat能標注在LocalDateTime上面嗎?

JSR 310日期時間有哪些常見API?

@DateTimeFormat注解如何在普通Java Bean上使用?

 

責任編輯:武曉燕 來源: BAT的烏托邦
相關推薦

2020-06-02 16:30:20

Redis數據庫字符串

2024-02-26 09:36:10

toggleAPIweb

2021-03-04 08:26:17

synchronizeReentrantLojava

2018-12-05 10:44:41

Redis缺點程序員

2021-03-17 13:44:14

隱私信息安全手機

2023-10-09 08:31:19

2021-11-04 12:42:55

RocketMQ啟動消費

2019-09-24 09:46:35

Tomcat連接器Lifecycle

2022-02-17 10:56:33

Redis數據系統

2018-04-04 09:00:00

區塊鏈X即服務微軟

2022-09-21 16:25:17

Redis性能

2020-01-09 13:31:50

AI 數據人工智能

2021-03-17 10:20:14

網絡安全網絡安全技術周刊

2015-07-07 17:21:46

2024-04-26 06:46:27

量化剪枝模型

2021-02-27 11:03:26

算法職責ICBU

2015-03-02 10:35:25

百度專利經費

2020-04-07 16:21:38

疫情科技企業

2009-06-03 09:08:36

2020-11-24 08:05:18

5G衛星通信
點贊
收藏

51CTO技術棧公眾號

粉嫩av一区二区三区| 欧美性受极品xxxx喷水| 在线免费一区| 青青草伊人久久| 秋霞在线观看一区二区三区| 日本在线不卡一区| 国产成人生活片| 99久久免费国产| 中文字幕国内自拍| 亚洲成精国产精品女| 人人九九精品| 这里只有精品视频在线观看| 在线手机中文字幕| 欧美大片在线看| 成人区精品一区二区婷婷| 91麻豆国产语对白在线观看| 日韩一区欧美二区| 777米奇影视第四色| 亚洲国产日日夜夜| 久久久亚洲成人| 韩国精品免费视频| www.色偷偷.com| 在线成人国产| 50度灰在线观看| 91官网在线观看| 成人亚洲性情网站www在线观看| 欧美专区亚洲专区| 欧美一区1区三区3区公司| 日本精品视频一区二区| 国产探花一区| 欧美精品xxx| 欧美激情四色| 亚洲一卡二卡三卡| 久做在线视频免费观看| 中文字幕免费精品一区高清| 女优一区二区三区| 日韩av电影免费观看| 国产精品每日更新在线播放网址 | 久久伊人精品天天| 日韩欧美高清| 色哟哟免费网站| 色综合久久久久久久久| 九七电影院97理论片久久tvb| 成人网欧美在线视频| 国产成人日日夜夜| 国产香蕉视频在线看| 久久综合免费视频影院| 在线国产欧美| 国产网站免费观看| www.xxxx精品| 午夜在线播放视频欧美| 色偷偷免费视频| 久久亚洲精品小早川怜子66| 香蕉久久夜色精品国产| 在线观看视频免费| 久久国产精品久久久久| 日本午夜精品一区二区三区电影| 欧美h版电影| 日韩在线视频观看正片免费网站| 免费久久99精品国产自在现线| 免费成人高清| 免费av在线一区| 国产精品影视在线| 浪潮av一区| 91老司机在线| 亚洲精品成a人| 国产一区二区久久久久| 欧美日韩一级在线| 日韩三级在线观看| 天天射天天综合网| 国产黄色免费网| 欧美人在线视频| 国产91丝袜在线播放九色| 黄色羞羞视频在线观看| 精品国产一二| 久久夜夜久久| 视频一区二区视频| 日韩美女天天操| 欧美精品午夜| 九色在线免费| 91久久国产精品91久久性色| 亚洲一区二区三区在线播放| 精品成人自拍视频| 欧美三级午夜理伦三级富婆| 欧美成人性生活| 91视频一区二区三区| 成人在线分类| 国产情侣av自拍| 久久久久久久久国产精品| 国产日产欧美一区| 老汉色老汉首页av亚洲| 成人免费淫片在线费观看| 国产91精品久| 一区二区三区日本| 精品国产乱码久久久| 超碰在线公开超碰在线| 成人精品一区二区三区| 欧美性高潮在线| 99国内精品| 呦呦在线视频| 日本一级淫片演员| 色999日韩欧美国产| 91日韩在线专区| 视频一区在线| 2020色愉拍亚洲偷自拍| 国产精品免费视频久久久| 色综合久久综合网97色综合| 激情欧美一区| gogo高清午夜人体在线| 成人午夜视频免费观看| 久久久97精品| 国产精品另类一区| 不卡一区综合视频| 欧美日本韩国一区二区三区视频| 久久亚洲美女| 日本最新不卡在线| 永久免费av片在线观看全网站| 国产精选在线观看91| 91麻豆精品国产91久久久资源速度| 激情久久久久| gogo在线观看| 天天综合五月天| 日韩小视频在线| 欧美激情资源网| 视频一区在线观看| 97在线观看免费观看高清 | 青青草在线免费观看| 99久久综合狠狠综合久久止 | 亚洲a∨精品一区二区三区导航| 水蜜桃亚洲精品| 国产视频一区三区| 日本高清中文字幕在线| 久久久无码中文字幕久...| 欧美极品在线视频| 欧美性猛交xxxxx免费看| 美女91精品| 不卡的国产精品| 中国在线观看免费国语版电影| 国产伦精品一区二区三区免费视频| 欧美白人最猛性xxxxx69交| 91欧美一区二区| 久久亚洲专区| 美女高潮在线观看| 国产黄色免费电影| 日本一区高清在线视频| 欧美大奶子在线| 欧美色男人天堂| 91丨九色丨黑人外教| 91精品亚洲| 电影在线观看一区二区| 网址你懂得在线观看| 日韩国产精品毛片| 国产精品成人久久久久| 亚洲福利小视频| 亚洲精品美腿丝袜| 紧缚奴在线一区二区三区| 久久综合五月婷婷| 久久www人成免费看片中文| www浪潮av99com| 五月天久久综合网| 国产精品高潮粉嫩av| 亚洲欧美日韩精品久久奇米色影视| 国产精品美女一区二区三区| 国产精品日韩| 色狠狠久久av综合| 鲁鲁在线中文| 亚洲免费av一区二区| 少妇人妻无码专区视频| 国产欧美日韩一区二区三区| 欧美国产日韩中文字幕在线| 91麻豆精品国产91久久久| 国产精品久久久久精k8| 久久99日本精品| 欧美a级片网站| 高清日韩中文字幕| 毛片在线导航| 邻家有女韩剧在线观看国语| 日本久久久久久久久久久久| 亚洲激情欧美激情| 狠狠久久亚洲欧美| 国产精品99免费看| www.激情网| 国产精品大片| 欧美影院精品| 麻豆视频在线观看免费网站| 99福利在线观看| 日本不卡高清视频一区| 国产激情999| 久久韩国免费视频| 日韩午夜激情av| 艳妇臀荡乳欲伦亚洲一区| 国产成人综合在线观看| 在线日韩电影| 欧美一区二区三区激情视频| 欧美另类激情| 超级碰碰不卡在线视频| 久久米奇亚洲| 欧美aaa大片| 天堂一区在线观看| 国产手机免费视频|