偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

原來是這么玩的,@DateTimeFormat和@NumberFormat

開發(fā) 前端
在本系列中間,用幾篇文章徹徹底底的把JDK日期時(shí)間系列深入講解了一遍,此系列有可能是把JDK日期時(shí)間講得最好最全的,強(qiáng)烈建議你前往看它一看。

[[381166]]

 前言你好,我是A哥(YourBatman)。

在本系列中間,用幾篇文章徹徹底底的把JDK日期時(shí)間系列深入講解了一遍,此系列有可能是把JDK日期時(shí)間講得最好最全的,強(qiáng)烈建議你前往看它一看。

本系列的上篇文章 對(duì)格式化器Formatter進(jìn)行了剖析,Spring對(duì)日期時(shí)間、數(shù)字、錢幣等常用類型都內(nèi)置了相應(yīng)的格式化器實(shí)現(xiàn),開發(fā)者可拿來就用。但是,這在使用上依舊有一定門檻:開發(fā)者需要知道對(duì)應(yīng)API的細(xì)節(jié)。比如若需要對(duì)Date、LocalDate進(jìn)行格式化操作的話,就需要分別了解處理他倆的正確API,這在使用上是存在一定“難度”的。

另外,在面向元數(shù)編程大行其道的今天,硬編碼往往是被吐槽甚至被拒絕的,聲明式才會(huì)受到歡迎。Spring自3.0起大量的引入了“更為時(shí)尚”的元數(shù)據(jù)編程支持,從而穩(wěn)固了其“江湖地位”。@DateTimeFormat和@NumberFormat兩個(gè)注解是Spring在類型轉(zhuǎn)換/格式化方面的元編程代表,本文一起來探討下。

本文提綱


版本約定

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

正文

據(jù)我了解,@DateTimeFormat是開發(fā)中出鏡率很高的一個(gè)注解,其作用見名之意很好理解:對(duì)日期時(shí)間格式化。但使用起來常常迷糊。比如:使用它還是com.fasterxml.jackson.annotation.JsonFormat注解呢?能否使用在Long類型上?能否使用在JSR 310日期時(shí)間類型上?

有這些問號(hào)其實(shí)蠻正常,但切忌囫圇吞棗,也不建議強(qiáng)記這些問題的答案,而是通過規(guī)律在原理層面去理解,不僅能更牢靠而且更輕松,這或許是學(xué)習(xí)編程最重要的必備技巧之一。

@DateTimeFormat和@NumberFormat

在類型轉(zhuǎn)換/格式化方面注解,Spring提供了兩個(gè):

  • @DateTimeFormat:將Field/方法參數(shù)格式化為日期/時(shí)間類型
  • @NumberFormat:將Field/方法參數(shù)格式化為數(shù)字類型

值得關(guān)注的是:這里所說的日期/時(shí)間類型有很多,如最古老的java.util.Date類型、JSR 310的LocalDate類型甚至?xí)r間戳Long類型都可稱作日期時(shí)間類型;同樣的,數(shù)字類型也是個(gè)泛概念,如Number類型、百分?jǐn)?shù)類型、錢幣類型也都屬此范疇。

  • ❝話外音:這兩個(gè)注解能夠作用的類型很廣很廣❞分別看看這兩個(gè)注解定義,不可謂不簡單:
  1. @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE}) 
  2. public @interface DateTimeFormat { 
  3.  
  4.  String style() default "SS"
  5.  ISO iso() default ISO.NONE; 
  6.  String pattern() default ""
  7.   

  1. @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE}) 
  2. public @interface NumberFormat { 
  3.  
  4.  Style style() default Style.DEFAULT
  5.  String pattern() default ""

哥倆有兩個(gè)共通的點(diǎn):

  1. 都支持標(biāo)注在方法Method、字段Field、方法參數(shù)Parameter上
  2. 均支持靈活性極大的pattern屬性,此屬性支持Spring占位符書寫形式
  3. 對(duì)于pattern屬性你既可以用字面量寫死,也可以用形如${xxx.xxx.pattern}占位符形式這種更富彈性的寫法

咱們?cè)谑褂眠@兩個(gè)注解時(shí),最最最常用的是pattern這個(gè)屬性沒有之一,理由是它非常的靈活強(qiáng)大,能滿足各式各樣格式化需求。從這一點(diǎn)也側(cè)面看出,咱們?cè)谌掌?時(shí)間、數(shù)字方面的格式化,并不遵循國際標(biāo)準(zhǔn)(如ISO),而普遍使用的“中國標(biāo)準(zhǔn)”。

