在SpringBoot中使用Java8新時間類型

Java 8日期/時間( Date/Time)API是開發(fā)人員最受追捧的變化之一,其簡潔、清晰以及線程安全等特性使得其推出后就備受Java開發(fā)者歡迎。

Java 8日期/時間API是JSR-310的實現(xiàn),它的實現(xiàn)目標(biāo)是克服舊的日期時間實現(xiàn)中所有的缺陷。但是Spring中的很多組件標(biāo)準(zhǔn)(如JPA2.1)的制定時間更早,因此未兼容到Java 8的新時間類型(LocalDate, LocalTime, LocalDateTime),所以直接使用這些類型作為時間屬性時,會出現(xiàn)轉(zhuǎn)換失敗等異常。

但Spring各組件在隨后的更新中均添加了對Java 8新時間類型的支持,但是需要進(jìn)行手動配置。使用這些相關(guān)的支持,可以讓我們更愉快地使用LocalDate等類型作為我們對象默認(rèn)的時間屬性了。

如何將LocalDate和LocalDateTime通過JPA持久化

當(dāng)我們在使用JPA進(jìn)行持久層操作時,如果實體(entity)的某個屬性為Java 8的新時間類型時,它將無法正確地被持久化到數(shù)據(jù)庫。JPA會將其映射為一個BLOB字段而不是DATE or TIMESTAMP,而這并不是我們所希望的。

使用AttributeConverter支持新時間類型的映射轉(zhuǎn)換

在JPA標(biāo)準(zhǔn)中,DATE字段使用java.sql.Date進(jìn)行映射,而TIMESTAMP字段則是java.sql.Timestampjava.util.Date則可以通過@Temporal注解指定映射的時間類型。因此,如果要讓JPA兼容新的時間類型,則需要將新時間類型轉(zhuǎn)換為JPA支持的時間類型。

使用Spring官方提供的Converter

在Sping Data的公共模塊中,很早便加入了JSR-310的支持,如果要使用該Converter,只需要在你的應(yīng)用啟動類中添加以下配置:

@EntityScan(
  basePackageClasses = { Application.class, Jsr310JpaConverters.class}
)
@SpringBootApplication
class Application { … }

該配置將保證你的應(yīng)用目錄以及JSR-310的Converter將被掃描到,并且支持使用新的時間類型的entity被持久化。但需要注意的是,該Converter只是將新時間類型轉(zhuǎn)換為了傳統(tǒng)的Date,而且僅支持未帶時區(qū)信息的時間類型。

使用自定義的Converter

由于Spring-Data-JPA默認(rèn)使用的HibernateJPA2.1標(biāo)準(zhǔn)進(jìn)行的實現(xiàn)。而在JPA2.1中,增加了Attribute Converter功能,因此,可以通過自定義Attribute Converter來實現(xiàn)新時間類型的轉(zhuǎn)換。

例如:

@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {
    
    @Override
    public Date convertToDatabaseColumn(LocalDate locDate) {
        return (locDate == null ? null : Date.valueOf(locDate));
    }
    
    @Override
    public LocalDate convertToEntityAttribute(Date sqlDate) {
        return (sqlDate == null ? null : sqlDate.toLocalDate());
    }
    
}

首先需要實現(xiàn)AttributeConverter<LocalDate, Date>接口,包括它的兩個轉(zhuǎn)換方法:convertToDatabaseColumnconvertToEntityAttribute,它們兩個定義了從實體類型(LocalDate)轉(zhuǎn)換成數(shù)據(jù)庫字段類型(Date)以及與之相反方法。這里的寫法非常簡單,因為java.sql.Date已經(jīng)有現(xiàn)成的通過LocalDate進(jìn)行轉(zhuǎn)換的方法。

然后需要將該屬性轉(zhuǎn)換器添加 @Converter 注解并設(shè)置autoApply屬性為true,該設(shè)置將保證該轉(zhuǎn)換器會自動應(yīng)用到LocalDate類型的屬性上。

最后確認(rèn)該Converter可以被bean掃描器掃描到,這樣我就完成了一個自定義的屬性轉(zhuǎn)換器。同理,我們可以創(chuàng)建一個LocalDateTime的轉(zhuǎn)換器:

@Converter(autoApply = true)
public class LocalDateTimeAttributeConverter implements AttributeConverter<LocalDateTime, Timestamp> {
    
