你可以通过覆盖 configureMessageConverters()(替换 Spring MVC 创建的默认转换器)或覆盖 extendMessageConverters()(自定义默认转换器或为默认转换器添加额外的转换器)在 Java 配置中定制 HttpMessageConverter。
下面的例子用一个定制的 ObjectMapper 来增加 XML 和 Jackson JSON 转换器,而不是默认的
@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
.modulesToInstall(new ParameterNamesModule());
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
}
}
在前面的例子中,Jackson2ObjectMapperBuilder 被用来为 MappingJackson2HttpMessageConverter 和MappingJackson2XmlHttpMessageConverter 创建一个共同的配置,启用缩进,自定义日期格式,并注册 jackson-module-parameter-names(被迁移到了 jackson-modules-java8),这增加了对访问参数名称的支持(Java 8 中增加的功能)。
这个构建器定制了 Jackson 的默认属性,如下所示:
该特性决定了在反序列化为 Java 原始类型(如 int 或 double )时,遇到 JSON null 是否是一个错误。如果是,会抛出一个JsonProcessingException 来表明这一点;如果不是,会使用默认值(0 代表 int,0.0 代表 double,与 JVM 使用的默认值相同)。
默认情况下,该功能是禁用的。
如果在 classpath 上检测到以下知名模块,它也会自动注册:
- jackson-datatype-joda: 支持 Joda-Time 类型
- jackson-datatype-jsr310: 支持 Java 8 日期和时间 API 类型。
- jackson-datatype-jdk8: 支持其他 Java 8 类型,如 Optional。
- jackson-module-kotlin: 支持 Kotlin 类和数据类。
:::tips 启用 Jackson XML 支持的缩进,除了 jackson-dataformat-xml 之外,还需要 woodstox-core-asl 的依赖。 :::
其他有趣的 Jackson 模块也可以使用:
- jackson-datatype-money:支持 javax.money 类型(非官方模块)。
- jackson-datatype-hibernate:支持 Hibernate 特定的类型和属性(包括懒惰加载方面)。
下面的例子显示了如何在 XML 中实现同样的配置:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
<bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">
<property name="objectMapper" ref="xmlMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
p:indentOutput="true"
p:simpleDateFormat="yyyy-MM-dd"
p:modulesToInstall="com.fasterxml.jackson.module.paramnames.ParameterNamesModule"/>
<bean id="xmlMapper" parent="objectMapper" p:createXmlMapper="true"/>
一个例子
@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
.modulesToInstall(new ParameterNamesModule());
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
}
}
注意需要添加以下依赖
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.2.2'
// MappingJackson2XmlHttpMessageConverter 会用到
implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: '2.13.2'
就那上面的 dataFormat 来说,它的效果就是让你的入参的 Date 能够正确的被格式化(如果没有配置这个,默认也能被解析,应该是 Spring 默认的转换器器提供的功能,但是时分秒或则说是时区不正确),而响应的时候,也能按照这里的格式格式化后输出
@PostMapping("/data")
@ResponseBody
public Pet data(@Valid @RequestBody Pet pet) {
System.out.println(pet);
return pet;
}
public class Pet {
@NotNull
private String name;
private Date date;
.. 省略 getter 和 setter
访问的时候
POST http://localhost:8080/demo/data
Content-Type: application/json
{
"name": "zxx",
"date": "2022-02-03"
}
关于 jackson-modules-java8
jackson-modules-java8 当与 Jackson 2.x 一起使用时,Java 8 支持通过 3 个单独的模块提供:
- 参数名称:支持检测构造函数和工厂方法(creator)参数,无需使用 @JsonProperty 注解
- 提供 com.fasterxml.jackson.module.paramnames.ParameterNamesModule
- Java 8 日期/时间:支持 Java 8 日期/时间类型(在 JSR-310 规范中指定)
- 提供 com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
- 还提供旧版变体 com.fasterxml.jackson.datatype.jsr310.JSR310TimeModule
- 2个模块之间的区别在于配置默认值:JavaTimeModule 强烈推荐使用新代码
- Java 8 数据类型:支持日期/时间之外的其他新的 Java 8 数据类型:最值得注意的是 Optional, OptionalLong,OptionalDouble
- 提供 com.fasterxml.jackson.datatype.jdk8.Jdk8Module