首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

SpringMVC @ResponseBody 日期類型序列化全攻略:Jackson 全局配置與字段級精細控制

     編輯:Java 綜合教學

前言

前後端分離架構下,@ResponseBody 返回對象直接序列化為 JSON,日期字段(Date、LocalDateTime 等)的格式化是高頻剛需。本文系統講解 Jackson 依賴配置、全局 ObjectMapper 定制、@JsonFormat 字段級覆蓋、Java 8 時間模塊支持、常見坑與避坑指南,構建完整日期序列化解決方案。

一、依賴準備:Jackson 核心三件套

<properties>
    <jackson.version>2.15.2</jackson.version> <!-- 統一版本,避免傳遞依賴衝突 -->
</properties>

<dependencies>
    <!-- 核心流式解析/生成 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <!-- 資料綁定:ObjectMapper、註解、POJO 映射 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <!-- Java 8 時間類型支持(LocalDateTime、Instant、ZoneId 等) -->
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        jackson-datatype-jsr310
        ${jackson.version}
    

注意: Spring Boot 2.x/3.x 內置 Jackson,無需額外引入,直接配置即可。傳統 SpringMVC 需確保類路徑有 jackson-databind,Spring MappingJackson2HttpMessageConverter 會自動檢測並啟用。

二、全局配置:ObjectMapper 定制化

2.1 Spring Boot 2.x/3.x 標準方式

@Configuration
public class JacksonConfig {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();

        // 1. 註冊 Java 8 時間模塊(關鍵!否則 LocalDateTime 序列化為數組/時間戳)
        mapper.registerModule(new JavaTimeModule());

        // 2. 禁用時間戳輸出,改用 ISO-8601 字串格式(推薦)
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        // 3. 設置全局默認日期格式(針對 java.util.Date、Calendar)
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

        // 4. 設置全局時區(避免跨時區部署導致時間偏移)
        mapper.setTimeZone(TimeZone.getTimeZone("GMT+8")); // 或 ZoneId.of("Asia/Shanghai")

        // 5. 反序列化容錯配置
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 忽略未知字段
        mapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, true); // 時區自適應

        return mapper;
    }
}

2.2 Spring Boot 配置屬性方式(零代碼)

# application.yml
spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    serialization:
      write-dates-as-timestamps: false
    deserialization:
      fail-on-unknown-properties: false
    # JavaTimeModule 需代碼註冊,或 Spring Boot 3+ 自動註冊

2.3 傳統 SpringMVC XML 配置

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="com.fasterxml.jackson.databind.ObjectMapper">
                    <property name="dateFormat">
                        <bean class="java.text.SimpleDateFormat">
                            <constructor-arg value="yyyy-MM-dd HH:mm:ss"/>
                        </bean>
                    </property>
                    <property name="timeZone" value="GMT+8"/>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

三、字段級精細控制:@JsonFormat 覆蓋全局

public class OrderVO {
    // 1. 標準格式:序列化/反序列化雙向生效
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime createTime;

    // 2. 僅序列化輸出格式化(反序列化按全局/默認)
    @JsonFormat(pattern = "yyyy/MM/dd", shape = JsonFormat.Shape.STRING)
    private LocalDate shipDate;

    // 3. 針對 java.util.Date 同樣生效
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
    private Date updateTime;

    // 4. 枚舉/數字/字串形態控制
    @JsonFormat(shape = JsonFormat.Shape.NUMBER_INT) // 序列化為時間戳毫秒數
    private Instant instant;
}

關鍵屬性詳解

屬性作用示例
pattern日期格式模式yyyy-MM-dd HH:mm:ss, yyyy-MM-dd'T'HH:mm:ss.SSSXXX
timezone時區 IDGMT+8, Asia/Shanghai, UTC
locale區域設定(月份名稱等)zh_CN, US
shape輸出形態STRING(默認), NUMBER_INT(時間戳), ARRAY

四、Java 8+ 時間類型最佳實踐

4.1 實體類優先使用 java.time 包

public class Event {
    private LocalDateTime startTime;    // 本地日期時間,無時區
    private ZonedDateTime zonedTime;    // 帶時區日期時間
    private Instant timestamp;          // 時間戳(UTC),資料庫存儲/傳輸首選
    private LocalDate dateOnly;         // 僅日期
    private LocalTime timeOnly;         // 僅時間
    private Duration duration;          // 時長
    private Period period;              // 日期間隔
}

4.2 必須註冊 JavaTimeModule

否則 LocalDateTime 會被序列化為 [2023, 10, 1, 14, 30, 0] 數組,Instant 序列化為時間戳數字,反序列化同樣失敗。

4.3 格式模式差異

  • Date/Calendar:SimpleDateFormat 模式(yyyy-MM-dd HH:mm:ss)。
  • java.time 類型:DateTimeFormatter 模式(yyyy-MM-dd HH:mm:ss 兼容,但推薦 ISO-8601 yyyy-MM-dd'T'HH:mm:ss)。

五、常見坑與避坑指南

現象原因解決方案
日期輸出為時間戳數字WRITE_DATES_AS_TIMESTAMPS=true (默認)全局 mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) 或字段 @JsonFormat(shape=STRING)
LocalDateTime 序列化為數組缺少 JavaTimeModulemapper.registerModule(new JavaTimeModule())
時間少 8 小時 / 多 8 小時時區不一致(JVM/服務器/數據庫/前端)全局統一 setTimeZone(GMT+8),字段 timezone 覆蓋,數據庫連接配置 serverTimezone=Asia/Shanghai
反序列化失敗:Unrecognized fieldJSON 字段與 POJO 不匹配FAIL_ON_UNKNOWN_PROPERTIES=false 或補全字段
@JsonFormat 不生效用在 getter 上但未開啟 USE_GETTERS_AS_SETTERS,或類型不匹配建議標註在字段上;確認類型為 Date/LocalDateTime 等時間類型
SimpleDateFormat 線程不安全全局 setDateFormat 共用實例Jackson 內部已處理線程安全,但自定義 DateFormat 實現需注意

六、進階:自定義 JsonSerializer/Deserializer

// 多格式兼容反序列化器
public class FlexibleLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
    private static final DateTimeFormatter[] FORMATTERS = {
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),
        DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"),
        DateTimeFormatter.ofPattern("yyyy-MM-dd"),
        DateTimeFormatter.ISO_LOCAL_DATE_TIME
    };

    @Override
    public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String text = p.getText().trim();
        for (DateTimeFormatter fmt : FORMATTERS) {
            try { return LocalDateTime.parse(text, fmt); }
            catch (DateTimeParseException ignored) {}
        }
        throw new IOException("無法解析日期: " + text);
    }
}

// 使用
@JsonDeserialize(using = FlexibleLocalDateTimeDeserializer.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime flexibleTime;

七、總結

  1. 依賴齊全: jackson-databind + jackson-datatype-jsr310(Java 8+ 必備)。
  2. 全局統一: ObjectMapper 配置格式、時區、時間戳開關、容錯策略。
  3. 字段覆蓋: @JsonFormat 精細控制單字段格式/形態/時區。
  4. 類型現代化: 實體類優先用 java.time 類型,配合 JavaTimeModule。
  5. 時區一致性: JVM/應用/數據庫/前端 全鏈路統一時區(推薦 GMT+8/Asia/Shanghai)。

掌握這套體系,即可從容應對 REST API 中 99% 的日期序列化場景,告別「時間少 8 小時」、「格式不一致」、「反序列化報錯」等經典坑點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved