【问题标题】:Spring configure @ResponseBody JSON formatSpring配置@ResponseBody JSON格式
【发布时间】:2011-06-16 22:32:14
【问题描述】:

想象一下我在 Spring 3 @Controller 中有这个带注释的方法

@RequestMapping("")
public @ResponseBody MyObject index(@RequestBody OtherObject obj) {
    MyObject result = ...;
    return result;
}

但是我需要配置输出json格式,就像我在做的那样:

ObjectMapper om = new ObjectMapper();
om.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, true);
om.getSerializationConfig()
        .setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
om.getSerializationConfig()
        .set(SerializationConfig.Feature.INDENT_OUTPUT, false);

有没有办法配置这种行为?

我发现了几个相关的问题,但我不确定如何根据我的具体情况调整它们:

  1. spring prefixjson with responsebody
  2. Who sets response content-type in Spring MVC (@ResponseBody)

谢谢!

【问题讨论】:

    标签: java spring spring-mvc jackson


    【解决方案1】:

    对于使用 基于 Java 的 Spring 配置的人:

    @Configuration
    @ComponentScan(basePackages = "com.domain.sample")
    @EnableWebMvc
    public class SpringConfig extends WebMvcConfigurerAdapter {
    ....
    
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
            final ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            converter.setObjectMapper(objectMapper);
            converters.add(converter);
            super.configureMessageConverters(converters);
        }
    
    ....
    
    }
    

    我正在使用 MappingJackson2HttpMessageConverter - 来自 fastxml。

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.3.1</version>
    </dependency>
    

    如果你想使用codehaus-jackson映射器,改用这个MappingJacksonHttpMessageConverter

     <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>${codehaus.jackson.version}</version>
     </dependency>
    

    【讨论】:

      【解决方案2】:

      我需要解决非常相似的问题,即将 Jackson Mapper 配置为“看在上帝的份上不要序列化空值!!!”。

      我不想留下花哨的 mvc:annotation-driven 标签,所以我发现,如何配置 Jackson 的 ObjectMapper,而不删除 mvc:annotation-driven 并添加不是很花哨的 ContentNegotiatingViewResolver。

      美妙的是,您不必自己编写任何 Java 代码!

      这里是 XML 配置(不要与 Jackson 类的不同命名空间混淆,我只是使用了新的 Jakson 2.x 库......同样适用于 Jackson 1.x 库):

      <mvc:annotation-driven>
          <mvc:message-converters register-defaults="true">
              <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                  <property name="objectMapper">
                      <bean class="com.fasterxml.jackson.databind.ObjectMapper">
                          <property name="serializationInclusion">
                              <value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value>
                          </property>
                      </bean>
                  </property>
              </bean>
          </mvc:message-converters>
      </mvc:annotation-driven>
      

      【讨论】:

      • 您还可以利用@Tody.Lu 所指出的Jackson2ObjectMapperFactoryBean,只需将serializationInclusion 属性设置为NON_NULL
      【解决方案3】:

      AngerClown pointed me 正确的方向。

      这就是我最后所做的,以防万一有人觉得它有用。

      <bean
          class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
          <property name="messageConverters">
              <list>
                  <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                      <property name="objectMapper" ref="jacksonObjectMapper" />
                  </bean>
              </list>
          </property>
      </bean>
      
      <!-- jackson configuration : https://stackoverflow.com/questions/3661769 -->
      <bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
      <bean id="jacksonSerializationConfig" class="org.codehaus.jackson.map.SerializationConfig"
          factory-bean="jacksonObjectMapper" factory-method="getSerializationConfig" />
      <bean
          class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
          <property name="targetObject" ref="jacksonSerializationConfig" />
          <property name="targetMethod" value="setSerializationInclusion" />
          <property name="arguments">
              <list>
                  <value type="org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion">NON_DEFAULT</value>
              </list>
          </property>
      </bean>
      

      我仍然需要弄清楚如何配置其他属性,例如:

      om.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, true);
      

      【讨论】:

      • 这对我不起作用。得到这个“org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping:86-AbstractDetectingUrlHandlerMapping.java {http-thread-pool-4848-(2)} | Rejected bean name 'jacksonObjectMapper': no URL paths known”跨度>
      • 只是不是这不适用于&lt;mvc:annotation-driven /&gt; 我发现很难。
      • AnnotationMethodHandlerAdapter 已弃用.... 改为使用 AbstractHttpMessageConverter
      【解决方案4】:

      在spring3.2中,引入了新的解决方案:http://static.springsource.org/spring/docs/3.2.0.BUILD-SNAPSHOT/api/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.html, 下面是我的例子:

       <mvc:annotation-driven>
         ​<mvc:message-converters>
           ​​<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
             ​​​<property name="objectMapper">
               ​​​​<bean
       class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                 ​​​​​<property name="featuresToEnable">
                   ​​​​​​<array>
                     ​​​​​​​<util:constant static-field="com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_SINGLE_QUOTES" />
                   ​​​​​​</array>
                 ​​​​​</property>
               ​​​​</bean>
             ​​​</property>
           ​​</bean>
         ​</mvc:message-converters>
       </mvc:annotation-driven>
      

      【讨论】:

      • 对我来说,当我在 AbstractMessageConverterMethodProcessor 类中检查 messageConverters 时,它包含两个 MappingJackson2HttpMessageConverter。一个通过 spring 另一个通过我们的配置。
      • 对我来说,当我在 AbstractMessageConverterMethodProcessor 类中检查 messageConverters 时,它包含两个 MappingJackson2HttpMessageConverter。一个通过 spring 另一个通过我们的配置。
      【解决方案5】:

      适用于 Spring 4.1.3+ 版

      我尝试了 Jama 的解决方案,但随后所有响应都返回了 Content-type 'application/json',包括生成的主要 HTML 页面。

      覆盖configureMessageConverters(...) 防止 spring 设置默认转换器。 Spring 4.1.3 允许通过覆盖来修改已配置的转换器 extendMessageConverters(...):

      @Configuration
      public class ConverterConfig extends WebMvcConfigurerAdapter {
          @Override
          public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
              for (HttpMessageConverter<?> converter : converters) {
                  if (converter instanceof AbstractJackson2HttpMessageConverter) {
                      AbstractJackson2HttpMessageConverter c = (AbstractJackson2HttpMessageConverter) converter;
                      ObjectMapper objectMapper = c.getObjectMapper();
                      objectMapper.setSerializationInclusion(Include.NON_NULL);
                  }
              }
      
              super.extendMessageConverters(converters);
          }
      }
      

      org.springframework..WebMvcConfigurationSupport#getMessageConverters()

      org.springframework..WebMvcConfigurationSupport#addDefaultHttpMessageConverters(...)

      【讨论】:

        【解决方案6】:

        我编写了自己的 FactoryBean,它实例化了一个 ObjectMapper(简化版):

         public class ObjectMapperFactoryBean implements FactoryBean<ObjectMapper>{
        
                @Override
                public ObjectMapper getObject() throws Exception {
                        ObjectMapper mapper = new ObjectMapper();
                        mapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
                        return mapper;
                }
        
                @Override
                public Class<?> getObjectType() {
                        return ObjectMapper.class;
                }
        
                @Override
                public boolean isSingleton() {
                        return true;
                }
        
        }
        

        以及spring配置中的用法:

        <bean
            class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
            <property name="messageConverters">
                <list>
                    <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                        <property name="objectMapper" ref="jacksonObjectMapper" />
                    </bean>
                </list>
            </property>
        </bean>
        

        【讨论】:

          【解决方案7】:

          不回答问题,但这是谷歌搜索结果。

          如果有人来这里并想为 Spring 4 做这件事(就像我发生的那样),你可以使用注释

          @JsonInclude(Include.NON_NULL)
          

          在返校班上。

          【讨论】:

          • 解决了包含非空参数的问题。但是 JsonGenerator.Feature.QUOTE_FIELD_NAMES 或 SerializationConfig.Feature.INDENT_OUTPUT 等其他自定义项呢?
          • QUOTE_FIELD_NAMES 默认启用,因此 spring 4 至少(没有用 3 测试)会自动执行它,它在 javadoc 中:/** *(主要信息).... * 功能是默认启用(因为它是 JSON 规范所要求的)。 */ 至于 INDENT_OUTPUT,你可以这样做: MyObject result = ...; ObjectMapper 映射器 = 新的 ObjectMapper(); return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(result);
          【解决方案8】:

          您可以将 ObjectMapper 配置为 Spring xml 文件中的 bean。拥有对 ObjectMapper 的引用的是 MappingJacksonJsonView 类。然后,您需要将视图附加到 ViewResolver。

          这样的事情应该可以工作:

          <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
                <property name="mediaTypes">
                <map>
                  <entry key="json" value="application/json" />
                  <entry key="html" value="text/html" />
                </map>
              </property>
              <property name="viewResolvers">
                <list>
                  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/WEB-INF/jsp/" />
                    <property name="suffix" value=".jsp" />
                  </bean>
                </list>
              </property>
              <property name="defaultViews">
                <list>
                  <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
                    <property name="prefixJson" value="false" />
                    <property name="objectMapper" value="customObjectMapper" />
                  </bean>
                </list>
              </property>
            </bean>
          

          customObjectMapper 在 xml 文件的其他位置定义。请注意,您可以使用 Enums Jackson 定义的方式直接设置 Spring 属性值;见this question

          另外,可能不需要 ContentNegotiatingViewResolver,它只是我在现有项目中使用的代码。

          【讨论】:

          • 谢谢,您的回答对我帮助很大。使用最终和工作配置查看我的答案。
          【解决方案9】:

          看看 Rick Hightower 的方法。他的方法避免将 ObjectMapper 配置为单例,并允许您针对每个请求方法以不同的方式过滤同一对象的 JSON 响应。

          http://www.jroller.com/RickHigh/entry/filtering_json_feeds_from_spring

          【讨论】:

          • 有趣。谢谢你,格雷格。
          • 对于其他使用它的人,如果使用 XML 连接通知,请确保它是在 servlet 上下文而不是根上下文中完成的。如果 XML 在根上下文中,则建议不会应用于 @Controllers。
          • 网站已关闭。
          【解决方案10】:

          您可以执行以下操作(杰克逊版本

          自定义映射器类:

          import org.codehaus.jackson.JsonGenerator;
          import org.codehaus.jackson.map.ObjectMapper;
          import org.codehaus.jackson.map.SerializationConfig;
          import org.codehaus.jackson.map.annotate.JsonSerialize;
          
          public class CustomObjectMapper extends ObjectMapper {
              public CustomObjectMapper() {
                  super.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, true);
                  super.getSerializationConfig()
                          .setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
                  super.getSerializationConfig()
                          .set(SerializationConfig.Feature.INDENT_OUTPUT, false);
              }
          }
          

          弹簧配置:

          <mvc:annotation-driven>
              <mvc:message-converters register-defaults="false">
                  <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                      <property name="objectMapper">
                          <bean class="package.CustomObjectMapper"/>
                      </property>
                  </bean>
              </mvc:message-converters>
          </mvc:annotation-driven>
          

          【讨论】:

            【解决方案11】:

            是的,但是如果您开始使用 mixins 会发生什么,例如,您不能将 ObjectMapper 作为单例,因为您将在全局范围内应用配置。那么您将在同一个 ObjectMapper 实例上添加或设置 mixin 类?

            【讨论】:

            • 好问题。我不知道我采取的方法是否可行。
            猜你喜欢
            • 1970-01-01
            • 2018-01-11
            • 2014-04-11
            • 2017-05-25
            • 2012-04-01
            • 1970-01-01
            • 2013-06-15
            • 2011-05-21
            • 2015-01-14
            相关资源
            最近更新 更多