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

Spring MVC JSON 日期格式化完整解決方案:@JsonFormat、ObjectMapper 全域配置、Jackson 2.x 最佳實踐

     編輯:Java 相關知識

前言

Spring MVC 返回 JSON 時,`Date`/`LocalDateTime` 預設序列化為 **時間戳(Long)**,前端需自行格式化。本文提供三大類解決方案:**註解級精確控制、全域統一配置、Jackson 2.x 現代 API**,並解決常見坑點。

方案一:@JsonFormat 註解級精確控制(推薦細粒度)

1.1 基本用法


public class User {
    private Date birthday;
    private LocalDateTime createTime;

    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    public Date getBirthday() { return birthday; }

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    public LocalDateTime getCreateTime() { return createTime; }
}

1.2 關鍵屬性

屬性說明範例
pattern日期格式模式"yyyy-MM-dd HH:mm:ss"
timezone時區"GMT+8", "UTC", "Asia/Shanghai"
locale地區化Locale.CHINA
shape序列化形狀Shape.STRING (預設), Shape.NUMBER, Shape.ARRAY

1.3 依賴要求(Jackson 2.x)


<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.15.2</version>
</dependency> 

方案二:全域 ObjectMapper 配置(推薦統一標準)

2.1 Spring Boot 2.x/3.x 自動配置方式(application.yml)


spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    serialization:
      write-dates-as-timestamps: false # 關鍵:禁用時間戳

2.2 Java 配置類方式(完全控制)


@Configuration
public class JacksonConfig {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        
        // 註冊 Java 8 時間模組
        mapper.registerModule(new JavaTimeModule());
        
        // 禁用時間戳輸出
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        
        // 統一日期格式
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        
        // 統一時區
        mapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        
        // 忽略未知屬性(防禦性)
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        
        return mapper;
    }
}

2.3 Spring MVC 非 Boot 環境配置


<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>

方案三:Jackson 2.x 進階特性與最佳實踐

3.1 Java 8 時間類型專用序列化器


@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        
        // LocalDateTime 格式
        mapper.configOverride(LocalDateTime.class)
            .setFormat(JsonFormat.Value.forPattern("yyyy-MM-dd HH:mm:ss"));
        
        // LocalDate 格式
        mapper.configOverride(LocalDate.class)
            .setFormat(JsonFormat.Value.forPattern("yyyy-MM-dd"));
        
        // Instant 格式(ISO-8601)
        mapper.configOverride(Instant.class)
            .setFormat(JsonFormat.Value.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"));
        
        return mapper;
    }
}

3.2 全域配置與註解共存策略

  • **全域配置**作為預設標準(如 `yyyy-MM-dd HH:mm:ss`)
  • **特殊字段**用 `@JsonFormat` 覆蓋(如生日只需 `yyyy-MM-dd`)
  • **優先級**:`@JsonFormat` > `configOverride` > `setDateFormat`

3.3 反序列化多格式兼容


@Bean
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JavaTimeModule());
    
    // 自定義反序列化器:支援多種輸入格式
    mapper.setDateFormat(new StdDateFormat()); // Jackson 內建多格式支援
    // 或自定義
    SimpleModule module = new SimpleModule();
    module.addDeserializer(Date.class, new JsonDeserializer() {
        private static final String[] PATTERNS = {
            "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd", "yyyy/MM/dd", "yyyyMMdd"
        };
        @Override
        public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            String text = p.getText();
            for (String pattern : PATTERNS) {
                try { return new SimpleDateFormat(pattern).parse(text); } 
                catch (ParseException ignored) {}
            }
            throw new IOException("無法解析日期: " + text);
        }
    });
    mapper.registerModule(module);
    return mapper;
}

常見坑點與解決

現象原因解決
依然輸出時間戳未禁用 WRITE_DATES_AS_TIMESTAMPSmapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
時區偏移 8 小時伺服器時區非 GMT+8,Jackson 預設 UTCmapper.setTimeZone(TimeZone.getTimeZone("GMT+8"))
LocalDateTime 序列化失敗缺少 jackson-datatype-jsr310引入依賴並 registerModule(new JavaTimeModule())
MyBatis 生成實體覆蓋註解代碼生成器覆寫 getter配置生成器模板保留註解、或用全域配置
Swagger 文檔顯示格式不一致Swagger 讀取註解/型別資訊@ApiModelProperty(example = "2024-01-01 12:00:00") 或全域配置

效能優化建議

  1. ObjectMapper 為單例:線程安全,重用避免重複建立開銷
  2. 預先註冊模組:啟動時完成 `JavaTimeModule`、`ParameterNamesModule` 等註冊
  3. 關閉不必要特性:`FAIL_ON_UNKNOWN_PROPERTIES=false`、`WRITE_DATES_AS_TIMESTAMPS=false`
  4. 日期格式化器複用:`SimpleDateFormat` 非線程安全,**不可**作為靜態共享,Jackson 內部已處理

總結

**全域配置統一標準,註解覆蓋特例,Jackson 2.x + JavaTimeModule 是現代基石**。Spring Boot 僅需 `application.yml` 3 行配置;傳統 Spring MVC 用 `MappingJackson2HttpMessageConverter` 注入自定義 `ObjectMapper`。掌握序列化/反序列化全鏈路、時區處理、多格式兼容、效能優化,才能構建穩健的 JSON API 服務。

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