【深度思考】自定義日期格式,為什么@JSONField生效,@JsonFormat不生效?
2025-04-21 10:16 申城異鄉人 閱讀(784) 評論(0) 收藏 舉報1. 前言
最近在自測接口時,發現一個問題:字段類型定義的是Date,但接口返回值里卻是時間戳(1744959978674),
而不是預期的2025-04-18 15:06:18。
private Date useTime;
{
"code": "200",
"message": "",
"result": [
{
"id": 93817601,
"useTime": 1744959978674
}
]
}
這種返回值,無法快速的知道是哪個時間,如果想知道時間對不對,還得找一個時間戳轉換工具做下轉換才能確定,非常不方便。
因此想讓接口直接返回預期的2025-04-18 15:06:18格式。
剛開始,在字段上添加了@JsonFormat注解,發現沒生效,返回的還是時間戳:
import com.fasterxml.jackson.annotation.JsonFormat;
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date useTime;
然后,改成了@JSONField注解,發現生效了,達到了預期的結果:
import com.alibaba.fastjson.annotation.JSONField;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date useTime;
{
"code": "200",
"message": "",
"result": [
{
"id": 93817601,
"useTime": "2025-04-18 15:06:18"
}
]
}
那么問題來了,為啥@JSONField生效,@JsonFormat不生效?
2. 原因分析
默認情況下,Spring Boot使用的JSON消息轉換器是Jackson的MappingJackson2HttpMessageConverter,核心依賴為:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.11.3</version>
</dependency>
現在使用Jackson的@JsonFormat注解不生效,說明Spring Boot沒有使用默認的MappingJackson2HttpMessageConverter。
使用fastjson的@JSONField注解生效了,說明Spring Boot使用的是fastjson下的JSON消息轉換器,也就是
FastJsonHttpMessageConverter,依賴為:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
那么怎么找到代碼在哪配置的呢?
第一步,先在項目中全局搜索FastJsonHttpMessageConverter(Windows快捷鍵:Ctrl+Shift+F),不過大概率是搜索不到,因為
公司里的項目一般都繼承自公司公共的xxx-spring-boot-starter。
第二步,連按2次Shift鍵搜索FastJsonHttpMessageConverter,然后查找該類的引用或者子類(子類很可能是公司底層框架中寫的)。
然后,很可能會找到類似下面的代碼:
@Configuration
public class FastJsonMessageConverterConfig {
@Bean
public HttpMessageConverters customConverters() {
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
return new HttpMessageConverters(new HttpMessageConverter[]{fastJsonHttpMessageConverter});
}
}
以上代碼顯式注冊了一個FastJsonHttpMessageConverter,并通過HttpMessageConverters覆蓋了默認的HTTP 消息轉換器
(Jackson的MappingJackson2HttpMessageConverter),所以Spring MVC將只使用fastjson處理JSON序列化/反序列化。
這也是@JSONField生效,@JsonFormat不生效的根本原因。
3. 默認行為及全局配置
fastjson 1.2.36及以上版本,默認將日期序列化為時間戳(如1744959978674),如果要默認將日期序列化為yyyy-MM-dd HH:mm:ss
(如2025-04-18 15:06:18),需要啟用WriteDateUseDateFormat特性:
@Configuration
public class FastJsonMessageConverterConfig {
@Bean
public HttpMessageConverters customConverters() {
FastJsonConfig fastJsonConfig = new FastJsonConfig();
// 啟用日期格式化特性(禁用時間戳)
fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteDateUseDateFormat);
// 設置日期格式(不指定時,默認為yyyy-MM-dd HH:mm:ss,但即使與默認值一致,也建議明確指定)
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
return new HttpMessageConverters(new HttpMessageConverter[]{fastJsonHttpMessageConverter});
}
}
如果某個日期字段有特殊序列化要求,可以使用@JSONField注解靈活配置(該注解會覆蓋全局配置):
import com.alibaba.fastjson.annotation.JSONField;
@JSONField(format = "yyyy-MM-dd")
private Date anotherUseTime;
注意事項:
修改全局配置需慎重,如果一個老項目,原來日期類型返回的都是時間戳,突然全部改為返回字符串,可能會造成調用方報錯。
文章持續更新,歡迎關注微信公眾號「申城異鄉人」第一時間閱讀!
浙公網安備 33010602011771號