Message Converters

你可以通过覆盖 configureMessageConverters()(替换 Spring MVC 创建的默认转换器)或覆盖 extendMessageConverters()(自定义默认转换器或为默认转换器添加额外的转换器)在 Java 配置中定制 HttpMessageConverter。

下面的例子用一个定制的 ObjectMapper 来增加 XML 和 Jackson JSON 转换器,而不是默认的

  1. @Configuration
  2. @EnableWebMvc
  3. public class WebConfiguration implements WebMvcConfigurer {
  4. @Override
  5. public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
  6. Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
  7. .indentOutput(true)
  8. .dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
  9. .modulesToInstall(new ParameterNamesModule());
  10. converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
  11. converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
  12. }
  13. }

在前面的例子中,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 上检测到以下知名模块,它也会自动注册:

:::tips 启用 Jackson XML 支持的缩进,除了 jackson-dataformat-xml 之外,还需要 woodstox-core-asl 的依赖。 :::

其他有趣的 Jackson 模块也可以使用:

下面的例子显示了如何在 XML 中实现同样的配置:

  1. <mvc:annotation-driven>
  2. <mvc:message-converters>
  3. <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
  4. <property name="objectMapper" ref="objectMapper"/>
  5. </bean>
  6. <bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">
  7. <property name="objectMapper" ref="xmlMapper"/>
  8. </bean>
  9. </mvc:message-converters>
  10. </mvc:annotation-driven>
  11. <bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
  12. p:indentOutput="true"
  13. p:simpleDateFormat="yyyy-MM-dd"
  14. p:modulesToInstall="com.fasterxml.jackson.module.paramnames.ParameterNamesModule"/>
  15. <bean id="xmlMapper" parent="objectMapper" p:createXmlMapper="true"/>

一个例子

  1. @Configuration
  2. @EnableWebMvc
  3. public class WebConfiguration implements WebMvcConfigurer {
  4. @Override
  5. public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
  6. Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
  7. .indentOutput(true)
  8. .dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
  9. .modulesToInstall(new ParameterNamesModule());
  10. converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
  11. converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
  12. }
  13. }

注意需要添加以下依赖

  1. implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.2.2'
  2. // MappingJackson2XmlHttpMessageConverter 会用到
  3. implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: '2.13.2'

就那上面的 dataFormat 来说,它的效果就是让你的入参的 Date 能够正确的被格式化(如果没有配置这个,默认也能被解析,应该是 Spring 默认的转换器器提供的功能,但是时分秒或则说是时区不正确),而响应的时候,也能按照这里的格式格式化后输出

  1. @PostMapping("/data")
  2. @ResponseBody
  3. public Pet data(@Valid @RequestBody Pet pet) {
  4. System.out.println(pet);
  5. return pet;
  6. }
  7. public class Pet {
  8. @NotNull
  9. private String name;
  10. private Date date;
  11. .. 省略 getter setter

访问的时候

  1. POST http://localhost:8080/demo/data
  2. Content-Type: application/json
  3. {
  4. "name": "zxx",
  5. "date": "2022-02-03"
  6. }

关于 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