    @Override
    public Timestamp convertToDatabaseColumn(LocalDateTime locDateTime) {
        return (locDateTime == null ? null : Timestamp.valueOf(locDateTime));
    }

    @Override
    public LocalDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
        return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime());
    }
}

其它方案

Hibernate5同樣提供了對Java 8新時間類型的支持,可以通過pom文件中增加以下配置來添加依賴:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-java8</artifactId>
    <version>5.1.0.Final</version>
</dependency>

附:hibernate5 Java 8支持包映射關(guān)系對應(yīng)表

Java type JDBC type
java.time.Duration BIGINT
java.time.Instant TIMESTAMP
java.time.LocalDateTime TIMESTAMP
java.time.LocalDate DATE
java.time.LocalTime TIME
java.time.OffsetDateTime TIMESTAMP
java.time.OffsetTime TIME
java.time.ZonedDateTime TIMESTAMP

SpringMVC如何將request參數(shù)自動封裝為LocalDate和LocalDateTime

在使用SpringMVC時,java.util.Date類型字段可以使用@DateTimeFormat注解將application/x-www-from-urlencoded類型的請求中的字符串進(jìn)行自動轉(zhuǎn)換。而Java 8中新的時間類型該如何支持呢?

在application/x-www-from-urlencoded(鍵值對)請求中自動轉(zhuǎn)換新時間類型

Spring4.0開始,Spring的context模塊包中增加了Jsr310DateTimeFormatAnnotationFormatterFactory工廠類。該類是對@DateTimeFormat注解的JSR310標(biāo)準(zhǔn)擴(kuò)展支持。因此,在Spring4.0之后,可以直接使用@DateTimeFormat注解標(biāo)注LocalDate等新時間類型字段,從而實現(xiàn)時間格式字符串到新時間類型的自動轉(zhuǎn)換。

如:

public class SimpleRequest {
    
    private Integer id;
    
    @DateTimeFormat(iso = ISO.DATE)
    private LocalDate startDate;
    
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime startTime;
}

在JSON請求中支持新時間類型的轉(zhuǎn)換

如果請求的格式為application/json,則@DateTimeFormat注解將不再生效,取而代之的是Spring默認(rèn)使用Jackson作為json的序列化工具,因此需要增加Jackson對新時間類型的反序列化器(Deserializer)來支持新時間類型的轉(zhuǎn)換。

Jackson官方已經(jīng)提供了對JSR310標(biāo)準(zhǔn)的支持包,只需在pom文件中添加以下配置引入依賴(版本自選):

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.9.3</version>
</dependency>

然后在需要反序列化(序列化)的對象字段上添加@JsonDeserialize(using = LocalDateDeserializer.class)@JsonSerialize(using = LocalDateSerializer.class))注解,Jackson便會使用該反序列化器將json字段反序列化成LocalDate類型。

如:

public class SimpleRequest {
    
    private Integer id;
    
    @JsonDeserialize(using = LocalDateDeserializer.class)
    @JsonSerialize(using = LocalDateSerializer.class)
    private LocalDate startDate;
    
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    private LocalDateTime startTime;
}

在Spring Boot 2.0之后,將默認(rèn)依賴spring-boot-starter-json包,該依賴包括了jackson-datatype-jsr310在內(nèi)的3種json實用工具包,因此不需要再手動添加依賴

結(jié)語

Java 8的日期/時間API非常易于使用,理解了其設(shè)計語法會讓相似方法也變得非常好找。以上的這些說明就是為了方便更快地在實際應(yīng)用中將舊的時間類切換為新的時間類型,雖然會有些時間上的消耗,但我相信在你理解了新Api帶來的方便與好處后,就會知道這是值得的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,253評論 6 342
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評論 19 139
  • 和蒙哥馬利寫的另一本書《綠山墻的安妮》一樣,里面充滿了對景物的描寫。各種平凡的景物,在作者筆下仿佛有了生命力一樣...
    春春她說閱讀 226評論 0 1
  • 你的美 光艷 璀璨 讓人不忍直視 又流連忘返 多少暗夜 用淚水 洗盡自己的鉛華 多少苦痛 用身體 一層一層的包裹 ...
    海靜16閱讀 133評論 0 0
  • 津渡(66)拒賄文|大尾巴狗 津渡目錄上一章【都市】津渡(65)新氣象 學(xué)校辦公樓后面,常有兩輛同樣款式的帕薩特停...
    大尾巴狗閱讀 603評論 4 5

友情鏈接更多精彩內(nèi)容