在项目中,实际的例子是:用户触发password changed event,listener 执行update password事件,创建producer。随后通过RabbitMQ Direct Exchange的方式发送数据给queue队列,consumer端接收数据,操作数据库表。
其中环节:在Channel中发送/接收数据时,存在Java Bean 与 Message(一般为Json数据类型)的序列化与反序列化。
附加情况:Java Bean中属性声明modifyDateTime,数据类型为LocalDateTime
。
最终问题在于:对LocalDateTime
属性的序列化与反序列化。
复现问题所在:
定义Java Bean Demo.java:
通过Junit Test执行程序:
其中,serializer打印为:
{
"localDateTime": {
"dayOfWeek": "MONDAY",
"dayOfYear": 301,
"month": "OCTOBER",
"year": 2019,
"monthValue": 10,
"minute": 51,
"second": 49,
"nano": 848000000,
"dayOfMonth": 28,
"hour": 13,
"chronology": {
"id": "ISO",
"calendarType": "iso8601"
}
}
}
这就是问题所在,在LocalDateTime
属性被序列化成Json Object,这使得没法进行反序列化处理。(我这里用的Spring Boot 2.1.6.RELEASE),在正常项目中,这种问题是不存在的,因为默认,spring boot在转换过程中给我们提供了Deserializer
和Serializer
。
题外,简单地查看@ResponseBody
注解的实现:
Spring RequestResponseBodyMethodProcessor
handles return values from methods annotated with @ResponseBody
by writing to the body of the response with an HttpMessageConverter
.
通过Http Request Header Accept指定类型,查找当前response converter,在这里就不多解释这个问题了,抛一篇好文,觉得解释得挺到位(https://www.cnblogs.com/java-chen-hao/p/11187914.html )
对于Json类型,采用了HttpMessageConverter
实现类MappingJackson2HttpMessageConverter
,通过MappingJackson2HttpMessageConverter
给我们提供了ObjectMapper
,查看其中的build()# configue(mapper)#registerWellKnownModulesIfAvailable(modulesToRegister)
从中可以看到,
com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
将该模块添加至ObjectMapper
中,查看JavaTimeModule
源码发现:
addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);
addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE);
这正是我们所需要的。所以,基于Spring Boot的默认机制,已经实现了对LocalDateTime
属性的JSON序列化和反序列化实现。
紧接着上个话题,我通过Junit Test复现问题,在代码中,我们创建了一个新的ObjectMapper
实例,在这种情况下,没有对mapper进行注册JavaTimeModule
模块。
接下来,尝试声明JavaTimeModule
unit test:
序列化结果为:
{"localDateTime":[2019,10,29,1,8,26,191000000]}
也可以通过addSerializer方法加入你想要的或者自定义的序列化实现方式:
结果为:
{"localDateTime":"2019-10-29T12:43:49.272"}
{"localDateTime":"2019-10-29 12:54:25"}
在项目中,通过xml配置或注解方式进行声明:
对于注解方式:
在Java Bean的该属性声明时,加注@JsonSerialize
(指定序列化方式), @JsonDeserialize
(指定反序列化方式),@JsonFormat
(指定格式):
对于xml配置方式,主要是对MappingJackson2HttpMessageConverter
创建ObjectMapper
实例,通过继承ObjectMapper
自定义CustomObjectMapper
,通过构造器方法将需要注册的module添加到mapper中:
其实本质上是对mapper进行添加注册所需的module模块类,通过这种方式,引入我们所需的(反)序列化的方式。当然,对于通过xml配置这种方式对于spring boot本身是没有将注解的方式发挥完整,这个就属于另外一个知识点的学习总结了。