1. 前言
最近在自测接口时,发现一个问题:字段类型定义的是Date,但接口返回值里却是时间戳(1744959978674),
而不是预期的2025-04-18 15:06:18。
java
private Date useTime;
json
{
"code": "200",
"message": "",
"result": [
{
"id": 93817601,
"useTime": 1744959978674
}
]
}
这种返回值,无法快速的知道是哪个时间,如果想知道时间对不对,还得找一个时间戳转换工具做下转换才能确定,非常不方便。
因此想让接口直接返回预期的2025-04-18 15:06:18格式。
刚开始,在字段上添加了@JsonFormat
注解,发现没生效,返回的还是时间戳:
java
import com.fasterxml.jackson.annotation.JsonFormat;
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date useTime;
然后,改成了@JSONField
注解,发现生效了,达到了预期的结果:
java
import com.alibaba.fastjson.annotation.JSONField;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date useTime;
json
{
"code": "200",
"message": "",
"result": [
{
"id": 93817601,
"useTime": "2025-04-18 15:06:18"
}
]
}
那么问题来了,为啥@JSONField生效,@JsonFormat不生效?
2. 原因分析
默认情况下,Spring Boot使用的JSON消息转换器是Jackson的MappingJackson2HttpMessageConverter
,核心依赖为:
xml
<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
,依赖为:
xml
<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
,然后查找该类的引用或者子类(子类很可能是公司底层框架中写的)。
然后,很可能会找到类似下面的代码:
java
@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
特性:
java
@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
注解灵活配置(该注解会覆盖全局配置):
java
import com.alibaba.fastjson.annotation.JSONField;
@JSONField(format = "yyyy-MM-dd")
private Date anotherUseTime;
注意事项:
修改全局配置需慎重,如果一个老项目,原来日期类型返回的都是时间戳,突然全部改为返回字符串,可能会造成调用方报错。
文章持续更新,欢迎关注微信公众号「申城异乡人」第一时间阅读!