由于這兩個(gè)注解幾乎所有同學(xué)都在Spring MVC上使用過,那么本文就先原理再示例。在知曉了其背后原理后再去使用,別有一番體會(huì)。

AnnotationFormatterFactory

說到格式化注解,就不得不提該工廠類,它是實(shí)現(xiàn)原理的核心所在。

字面含義:注解格式化工廠。用大白話解釋:該工廠用于為標(biāo)注在Field字段上的注解創(chuàng)建對(duì)應(yīng)的格式化器進(jìn)而對(duì)值進(jìn)行格式化處理。從這句話里可提取出幾個(gè)關(guān)鍵因素:


  1. 注解
  2. 字段Field
  3. 這里Field并不只表示java.lang.reflect.Field,像方法返回類型、參數(shù)類型都屬此范疇,下面使用示例會(huì)有所體會(huì)
  4. 格式化器Formatter

接口定義:

 

  1. public interface AnnotationFormatterFactory<A extends Annotation> { 
  2.   
  3.  Set<Class<?>> getFieldTypes(); 
  4.   
  5.  Printer<?> getPrinter(A annotation, Class<?> fieldType); 
  6.  Parser<?> getParser(A annotation, Class<?> fieldType); 

 

接口共定義了三個(gè)方法:

此接口Spring內(nèi)建有如下實(shí)現(xiàn):

 


雖然實(shí)現(xiàn)有5個(gè)之多,但其實(shí)只有兩類,也就是說面向使用者而言只需做兩種區(qū)分即可,分別對(duì)應(yīng)上面所講的兩個(gè)注解。這里A哥把它繪制成圖所示:


紅色框框部分(以及其處理的Field類型)是咱們需要關(guān)注的重點(diǎn),其它的留個(gè)印象即可。

關(guān)于日期時(shí)間類型,我在多篇文章里不再推薦使用java.util.Date類型(更不建議使用Long類型嘍),而是使用Java 8提供的JSR 310日期時(shí)間類型100%代替(包括代替joda-time)。但是呢,在當(dāng)下階段java.util.Date類型依舊不可忽略(龐大存量市場(chǎng),龐大“存量”程序員的存在),因此決定把DateTimeFormatAnnotationFormatterFactory依舊還是抬到桌面上來敘述敘述,但求做得更全面些。

❝關(guān)于JDK的日期時(shí)間我寫了一個(gè)非常全的系列,詳情點(diǎn)擊這里直達(dá):日期時(shí)間系列,建議先行了解❞

DateTimeFormatAnnotationFormatterFactory

對(duì)應(yīng)的格式化器API是:org.springframework.format.datetime.DateFormatter。

@since 3.2版本就已存在,專用于對(duì)java.util.Date體系 + @DateTimeFormat的支持:創(chuàng)建出相應(yīng)的Printer/Parser。下面解讀其源碼:


①:該工廠類專為@DateTimeFormat注解服務(wù)②:借助Spring的StringValueResolver對(duì)占位符(若存在)做替換


這部分源碼告訴我們:@DateTimeFormat注解標(biāo)注在如圖的這些類型上時(shí)才有效,才能被該工廠處理從而完成相應(yīng)創(chuàng)建工作。

  • ❝注意:除了Date和Calendar類型外,還有Long類型哦,請(qǐng)不要忽略了❞

核心處理邏輯也比較好理解:不管是Printer還是Parser最終均委托給DateFormatter去完成,而此API在本系列前面文章已做了詳細(xì)講解。電梯直達(dá)

值得注意的是:DateFormatter 只能 處理Date類型。換句話講getFormatter()方法的第二個(gè)參數(shù)fieldType在此方法里并沒有被使用,也就是說缺省情況下@DateTimeFormat注解并不能正常處理其標(biāo)注在Calendar、Long類型的Case。若要得到支持,需自行重寫其getPrinter/getParser等方法。

使用示例

由于@DateTimeFormat可以標(biāo)注在成員屬性、方法參數(shù)、方法(返回值)上,且當(dāng)其標(biāo)注在Date、Calendar、Long等類型上時(shí)方可交給本工廠類來處理生成相應(yīng)的處理類,本文共用三個(gè)案例case進(jìn)行覆蓋。

case1:成員屬性 + Date類型。輸入 + 輸出

準(zhǔn)備一個(gè)標(biāo)注有@DateTimeFormat注解的Field屬性,為Date類型

  1. @Data 
  2. @AllArgsConstructor 
  3. class Person { 
  4.  
  5.     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss"
  6.     private Date birthday; 
  7.      

書寫測(cè)試程序:

  1. @Test 
  2. public void test1() throws Exception { 
  3.     AnnotationFormatterFactory annotationFormatterFactory = new DateTimeFormatAnnotationFormatterFactory(); 
  4.  
  5.     // 找到該field 
  6.     Field field = Person.class.getDeclaredField("birthday"); 
  7.     DateTimeFormat annotation = field.getAnnotation(DateTimeFormat.class); 
  8.     Class<?> type = field.getType(); 
  9.  
  10.     // 輸出: 
  11.     System.out.println("輸出:Date -> String===================="); 
  12.     Printer printer = annotationFormatterFactory.getPrinter(annotation, type); 
  13.     Person person = new Person(new Date()); 
  14.     System.out.println(printer.print(person.getBirthday(), Locale.US)); 
  15.  
  16.     // 輸入: 
  17.     System.out.println("輸入:String -> Date===================="); 
  18.     Parser parser = annotationFormatterFactory.getParser(annotation, type); 
  19.     Object output = parser.parse("2021-02-06 19:00:00", Locale.US); 
  20.     person = new Person((Dateoutput); 
  21.     System.out.println(person); 

運(yùn)行程序,輸出:

  1. 輸出:Date -> String==================== 
  2. 2021-02-06 22:21:56 
  3. 輸入:String -> Date==================== 
  4. Person(birthday=Sat Feb 06 19:00:00 CST 2021) 

完美。

case2:方法參數(shù) + Calendar。輸入

  1. @Test 
  2. public void test2() throws NoSuchMethodException, ParseException { 
  3.     AnnotationFormatterFactory annotationFormatterFactory = new DateTimeFormatAnnotationFormatterFactory(); 
  4.  
  5.     // 拿到方法入?yún)?nbsp;
  6.     Method method = this.getClass().getDeclaredMethod("method", Calendar.class); 
  7.     Parameter parameter = method.getParameters()[0]; 
  8.     DateTimeFormat annotation = parameter.getAnnotation(DateTimeFormat.class); 
  9.     Class<?> type = parameter.getType(); 
  10.  
  11.     // 輸入: 
  12.     System.out.println("輸入:String -> Calendar===================="); 
  13.     Parser parser = annotationFormatterFactory.getParser(annotation, type); 
  14.     Object output = parser.parse("2021-02-06 19:00:00", Locale.US); 
  15.  // 給該方法傳入“轉(zhuǎn)換好的”參數(shù),表示輸入 
  16.     method((Calendar) output); 
  17.  
  18. public void method(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Calendar calendar) { 
  19.     System.out.println(calendar); 
  20.     System.out.println(calendar.getTime()); 

運(yùn)行程序,報(bào)錯(cuò):

  1. 輸入:String -> Calendar==================== 
  2.  
  3. java.lang.ClassCastException: java.util.Date cannot be cast to java.util.Calendar 
  4.  ... 

通過文上的闡述,這個(gè)錯(cuò)誤是在意料之中的。下面通過自定義一個(gè)增強(qiáng)實(shí)現(xiàn)來達(dá)到目的:

  1. class MyDateTimeFormatAnnotationFormatterFactory extends DateTimeFormatAnnotationFormatterFactory { 
  2.  
  3.     @Override 
  4.     public Parser<?> getParser(DateTimeFormat annotation, Class<?> fieldType) { 
  5.         if (fieldType.isAssignableFrom(Calendar.class)) { 
  6.             return new Parser<Calendar>() { 
  7.                 @Override 
  8.                 public Calendar parse(String text, Locale locale) throws ParseException { 
  9.                     // 先翻譯為Date 
  10.                     Formatter<Date> formatter = getFormatter(annotation, fieldType); 
  11.                     Date date = formatter.parse(text, locale); 
  12.  
  13.                     // 再翻譯為Calendar 
  14.                     Calendar calendar = Calendar.getInstance(TimeZone.getDefault()); 
  15.                     calendar.setTime(date); 
  16.                     return calendar; 
  17.                 } 
  18.  
  19.             }; 
  20.         } 
  21.         return super.getParser(annotation, fieldType); 
  22.     } 

將測(cè)試程序中的工廠類換為自定義的增強(qiáng)實(shí)現(xiàn):

  1. AnnotationFormatterFactory annotationFormatterFactory = new MyDateTimeFormatAnnotationFormatterFactory(); 

再次運(yùn)行程序,輸出:

  1. 輸入:String -> Calendar==================== 
  2. java.util.GregorianCalendar[time=1612609200000, ... 
  3. Sat Feb 06 19:00:00 CST 2021 

完美。

case3:方法返回值 + Long。輸出 建議自行實(shí)現(xiàn),略

❝時(shí)間戳被經(jīng)常用來做時(shí)間傳遞,那么傳輸中的Long類型如何被自動(dòng)封裝 為Date類型(輸入)呢?動(dòng)動(dòng)手鞏固下吧~❞

Jsr310DateTimeFormatAnnotationFormatterFactory

對(duì)應(yīng)的格式化器API是:Spring的org.springframework.format.datetime.standard.DateTimeFormatterFactory以及JDK的java.time.format.DateTimeFormatter。

@since 4.0。JSR 310時(shí)間是伴隨著Java 8的出現(xiàn)而出現(xiàn)的,Spring自4.0 開始支持 Java 8,自5.0至少基于 Java 8,因此此類since 4.0就不好奇嘍。

從類名能讀出它用于處理JSR 310日期時(shí)間。下面解讀一下它的部分源碼,透過現(xiàn)象看其本質(zhì):


①:該工廠專為@DateTimeFormat注解服務(wù)②:借助Spring的StringValueResolver對(duì)占位符(若存在)做替換


@DateTimeFormat注解標(biāo)注在這些類型上時(shí),就會(huì)交給此工廠類來負(fù)責(zé)其格式化器的創(chuàng)建工作。


①:得到一個(gè)JDK的java.time.format.DateTimeFormatter,由它負(fù)責(zé)將 日期/時(shí)間 -> String類型的格式化。由于JSR 310日期/時(shí)間的格式化JDK自己實(shí)現(xiàn)得已經(jīng)非常完善,Spring只需要將它整合進(jìn)來就成。但是呢,DateTimeFormatter它是線程安全的無法同時(shí)設(shè)置iso、pattern等個(gè)性化參數(shù),于是Spring就造了DateTimeFormatterFactory工廠類,用它用來抹平使用上的差異,達(dá)到(和java.util.Date)一致的使用體驗(yàn)。當(dāng)然嘍,這個(gè)知識(shí)點(diǎn)屬于上篇文章的內(nèi)容,欲回顧詳情可點(diǎn)擊這里電梯直達(dá)。

回到本處,getFormatter()方法得到格式化器實(shí)例是關(guān)鍵,具體代碼如下:


使用Spring的工廠類DateTimeFormatterFactory構(gòu)建出一個(gè)JSR 310的日期時(shí)間格式化器DateTimeFormatter來處理。有了上篇文章的鋪墊,相信這個(gè)邏輯無需再多費(fèi)一言解釋了哈。

②:這一大塊是對(duì)LocalXXX(含LocalDate/Time)標(biāo)準(zhǔn)格式化器做的特殊處理:將ISO_XXX格式化模版適配為更加適用的ISO_Local_XXX格式化模版,更加精確。③:TemporalAccessorPrinter它就是個(gè)Printer,實(shí)際的格式化器依舊是DateTimeFormatter,只不過它的作用是兼容到了上下文級(jí)別(和當(dāng)前線程綁定)的格式化器,從而有能力用到上下文級(jí)別的格式化參數(shù),具有更好的可定制性,如下圖所示(源碼來自TemporalAccessorPrinter):


強(qiáng)調(diào):別看這個(gè)特性很小,但非常有用,有四兩撥千斤的功效。因?yàn)樗臀覀儤I(yè)務(wù)系統(tǒng)息息相關(guān),掌握這個(gè)點(diǎn)可輕松實(shí)現(xiàn)事半功倍的效果,別人加班你加薪。關(guān)于此知識(shí)點(diǎn)的應(yīng)用,A哥覺得值得專門寫篇文章來描述,敬請(qǐng)期待下文。

接下來再看看getParser()部分的實(shí)現(xiàn):


①:TemporalAccessorParser是個(gè)Parser,同樣的也是利用了具有Context上下文特性的DateTimeFormatter來完成String -> TemporalAccessor工作的。熟悉這個(gè)方向的轉(zhuǎn)換邏輯的同學(xué)就知道,因?yàn)槎际庆o態(tài)方法調(diào)用,所以必須用“枚舉”的方式一一處理,截圖如下(源碼來自TemporalAccessorParser):


到此,整個(gè)Jsr310DateTimeFormatAnnotationFormatterFactory的源碼就分析完了,總結(jié)一下:

  1. 此工廠專為標(biāo)注在JSR 310日期/時(shí)間類型的@DateTimeFormat注解服務(wù)
  2. 底層格式化器雙向均使用的是和上下文相關(guān)的的DateTimeFormatter,具有高度可定制化的特性。此特性雖小卻有四兩撥千斤的效果,后面會(huì)專文給出使用場(chǎng)景
  3. @DateTimeFormat注解的style和pattern屬性都是支持占位符形式書寫的,更富彈性

使用示例

它不像DateTimeFormatAnnotationFormatterFactory只提供了部分支持,而是提供了全部功能,感受一下。

case1:成員屬性 + LocalDate類型。輸入 + 輸出

  1. @Data 
  2. @AllArgsConstructor 
  3. class Father { 
  4.     @DateTimeFormat(iso = DateTimeFormat.ISO.DATE
  5.     private LocalDate birthday; 

測(cè)試代碼:

  1. @Test 
  2. public void test4() throws NoSuchFieldException, ParseException { 
  3.     AnnotationFormatterFactory annotationFormatterFactory = new Jsr310DateTimeFormatAnnotationFormatterFactory(); 
  4.  
  5.     // 找到該field 
  6.     Field field = Father.class.getDeclaredField("birthday"); 
  7.     DateTimeFormat annotation = field.getAnnotation(DateTimeFormat.class); 
  8.     Class<?> type = field.getType(); 
  9.  
  10.     // 輸出: 
  11.     System.out.println("輸出:LocalDate -> String===================="); 
  12.     Printer printer = annotationFormatterFactory.getPrinter(annotation, type); 
  13.     Father father = new Father(LocalDate.now()); 
  14.     System.out.println(printer.print(father.getBirthday(), Locale.US)); 
  15.  
  16.     // 輸入: 
  17.     System.out.println("輸入:String -> Date===================="); 
  18.     Parser parser = annotationFormatterFactory.getParser(annotation, type); 
  19.     Object output = parser.parse("2021-02-07", Locale.US); 
  20.     father = new Father((LocalDate) output); 
  21.     System.out.println(father); 

運(yùn)行程序,輸出:

  1. 輸出:LocalDate -> String==================== 
  2. 2021-02-07 
  3. 輸入:String -> Date==================== 
  4. Father(birthday=2021-02-07) 

完美。

case2:方法參數(shù) + LocalDate類型。輸入

  1. @Test 
  2. public void test5() throws ParseException, NoSuchMethodException { 
  3.     AnnotationFormatterFactory annotationFormatterFactory = new Jsr310DateTimeFormatAnnotationFormatterFactory(); 
  4.  
  5.     // 拿到方法入?yún)?nbsp;
  6.     Method method = this.getClass().getDeclaredMethod("methodJSR310", LocalDate.class); 
  7.     Parameter parameter = method.getParameters()[0]; 
  8.     DateTimeFormat annotation = parameter.getAnnotation(DateTimeFormat.class); 
  9.     Class<?> type = parameter.getType(); 
  10.  
  11.  
  12.     // 輸入: 
  13.     System.out.println("輸入:String -> LocalDate===================="); 
  14.     Parser parser = annotationFormatterFactory.getParser(annotation, type); 
  15.     Object output = parser.parse("2021-02-06", Locale.US); 
  16.     // 給該方法傳入“轉(zhuǎn)換好的”參數(shù),表示輸入 
  17.     methodJSR310((LocalDate) output); 
  18.  
  19. public void methodJSR310(@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate localDate) { 
  20.     System.out.println(localDate); 

運(yùn)行程序,輸出:

  1. 輸入:String -> LocalDate==================== 
  2. 2021-02-06 

case3:方法返回值 + LocalDate類型。輸入

  1. @Test 
  2. public void test6() throws NoSuchMethodException { 
  3.     AnnotationFormatterFactory annotationFormatterFactory = new Jsr310DateTimeFormatAnnotationFormatterFactory(); 
  4.  
  5.     // 拿到方法返回值類型 
  6.     Method method = this.getClass().getDeclaredMethod("method1JSR310"); 
  7.     DateTimeFormat annotation = method.getAnnotation(DateTimeFormat.class); 
  8.     Class<?> type = method.getReturnType(); 
  9.  
  10.  
  11.     // 輸出: 
  12.     System.out.println("輸出:LocalDate -> 時(shí)間格式的String===================="); 
  13.     Printer printer = annotationFormatterFactory.getPrinter(annotation, type); 
  14.  
  15.     LocalDate returnValue = method1JSR310(); 
  16.     System.out.println(printer.print(returnValue, Locale.US)); 
  17.  
  18. @DateTimeFormat(iso = DateTimeFormat.ISO.DATE
  19. public LocalDate method1JSR310() { 
  20.     return LocalDate.now(); 

完美。

NumberFormatAnnotationFormatterFactory

對(duì)應(yīng)的格式化器API是:org.springframework.format.number.AbstractNumberFormatter的三個(gè)子類


@since 3.0。直奔主題,源碼嘍幾眼:


有了上面的“經(jīng)驗(yàn)”,此part不用解釋了吧。

①:@NumberFormat可以標(biāo)注在Number的子類型上,并生成對(duì)應(yīng)的格式化器處理。

底層實(shí)現(xiàn):實(shí)際的格式化動(dòng)作Printer/Parser如下圖所示,全權(quán)委托給前面已介紹過的格式化器來完成,就不做過多介紹啦。有知識(shí)盲區(qū)的可乘坐電梯前往本系列前面文章查看~


使用示例

@NumberFormat支持標(biāo)注在多種類型上,如小數(shù)、百分?jǐn)?shù)、錢幣等等,由于文上已做好了鋪墊,所以這里只給出個(gè)簡單使用案例即可,舉一反三。

  1. @Test 
  2. public void test2() throws NoSuchMethodException, ParseException { 
  3.     AnnotationFormatterFactory annotationFormatterFactory = new NumberFormatAnnotationFormatterFactory(); 
  4.  
  5.     // 獲取待處理的目標(biāo)類型(方法參數(shù)、字段屬性、方法返回值等等) 
  6.     Method method1 = this.getClass().getMethod("method2"double.class); 
  7.     Parameter parameter = method1.getParameters()[0]; 
  8.     NumberFormat annotation = parameter.getAnnotation(NumberFormat.class); 
  9.     Class<?> fieldType = parameter.getType(); 
  10.  
  11.     // 1、根據(jù)注解和field類型生成一個(gè)解析器,完成String -> LocalDateTime 
  12.     Parser parser = annotationFormatterFactory.getParser(annotation, fieldType); 
  13.     // 2、模擬轉(zhuǎn)換動(dòng)作,并輸出結(jié)果 
  14.     Object result = parser.parse("11%", Locale.US); 
  15.     System.out.println(result.getClass()); 
  16.     System.out.println(result); 
  17.  
  18.  
  19. public void method2(@NumberFormat(style = NumberFormat.Style.PERCENT) double d) { 

運(yùn)行程序,輸出:

  1. class java.math.BigDecimal 
  2. 0.11 

完美的將11%這種百分?jǐn)?shù)數(shù)字轉(zhuǎn)換為BigDecimal了。至于為何是BigDecimal類型而不是double,那都在PercentStyleFormatter里了。

總結(jié)

這兩個(gè)注解更像是高層抽象:模糊掉開發(fā)者的使用成本,能夠達(dá)到的效果是:

  • @DateTimeFormat:日期時(shí)間類型的格式化,找我就夠了
  • @NumberFormat:數(shù)字類型的格式化,找我就夠了

這兩個(gè)由于過于常用Spring內(nèi)置提供了,若你有特殊需求,Spring也提供了鉤子,可以自定義注解 + 擴(kuò)展AnnotationFormatterFactory接口來實(shí)現(xiàn)。注解 + 工廠類組合在一起像是一個(gè)分發(fā)器,模糊掉類型上的差異,讓使用者有統(tǒng)一感受。

有了本系列前面知識(shí)的鋪墊,本文一路讀下來毫不費(fèi)力,底層基礎(chǔ)決定上層建筑。這些都是在Spring MVC場(chǎng)景下使用的這些注解的底層原理,本系列對(duì)其抽絲剝繭后,那些使用上的問題自當(dāng)無師自通,迎刃而解。

當(dāng)然嘍,在實(shí)際應(yīng)用中不可能像本例一樣這樣編碼實(shí)現(xiàn),開發(fā)者應(yīng)該只需知道注解使用在哪即可。既然要方便,那就需要整合。下篇文章將繼續(xù)了解Spring是如何將此功能整合進(jìn)注冊(cè)中心,大大簡化使用方式的。

本文思考題

本文所屬專欄:Spring類型轉(zhuǎn)換,后臺(tái)回復(fù)專欄名即可獲取全部內(nèi)容,已被https://www.yourbatman.cn收錄。

看完了不一定懂,看懂了不一定會(huì)。來,文末3個(gè)思考題幫你復(fù)盤:

傳入Long類型時(shí)間戳,如何能支持自動(dòng)封裝到Date類型?

@DateTimeFormat一般用于Controller層?那么它能用在Service層嗎?如何做?

為什么并不建議在Service/Dao層使用@DateTimeFormat等注解呢?

 

責(zé)任編輯:姜華 來源: BAT的烏托邦
相關(guān)推薦

2014-03-31 14:59:08

大數(shù)據(jù)

2020-02-23 15:55:00

疫情AI人工智能

2022-01-14 14:19:38

ReactTS前端

2022-12-06 17:30:04

2025-04-03 10:39:56

2021-07-29 16:56:59

微信騰訊注冊(cè)

2022-08-15 08:01:00

三色標(biāo)記JVM算法

2020-06-30 08:12:32

VMwareKVMDocker

2025-07-03 07:05:00

JavaScriptPromise代碼

2024-10-11 11:59:03

2017-06-06 15:13:07

2025-08-18 07:35:40

2022-12-14 07:32:40

InnoDBMySQL引擎

2018-10-28 17:54:00

分布式事務(wù)數(shù)據(jù)

2023-04-09 23:25:30

Java注解元注解

2022-01-04 08:00:48

前端技術(shù)Esbuild

2017-11-27 12:24:02

命令行代碼指令

2023-09-11 13:27:00

數(shù)據(jù)訓(xùn)練

2022-05-05 08:55:12

工業(yè)物聯(lián)網(wǎng)IIoT

2024-02-06 09:30:25

Figma矩形矩形物理屬性
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)