💥 前端传个"2026-10-16 14:30:00",后端一接收直接报错400------日期格式化的痛,每个Java后端都经历过。
💥 项目里十几个实体类,每个字段都写@JsonFormat?改个格式要改十几处?维护起来想哭......
💥 今天分享3种全局日期格式化方案,从简单到高级,配完整代码,抄完直接用,再也不用手写转换了。
一、痛点回顾:日期格式为什么总出问题?
Java后端的日期处理一直是重灾区,主要问题有这几个:
✅ 前端传的是字符串"2026-10-16",后端要用LocalDate接收
✅ 前端传的是时间戳1760601600000,后端要用Date接收
✅ 后端返回给前端的日期格式不统一,有的带T,有的带时区
✅ 不同接口格式不一样,用户中心用yyyy-MM-dd,订单中心用yyyy/MM/dd
最原始的做法是在每个Controller里手动SimpleDateFormat转换,代码丑、容易出错、还没法复用。下面看3种正经方案。
二、方案一:@JsonFormat注解(最简单)
直接在实体类字段上加注解,控制序列化和反序列化格式:
java
public class OrderDTO {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",
timezone = "GMT+8")
private LocalDateTime createTime;
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate birthDay;
}
三、方案二:全局Converter配置(推荐)
写一个全局的Converter,统一处理前端传入的字符串到LocalDate/LocalDateTime的转换:
java
@Configuration
public class DateConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter<String, LocalDate>() {
@Override
public LocalDateconvert(String source) {
return LocalDate.parse(source,
DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}
});
registry.addConverter(new Converter<String, LocalDateTime>() {
@Override
public LocalDateTimeconvert(String source) {
return LocalDateTime.parse(source,
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
});
}
}
**适用场景:**处理前端通过GET请求参数、表单提交传入的日期字符串。比如 /api/orders?startDate=2026-10-16 这种。
**注意:**这个方案只管"接收",不管"返回"。如果要控制返回给前端的格式,还需要配合其他方案。
四、方案三:Jackson全局配置(最全面)
直接配置Jackson的ObjectMapper,同时控制序列化和反序列化,一劳永逸:
java
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizercustomizer() {
return builder -> {
DateTimeFormatter dateFormatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter dateTimeFormatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// LocalDate序列化/反序列化
builder.serializers(
new LocalDateSerializer(dateFormatter));
builder.deserializers(
new LocalDateDeserializer(dateFormatter));
// LocalDateTime序列化/反序列化
builder.serializers(
new LocalDateTimeSerializer(dateTimeFormatter));
builder.deserializers(
new LocalDateTimeDeserializer(dateTimeFormatter));
};
}
}
配完之后,所有接口的请求和响应都自动按统一格式处理,实体类上不用加任何注解,干净清爽。
⚠️ 注意
如果某个接口需要特殊格式,在字段上加@JsonFormat可以覆盖全局配置,优先级:字段注解 > 全局配置。
五、application.yml极简配置法
如果你只需要统一格式,不需要多格式兼容,直接在配置文件里写就行,连Java代码都不用动:
java
# application.yml
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
serialization:
write-dates-as-timestamps: false
这个方案对java.util.Date类型完全生效。但对Java 8的LocalDateTime需要额外加依赖或配合方案三使用。
六、3种方案对比
| 对比维度 | @JsonFormat注解 | 全局Converter | Jackson全局配置 |
|---|---|---|---|
| 控制粒度 | 字段级别 | 全局(接收) | 全局(接收+返回) |
| 代码量 | 多(每个字段加) | 中 | 少(一处配置) |
| 灵活性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 维护性 | 差(改格式要全局搜) | 好 | 最好 |
| 适用场景 | 格式不统一、特殊字段 | GET参数/表单接收 | JSON接口统一格式 |
七、生产环境最佳实践
✅ 统一用LocalDate/LocalDateTime,别再用java.util.Date了,线程不安全,坑多。
✅ 全局Jackson配置 + 个别字段@JsonFormat覆盖,兼顾统一性和灵活性。
✅ 时区必须明确指定,统一用GMT+8或者UTC,别依赖系统默认时区,部署到服务器上会出问题。
✅ 前后端约定好格式文档,写进Swagger或接口文档里,别靠口头约定。
✅ 时间戳方案不推荐,可读性差,调试困难,除非对接第三方系统有硬性要求。