Spring настраивает формат @ResponseBody JSON - PullRequest
39 голосов
/ 28 января 2011

Представьте, что у меня есть этот аннотированный метод в 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. пружинный префиксjson с ответным телом
  2. Кто устанавливает тип содержимого ответа в Spring MVC (@ResponseBody)

Спасибо!

Ответы [ 11 ]

31 голосов
/ 13 февраля 2014

Для тех, кто использует 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 Mapper, вместо этого используйте этот MappingJacksonHttpMessageConverter

 <dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>${codehaus.jackson.version}</version>
 </dependency>
28 голосов
/ 14 декабря 2012

Мне нужно решить очень похожую проблему, которая заключается в настройке Jackson Mapper на «Не сериализуйте нулевые значения ради Христа !!!».

Я не хотел оставлять необычный тег mvc: annotation-based, поэтому я нашел, как настроить ObjectMapper Джексона, не удаляя mvc: annotation-driven и добавляя не очень интересный ContentNegotiatingViewResolver.

Прекрасно то, что вам не нужно самостоятельно писать код Java!

А вот конфигурация XML (не путайте с различными пространствами имен классов Джексона, я просто использовал новую библиотеку 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>
15 голосов
/ 28 января 2011

AngerClown указал мне в правильном направлении.

Это то, что я наконец-то сделал, на случай, если кто-нибудь посчитает это полезным.

<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);
10 голосов
/ 01 сентября 2015

Для Spring версии 4.1.3 +

Я испробовал решение Jama, но затем все ответы были возвращены с типом контента application / json, включая основную сгенерированную страницу HTML.

Переопределение configureMessageConverters(...) не позволяет пружине настраивать преобразователи по умолчанию.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(...)

10 голосов
/ 03 мая 2013

Весной 3.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>
4 голосов
/ 20 января 2015

Не отвечает на вопрос, но это лучший результат Google.

Если кто-нибудь придет сюда и захочет сделать это для Spring 4 (как это случилось со мной), вы можете использовать аннотацию

@JsonInclude(Include.NON_NULL)

на возвращающемся классе.

4 голосов
/ 19 января 2012

Я написал свой собственный 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;
        }

}

И использование в конфигурации пружины:

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

3 голосов
/ 13 октября 2011

Взгляните на подход Рика Хайтауэра. Его подход избегает настройки ObjectMapper как одиночного и позволяет фильтровать JSON-ответ для одного и того же объекта различными способами для каждого метода запроса.

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

2 голосов
/ 28 января 2011

Вы можете настроить ObjectMapper как bean-компонент в своем XML-файле Spring.Ссылка на 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-файле.Обратите внимание, что вы можете напрямую устанавливать значения свойств Spring с помощью Enums, которые определяет Джексон;см. этот вопрос .

Кроме того, ContentNegotiatingViewResolver, вероятно, не требуется, это просто код, который я использую в существующем проекте.

1 голос
/ 25 декабря 2013

Вы можете сделать следующее (версия Джексона <2): </p>

Пользовательский класс сопоставления:

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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...