一个接口完成约一周后,前端反馈日期突然变成时间戳。我检查字段上的 @JsonFormat,它仍然存在。继续追踪,发现对象在返回之前经过了 Fastjson:
JSONObject.toJSONString(obj)
这使排查方向从“注解漏了没有”变成“谁真正负责序列化”。
注解属于哪一个库
@JsonFormat 来自 Jackson。项目如果显式调用 Fastjson,不能假定它会完整执行另一套库的注解规则。
在 Spring Web 应用中,还要查看控制器返回的是对象还是已经生成的字符串,以及实际生效的消息转换器。提前转成字符串可能绕开原本的对象序列化路径,也可能带来重复编码等差异,最终以响应头和响应正文为准。
当时采用的历史处理
旧项目改用可指定日期格式的 Fastjson API 后,取得了预期结果。对 Fastjson 1.x,对应示意是:
String json = JSON.toJSONStringWithDateFormat(
obj, "yyyy-MM-dd HH:mm:ss"
);
该 API 及历史默认格式常量可在 Fastjson 1.2.83 的 JSON 源码查看。这里是维护旧代码的说明,不是建议新项目安装该版本,也不适用于所有 fastjson2 API。
指定格式还不等于指定了时区。字段类型、序列化器配置和运行环境都可能影响日期含义。
更清楚的接口契约
如果应用决定使用 Jackson,通常应让框架按统一规则序列化对象,而不是在某个分支里临时换库生成 JSON 字符串。需要局部格式时,再按字段类型使用相应注解和时区配置。
排查可以固定同一个对象,比较“直接返回对象”和“先转字符串”两条路径,并记录日期字段值、类型、时区、Content-Type 及完整响应。不要仅凭浏览器展示推断服务器输出。
日期应在接口中明确采用时间戳、带偏移量的标准文本,还是约定时区的显示文本。选择哪一种都需要前后端一致;格式修复不能掩盖时间本身被错移的问题。