💡 问题现象
在开发 Spring Boot 后端项目时,为了让接口返回给前端的 JSON 日期格式保持统一(去掉默认的带 T 的格式),我们通常会在 application.yml 中加上这样一段 Jackson 的全局配置:
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: Asia/Shanghai
满心欢喜地以为配置完毕,启动项目用 Postman 调接口一看,傻眼了。如果你的实体类使用的是 Java 8 推出的 LocalDateTime,返回的 JSON 数据居然还是长这样:
{
"createTime": "2026-08-13T15:43:45",
"updateTime": "2026-08-13T15:43:45"
}
那个碍眼的 T 依然坚挺地杵在中间,仿佛在嘲笑我们的配置文件毫无作用。这是为什么呢?
🔍 原因分析
其实这不是 Spring Boot 的 Bug,而是 Jackson 处理不同时间类的机制决定的。
在 application.yml 中配置的 spring.jackson.date-format,底层依赖的是传统的 SimpleDateFormat,它只对 Java 老版本的 java.util.Date 类生效。
而对于 Java 8 引入的新时间 API(如 LocalDateTime、LocalDate),Jackson 引入了一个全新的模块(JavaTimeModule)来进行处理。这个模块非常“固执”,它默认遵循严格的 ISO-8601 国际标准(即 yyyy-MM-dd'T'HH:mm:ss)。因此,它会直接无视你在 yml 里的普通日期配置。
🛠️ 解决方案
要解决这个问题,告别带 T 的日期,通常有两种方式:
方法一:局部注解配置(适合临时应对)
如果你只有极个别字段需要格式化,可以直接在实体类的字段上加上 @JsonFormat 注解。它的优先级最高,会直接接管该字段的序列化格式。
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
public class SysUser {
// ... 其他字段 ...
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime createTime;
}
缺点:每次新建实体类都要写一遍,不仅繁琐,而且容易遗漏,不利于团队代码规范。
方法二:编写全局配置类(🌟 强烈推荐)
既然 application.yml 管不到 LocalDateTime,我们就用 Java 代码直接向 Spring Boot 的 Jackson 构建器中注入自定义的序列化规则。一劳永逸,全局生效。
在项目的 config 包下新建一个 JacksonConfig 类:
package cn.okcl.oa.config;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* Jackson 全局配置类
* 解决 LocalDateTime 在 JSON 序列化时带有 'T' 的问题
*/
@Configuration
public class JacksonConfig {
private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
// 1. 配置 LocalDateTime 的序列化(后端返回给前端的时间格式)
builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(formatter));
// 2. 配置 LocalDateTime 的反序列化(前端传给后端的时间格式解析)
builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(formatter));
};
}
}
🎉 最终效果
加上这个配置类,重启项目后再次请求接口,你会发现 JSON 里的时间已经变成了我们最熟悉的清爽格式:
{
"createTime": "2026-08-13 15:43:45",
"updateTime": "2026-08-13 15:43:45"
}
补充建议:yml 中的
date-format配置不用删除,可以继续保留。这样一来,yml 负责兜底老旧的java.util.Date,配置类负责接管新的LocalDateTime,双管齐下,你的项目就可以完美兼容所有的时间类型了!