我有一个 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/