Spring MVC 返回 JSON 時,`Date`/`LocalDateTime` 預設序列化為 **時間戳(Long)**,前端需自行格式化。本文提供三大類解決方案:**註解級精確控制、全域統一配置、Jackson 2.x 現代 API**,並解決常見坑點。
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; }
}
| 屬性 | 說明 | 範例 |
|---|---|---|
| pattern | 日期格式模式 | "yyyy-MM-dd HH:mm:ss" |
| timezone | 時區 | "GMT+8", "UTC", "Asia/Shanghai" |
| locale | 地區化 | Locale.CHINA |
| shape | 序列化形狀 | Shape.STRING (預設), Shape.NUMBER, Shape.ARRAY |
<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>
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
serialization:
write-dates-as-timestamps: false # 關鍵:禁用時間戳
@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;
}
}
<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>
@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;
}
}
@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_TIMESTAMPS | mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) |
| 時區偏移 8 小時 | 伺服器時區非 GMT+8,Jackson 預設 UTC | mapper.setTimeZone(TimeZone.getTimeZone("GMT+8")) |
| LocalDateTime 序列化失敗 | 缺少 jackson-datatype-jsr310 | 引入依賴並 registerModule(new JavaTimeModule()) |
| MyBatis 生成實體覆蓋註解 | 代碼生成器覆寫 getter | 配置生成器模板保留註解、或用全域配置 |
| Swagger 文檔顯示格式不一致 | Swagger 讀取註解/型別資訊 | @ApiModelProperty(example = "2024-01-01 12:00:00") 或全域配置 |
**全域配置統一標準,註解覆蓋特例,Jackson 2.x + JavaTimeModule 是現代基石**。Spring Boot 僅需 `application.yml` 3 行配置;傳統 Spring MVC 用 `MappingJackson2HttpMessageConverter` 注入自定義 `ObjectMapper`。掌握序列化/反序列化全鏈路、時區處理、多格式兼容、效能優化,才能構建穩健的 JSON API 服務。