springboot 默认使用objectmapper(jackson)操作对象的序列化和反序列化
分析
从springboot:3.2.1 web 项目序列化响应体的过程中分析日期格式化问题(左侧是请求处理流程,右侧是在流程中使用的一些对象的来源)

objectmapper与jsonserializer
根据上述流程可知,序列化响应结果时使用的objectmapper对象是由自动配置类jacksonautoconfiguratioin.jacksonobjectmapperconfiguration使用jackson2objectmapperbuilder创建,并注册到beanfactory中。

创建objectmapper对象

设置objectmapper对象的属性
在jackson2objectmapperbuilder#build方法中创建了objectmapper对象,然后在jackson2objectmapperbuilder#configure方法中对objectmapper对象设置了一些属性。
例如创建javatimemodule对象并将其注册给objectmapper, 正是在javatimemodule的构造方法中指定了localdatetime的序列化器使用com.fasterxml.jackson.datatype.jsr310.ser.localdatetimeserializer,并将这种关系使用objectmapper#registermodules注册给objectmapper对象

在以下方法中创建了com.fasterxml.jackson.datatype.jsr310.javatimemodule对象
private void registerwellknownmodulesifavailable(multivaluemap<object, module> modulestoregister) {
// ...
try {
class<? extends module> javatimemoduleclass = (class<? extends module>)
classutils.forname("com.fasterxml.jackson.datatype.jsr310.javatimemodule", this.moduleclassloader);
module javatimemodule = beanutils.instantiateclass(javatimemoduleclass);
modulestoregister.set(javatimemodule.gettypeid(), javatimemodule);
}
catch (classnotfoundexception ex) {
// jackson-datatype-jsr310 not available
}
// ...
}在javatimemodule类的构造函数中设置了localdatetime类型和该类型使用的序列化器localdatetimeserializer和反序列化器localdatetimedeserializer的对应关系

结论
springboot项目中,使用从beanfactory中获取的objectmapper序列化对象时,若对象的字段类型是localdatetime,则使用com.fasterxml.jackson.datatype.jsr310.ser.localdatetimeserializer对字段进行序列化,但是其默认的日期格式并不是我们想要的。

因此需要干涉上述流程,使用自定义的日期时间格式

自定义日期格式(全局)
1.直接操作spring容器中的objectmapperbean
利用objectmapper#registermodule
2.自定义容器中的jackson2objectmapperbuilderbean,达到间接操作objectmapper的目的
从流程图中可知,容器中的objectmapper对象由jackson2objectmapperbuilder创建(创建者模式),因此自定义jackson2objectmapperbuilder的属性,会间接作用到objectmapper的属性
根据jacksonautoconfiguration.jacksonobjectmapperbuilderconfiguration源码可知,创建一个jackson2objectmapperbuildercustomizer实现类,并将其注入到容器中,可对容器中的jackson2objectmapperbuilder bean进行自定义配置

按照上述思路实现如下(真实工作中需考虑多个customizer的顺序)

也可以使用modulestoinstall方法

3.向容器中注入com.fasterxml.jackson.databind.module的实现类
这是因为springboot自动配置包中已经提供了一个jackson2objectmapperbuildercustomizer实现类,在创建该实现类对象时,它将从容器中获取的com.fasterxml.jackson.databind.modulebean用于自定义配置jackson2objectmapperbuilder

同时,可以看到standardjackson2objectmapperbuildercustomizer类使用了jacksonproperties的配置,也就说可以在配置文件中做些定义的配置

扩展
利用配置文件指定java.util.date类型的格式化
spring:
jackson:
date-format: yyyy-mm-dd hh:mm:ss
time-zone: gmt+8这种方式对java.time.localdatetime类型无效
利用注解指定时间格式化(局部)
@jsonformat,对java.util.date和java.time.localdatetime都有效

@jsonserialize、@jsondeserialize,指定使用的序列化器@datetimeformat@jsoncomponent
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论