JDK8 日期格式化


SpringBoot 是為了簡化 Spring 應用的創建、運行、調試、部署等一系列問題而誕生的產物,自動裝配的特性讓我們可以更好的關注業務本身而不是外部的XML配置,我們只需遵循規范,引入相關的依賴就可以輕易的搭建出一個 WEB 工程

為什么要用新的日期類型

在 JDK8 中,一個新的重要特性就是引入了全新的時間和日期API,它被收錄在 java.time 包中。借助新的時間和日期API可以以更簡潔的方法處理時間和日期。

在 JDK8 之前,所有關於時間和日期的API存在以下幾個缺陷,也正是這些缺陷,出現了很多第三方的日期處理框架,例如 Joda-Timedate4j等開源項目。但是,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 了,一路學習下來的小伙伴們肯定都熟記於心了

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

配置文件

由於 spring.jackson.date-format 對新的日期類型不在有效果,所以這里0配置文件了

方案一(強烈推薦)

只需要定義一個配置類,在里面定義兩個 Bean 即可完成全局日期格式化處理,這種方式也是本人現在使用的,同時還兼顧了 Date 和 LocalDateTime 並存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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 注解我們可以更為精准的為日期字段格式化,它也是優先級最高的

1
2
3
4
5
6
public class Order {

@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDateTime payTime;
// 省略 GET SET ...
}

方案三(可選)

其實和第一種類似,只不過第一種的寫法更加優雅簡潔,如果有多種類型需要做統一格式化處理,這種方案也不是不可以考慮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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));
}
}
}

控制層

定義了一個很簡單的響應

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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;
}
}

主函數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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,訪問 http://localhost:8080/orders 即可看到格式化后的日期啦…


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM