Spring REST Web 服务序列化为多种 JSON 格式

标签 spring rest jackson

我有一个 Spring REST Web 服务,它根据数据库中的数据填充通用对象,目标是让用户将参数传递给 Web 服务以指示他们希望输出的格式.根据他们的输入,我们将使用正确的 JSONSerializer 来满足他们的需求。

我已经按如下方式设置了我的Web服务,在我的spring-ws-servlet.xml中,我已经将我们公司的ObjectMapper设置为由mvc:message-converters使用,我还在RestController上设置了它,以便它可以调整 ObjectMapper 以注册序列化器。它看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <bean
                class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper" ref="jacksonObjectMapper" />
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <bean id="endpoint" class="org.company.Controller">
        <property name="objectMapper" ref="jacksonObjectMapper" />
    </bean>

    <bean id="jacksonObjectMapper" class="org.company.CompanyObjectMapper" />

</beans>

Controller 看起来像这样:

@RestController
public class Controller {

    private ObjectMapper objectMapper;

    @RequestMapping(...)
    public GenericObject getObject(@PathVariables ...) {

        //Get Object from database, just creating an object for example
        GenericObject object = new GenericObject();

        //Based on the user input we will pick out
        //a Serializer that  extends JsonSerializer<GenericObject>
        BaseSerializer serializer = getSerializer();

        //Create a simpleModule and use it to register our serializer
        SimpleModule module = new SimpleModule();
        module.addSerializer(GenericObject.class, serializer);

        //get module and register the serializer
        ObjectMapper mapper = getObjectMapper();            
        mapper.registerModule(module);

        return object;
    }

    public ObjectMapper getObjectMapper() {
        return objectMapper;
    }

    public void setObjectMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }
}

问题是,当我发布 web 应用程序时,第一个查询可以正常工作,如果我指定 format=format1,我将获得 format1 的输出。但是,之后我只能接收format1。我可以指定 format=format2,但仍然得到 format1 的输出。我认为问题在于 ObjectMapper 仍然具有从第一个查询中注册到它的模块。我读过,我可以通过每次创建一个新的 ObjectMapper 来避免这个问题,但我不确定如何设置 Spring 在输出 JSON 时使用它。

有人可以帮我想出一个解决方案,要么在每次运行代码时创建一个新的 ObjectMapper 并将该 ObjectMapper 设置为 Spring Rest 服务,要么帮我弄清楚如何“取消注册”任何已注册的模块在设置最新的所需序列化器之前在对象映射器上?

最佳答案

一个想法可能是在启动时创建并配置您需要的所有映射器作为 spring beans。

然后创建默认对象映射器,它将作为其他对象映射器的调度程序(或作为后备映射器),并且它可能知道当前的 http 请求。 你可以在这个对象映射器中注册所有的映射器,注册这个映射器作为spring中的默认映射器。

也许是这样的:

 public class RequestAwareObjectMapper extends ObjectMapper{

    private Map<String, ObjectMapper > mappers = new HashMap<>();

    @Override
    public String writeValueAsString(Object value) throws JsonProcessingException{
        HttpServletRequest req = null;//get request from spring context, if any, this is a managed spring bean it wont be a prorblem
        String param = null; // read the param from the query
        ObjectMapper mapper = mappers.get(param);
        if(mapper == null){
            mapper = this;
        }
        return mapper.writeValueAsString(value);
    }

    public void registerMapper(String key, ObjectMapper mapper){...}
} 

这样,您就不会因为对对象映射器的引用而污染您的 Controller ,并且您可以继续使用@ResponseBody(感谢@RestController)..

我确信有一种更干净的方法可以在 Spring Flow 中集成类似的解决方案来实现相同的结果,现在找不到更好的方法。

关于Spring REST Web 服务序列化为多种 JSON 格式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33309557/

相关文章:

java - 这些天如何使用 wadl2java?

java - 使用 Spring 和 JsonTypeInfo 注释将 JSON 反序列化为多态对象模型

java - 使用 Spring 和 Jackson 将 Json 数组解析为 Pojo?

spring - 根据用户角色反序列化 JSON 字段

java - 当我正确映射并且文件位于正确的目标位置时出现 "requested resource not available"错误,但我反复遇到同样的问题

java - 如何在 Spring Boot 应用程序中更改 BIRT 创建的图像文件的位置

spring - 在 Spring Data JPA 中连接两个表实体

java - Spring Integration 中的 REST 端点使消息 channel 成为多线程

java - 以实例变量和参数为键的Spring缓存

rest - 通过 REST API 将文件附件上传到 ServiceNow 记录