0x03一次时间序列化问题


问题描述:


数据库中:时间是2023-06-08 16:00:00image-20250509133022538

前端接口请求后返回:2023-06-09 00:00:00

image-20250509133144692

处理步骤:


前端数据从buiness服务返回,业务服务是order。

先大致锁定是那个环节出了问题:

1.数据库->order服务? image-20250509133441428

通过日志判断数据库传到order服务是正确的。

2.order服务返回给business服务?

因为spring默认是用Jackson 序列话,故在两个服务的controller输出序列话结果。

@Autowired
private ObjectMapper objectMapper;

try {
  String json = objectMapper.writeValueAsString(complainSuggestionDTO);
  System.out.println("order服务序列化结果:" + json);
} catch (Exception e) {
  System.out.println(e.getMessage());
}

String json = objectMapper.writeValueAsString(orderComplainSuggestionDTO);
System.out.println("business服务序列化结果:" + json);


输出结果如下:
order:
image-20250509135216055
business:
image-20250509134701581
order服务正常,business服务就错了。
deepseek给出的原因:

  1. 数据库时区与服务端时区不匹配
  2. 序列化框架时区配置问题
  3. 数据库连接配置缺失

image-20250509135633872
数据库时区是正确的,排除1

通过检查配置,数据库连接也是正确的,排除3

需要验证是否是jackson的时区配置不正确

两个服务的配置均有:time-zone: Asia/Shanghai

@PostConstruct
public void checkConfig() {
    System.out.println("当前时区:" + objectMapper.getSerializationConfig().getTimeZone());
    System.out.println("日期格式:" + objectMapper.getDateFormat());
}


两个服务的配置也均为 Asia/Shanghai:

image-20250509140404372
因为该字段有注解:

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")


部分回答中提到注解需要加上时区

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss" ,timezone = "Asia/Shanghai")


经过测试 注解加上时区后,两个服务的时间就一致了。至此,算时间解决了问题。

等等?还有最重要的why?为什么已经指定了jackson的时区,还是需要在注解中再次指定?注解加上时区后序列话有所不同吗?

在wireshark中不加注解,端口出去的是:
image-20250509120934214
加了注解端口出去的还是
image-20250509142226736
也就是注解并不会影响http传输的内容

deepseek给的解释是:

  1. 字段注解优先级覆盖了全局配置,注解中没有明确指明就使用的jvm默认时区。
  2. 因为序列化时没有携带时区信息,反序列化时将其当作默认时区再按照本地时区给+8小时。


最终原因:

太难debug了,找到后面发现restTemplate里的ObjectMapper‌ 的baseconfig里的时区为null,解析时发现注解没有指定get方法就返回了默认UTC时区。可是为什么配置中已经有了jackson:time-zone: Asia/Shanghai,且Autowired的ObjectMapper‌时区是对的,为什么restTemplate里的Mapper就没有时区呢?可能不是同一个对象。
fuck:restTemplate 是用的 Jackson2ObjectMapperBuilder.json().build() 不是spring 自动管理的,故配置无效。


image-20250509192818337