【深度思考】自定义日期格式,为什么@JSONField生效,@JsonFormat不生效?

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;

注意事项:

修改全局配置需慎重,如果一个老项目,原来日期类型返回的都是时间戳,突然全部改为返回字符串,可能会造成调用方报错。

文章持续更新,欢迎关注微信公众号「申城异乡人」第一时间阅读!

相关推荐
熊大如如3 小时前
Java 反射
java·开发语言
猿来入此小猿4 小时前
基于SSM实现的健身房系统功能实现十六
java·毕业设计·ssm·毕业源码·免费学习·猿来入此·健身平台
goTsHgo4 小时前
Spring Boot 自动装配原理详解
java·spring boot
卑微的Coder5 小时前
JMeter同步定时器 模拟多用户并发访问场景
java·jmeter·压力测试
pjx9875 小时前
微服务的“导航系统”:使用Spring Cloud Eureka实现服务注册与发现
java·spring cloud·微服务·eureka
多多*5 小时前
算法竞赛相关 Java 二分模版
java·开发语言·数据结构·数据库·sql·算法·oracle
爱喝酸奶的桃酥5 小时前
MYSQL数据库集群高可用和数据监控平台
java·数据库·mysql
唐僧洗头爱飘柔95276 小时前
【SSM-SSM整合】将Spring、SpringMVC、Mybatis三者进行整合;本文阐述了几个核心原理知识点,附带对应的源码以及描述解析
java·spring·mybatis·springmvc·动态代理·ioc容器·视图控制器
骑牛小道士6 小时前
Java基础 集合框架 Collection接口和抽象类AbstractCollection
java
alden_ygq7 小时前
当java进程内存使用超过jvm设置大小会发生什么?
java·开发语言·jvm