中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

@DateTimeFormat的作用有哪些

發布時間:2021-10-18 10:47:25 來源:億速云 閱讀:978 作者:iii 欄目:web開發

本篇內容主要講解“@DateTimeFormat的作用有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“@DateTimeFormat的作用有哪些”吧!

本文提綱

@DateTimeFormat的作用有哪些

版本約定

  • 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的請求實體形如這樣:

@Data public class Person{    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")  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去完成的。那么這個流程是怎樣的呢?

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

@DateTimeFormat的作用有哪些

該流程可釋義為:通過格式化器注冊中心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接口的繼承體系三個實現類剛好與之對應:

@DateTimeFormat的作用有哪些

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就使用它倆來進行一系列注冊動作,因此可理解為他是更上層的封裝形式。

源碼分析

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

@DateTimeFormat的作用有哪些

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

@DateTimeFormat的作用有哪些

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

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

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

@DateTimeFormat的作用有哪些

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

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

@DateTimeFormat的作用有哪些

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

@DateTimeFormat的作用有哪些

①:這個  步驟類似于上文講述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的作用有哪些

@DateTimeFormat的作用有哪些

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

代碼示例

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

API使用方式

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

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

運行程序,輸出:

當前時間:2021-03-07T21:19:39.752 LocalDateTime轉為LocalDate:2021-03-07 LocalDateTime轉為LocalTime:21:19:39.752 當前時間戳:1615123179763 時間戳轉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就暫且略過嘍。

到此,相信大家對“@DateTimeFormat的作用有哪些”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

勃利县| 河曲县| 沙河市| 阿克苏市| 吉木乃县| 宁阳县| 邻水| 呼玛县| 微博| 临江市| 和平县| 深泽县| 霍山县| 紫阳县| 柏乡县| 泰和县| 通城县| 凤台县| 通榆县| 宾阳县| 深圳市| 五原县| 门头沟区| 怀安县| 会泽县| 册亨县| 临湘市| 泗水县| 静乐县| 百色市| 阿拉善左旗| 边坝县| 诸城市| 华亭县| 大同市| 三亚市| 平顺县| 五莲县| 宜阳县| 高安市| 珠海市|