1. 从一次真实的“时间错乱”Bug说起
我记得很清楚,那是去年一个周五的下午,临下班前,测试同学火急火燎地跑过来找我:“哥,你看这个新增用户的接口,我传‘2023-10-27’,怎么存到数据库里就变成‘2023-10-27 08:00:00’了?多了8个小时!” 我第一反应是服务器时区不对,但检查了Linux系统时间,是东八区没错。接着他又说:“还有,列表查询返回的创建时间字段,怎么是个带‘T’和‘+00:00’的奇怪字符串?前端直接解析报错了。”
这一连串的问题,瞬间把我拉回了现实。这可不是什么高深的算法难题,而是每个Java后端开发者在处理日期时间时,几乎百分百会踩到的坑。日期,这个看似简单的数据,在前端、后端、数据库、序列化框架之间流转时,就像一场没有统一规则的接力赛,稍有不慎就会“掉棒”。而解决这些问题的两把关键钥匙,就是 @DateTimeFormat 和 @JsonFormat 注解。很多人知道要用它们,但用起来总感觉差点意思,不是格式不对就是时间莫名偏移。今天,我就结合自己趟过的坑,带你彻底搞懂这两个注解,让你在日期处理上再也不“心虚”。
简单来说,@DateTimeFormat 和 @JsonFormat 是Spring和Jackson框架分别提供的“翻译官”。当日期数据在不同系统间传递时,它们负责把字符串“翻译”成Java的 Date 对象,或者把 Date 对象“翻译”成对方能看懂的字符串格式。@DateTimeFormat 主要管的是请求参数绑定,特别是URL查询参数和表单数据;而 @JsonFormat 管的是 JSON数据的序列化与反序列化,也就是接口入参和出参时,JSON字符串和Java对象之间的转换。理解它们的分工,是正确使用的第一步。
2. 不靠注解?先看看“裸奔”的日期有多混乱
在请出两位“翻译官”之前,我们得先看看如果不用它们,系统会乱成什么样。这能帮你深刻理解为什么必须用注解。我搭建了一个最简单的Spring Boot项目,一个 User 实体,里面有个 Date 类型的 birthday 字段,然后写了一个接收JSON的POST接口和一个接收URL参数的GET接口。
2.1 JSON传参的“默认行为”
我用Postman发一个POST请求,Body里写 {"birthday": "2023-10-27"}。你猜后端收到的 Date 对象是什么?控制台打印出来是 Fri Oct 27 08:00:00 CST 2023。没错,我明明只传了年月日,它自己给我加上了8点,还带上了“CST”时区标识。更“神奇”的是,这个对象直接通过 @ResponseBody 返回给前端时,变成了 2023-10-26T16:00:00.000+00:00。一个简单的日期,经过后端一趟,面目全非。
这里涉及两个关键机制。第一,当Spring接收到JSON字符串中的 "2023-10-27" 时,它的默认反序列化器会将其视为 UTC(世界协调时) 时间的零点。而我的服务器在东八区,所以Java在转换成 Date 对象时,会自动加上8小时,变成了当天的早上8点。第二,当Jackson把 Date 对象序列化成JSON返回时,默认使用的是 ISO 8601 格式,并且会先将时间转换回UTC时间。所以,东八区的早上8点,减去8小时,就变成了UTC时间的前一天下午4点,于是就有了那个带“T”和“+00:00”的字符串。如果你试图传 "2023-10-27 15:30:00" 这样的格式,Spring会直接懵掉,抛出一个400错误,因为它不认识这种非ISO的格式。
2.2 URL传参的“严格模式”
那通过GET请求,在URL里传 ?birthday=2023-10-27 呢?情况更糟。Spring MVC对于URL中的日期参数,默认期望的格式是 "yyyy/MM/dd"。你传 "2023-10-27" 这种带横杠的,它根本不认,直接400错误。即使你侥幸格式对了,时区转换的问题依然存在。这种“裸奔”状态下的日期处理,充满了不确定性和默认规则,完全无法满足业务开发


378

被折叠的 条评论
为什么被折叠?



