一起來學SpringBoot | 第二十八篇:JDK8 日期格式化
SpringBoot
是為了簡化Spring
應用的建立、執行、除錯、部署等一系列問題而誕生的產物,
自動裝配的特性讓我們可以更好的關注業務本身而不是外部的XML配置,我們只需遵循規範,引入相關的依賴就可以輕易的搭建出一個 WEB 工程
為什麼要用新的日期型別
在JDK8
中,一個新的重要特性就是引入了全新的時間和日期API,它被收錄在java.time
包中。藉助新的時間和日期API可以以更簡潔的方法處理時間和日期。
在JDK8
之前,所有關於時間和日期的API存在以下幾個缺陷,也正是這些缺陷,出現了很多第三方的日期處理框架,例如Joda-Time
,date4j
等開源專案。但是,Java 需要一套標準的用於處理時間和日期的框架,於是乎在JDK8
中引入了新的日期API。遵循JSR-310
規範的實現,而Joda-Time
框架的作者正是JSR-310
的規範的倡導者,所以用過Joda-Time
的對新日期API也不會陌生。
缺陷
-
之前的
java.util.Date
和java.util.Calendar
類易用性差,不支援時區,且非執行緒安全的; -
日期格式化類
java.text.DateFormat
是一個抽象類,使用時需要先例項化一個SimpleDateFormat
物件來處理日期格式化,同時DateFormat
也不是執行緒安全的,這意味著如果你在多執行緒程式中呼叫同一個DateFormat
物件,會得到意想不到的結果。 - 對日期的計算方式繁瑣,而且容易出錯,因為月份是從0開始的,從 Calendar 中獲取的月份需要加一才能表示當前月份。
為什麼要格式化
說了這麼多,和Spring Boot
有什麼關係呢?不要急,待我娓娓道來!
- 格式化前:{“payTime”:”2018-09-30T09:51:56.77”}
- 格式化後:{“payTime”:”2018-09-30 09:51:56”}
都知道我們國人習慣yyyy-MM-dd HH:mm:ss
這種格式的日期,但奈何框架是歪國大佬們寫的,他們的日期格式與我們相差甚遠,好在Spring Boot
提供了spring.jackson.date-format
,奈何它只能格式化java.util.Date
。那麼解決辦法是什麼呢?
匯入依賴
首先一個WEB
專案,必不可少的依賴就是spring-boot-starter-web
了,一路學習下來的小夥伴們肯定都熟記於心了
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
配置檔案
由於spring.jackson.date-format
對新的日期型別不在有效果,所以這裡0配置檔案了
方案一(強烈推薦)
只需要定義一個配置類,在裡面定義兩個Bean
即可完成全域性日期格式化處理,這種方式也是本人現在使用的,同時還兼顧了Date
和LocalDateTime
並存
package com.battcn.config; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; /** * @author Levin * @since 2018/9/30 0030 */ @Configuration public class LocalDateTimeSerializerConfig { @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}") private String pattern; @Bean public LocalDateTimeSerializer localDateTimeDeserializer() { return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern)); } @Bean public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() { return builder -> builder.serializerByType(LocalDateTime.class, localDateTimeDeserializer()); } }
方案二(強烈推薦)
有時候,我們對日期格式要做特殊的處理,全域性的格式化方式無法滿足我們需求是,使用該方案是非常好的選擇,通過@JsonFormat
註解我們可以更為精準的為日期欄位格式化,它也是優先順序最高的
public class Order { @JsonFormat(pattern = "yyyy-MM-dd") private LocalDateTime payTime; // 省略 GET SET ... }
方案三(可選)
其實和第一種類似,只不過第一種的寫法更加優雅簡潔,如果有多種型別需要做統一格式化處理,這種方案也不是不可以考慮
package com.battcn.config; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import java.io.IOException; import java.time.LocalDate; import java.time.LocalDateTime; import static java.time.format.DateTimeFormatter.ofPattern; /** * @author Levin * @since 2018/9/30 0030 */ @Configuration public class LocalDateTimeSerializerConfig1 { @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}") private String pattern; @Bean @Primary public ObjectMapper serializingObjectMapper() { ObjectMapper objectMapper = new ObjectMapper(); JavaTimeModule javaTimeModule = new JavaTimeModule(); javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer()); javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer()); objectMapper.registerModule(javaTimeModule); return objectMapper; } public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> { @Override public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeString(value.format(ofPattern(pattern))); } } public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> { @Override public LocalDateTime deserialize(JsonParser p, DeserializationContext deserializationContext) throws IOException { return LocalDateTime.parse(p.getValueAsString(), ofPattern(pattern)); } } }
控制層
定義了一個很簡單的響應
package com.battcn.controller; import com.battcn.pojo.Order; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; /** * @author Levin * @since 2018/8/2 0002 */ @RestController @RequestMapping("/orders") public class OrderController { @GetMapping public Order query() { Order order = new Order(); order.setPayTime(LocalDateTime.now()); return order; } }
主函式
package com.battcn; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @author Levin */ @SpringBootApplication public class Chapter28Application { public static void main(String[] args) { SpringApplication.run(Chapter28Application.class, args); } }
測試
完成準備事項後,啟動Chapter28Application
,訪問ofollow,noindex">http://localhost:8080/orders
即可看到格式化後的日期啦…
總結
目前很多大佬都寫過關於
SpringBoot
的教程了,如有雷同,請多多包涵,本教程基於最新的spring-boot-starter-parent:2.0.3.RELEASE
編寫,包括新版本的特性都會一起介紹…