我有一个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>
控制器如下所示:
@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;
}
}
问题在于,当我发布我的webapp时,第一个查询正常工作,如果我指定format = format1,我将获得format1的输出。但是,之后我只能收到format1。我可以指定format = format2,但仍然以format1获取输出。我相信问题是ObjectMapper仍然从第一个查询中注册了它的模块。我已经读过,我可以通过每次创建一个新的ObjectMapper来避免这个问题,但是我不确定如何设置Spring在它输出JSON时使用它。
有人可以帮我提出一个解决方案,每次运行代码时创建一个新的ObjectMapper并将ObjectMapper设置为Spring休息服务,或者帮助我弄清楚如何“注销”任何已注册的模块在设置最新的所需序列化器之前在对象映射器上?
答案 0 :(得分:2)
创建您的customObjectMapper类并使用@Autowire注释自动将其连接到您的控制器。然后,您可以创建不同的方法来创建不同的格式化对象
您也可以将序列化程序作为参数发送。
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
super();
super.setSerializationInclusion(JsonInclude.Include.ALWAYS);
super.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
..... etc.....
super.setDateFormat(df);
}
public byte[] generateJsonFormat1(Object value, BaseSerializer serializer) throws IOException, JsonGenerationException, JsonMappingException {
Hibernate4Module hm = new Hibernate4Module();
hm.configure(Hibernate4Module.Feature.USE_TRANSIENT_ANNOTATION, false);
hm.configure(Hibernate4Module.Feature.FORCE_LAZY_LOADING, false);
.....
.....
hm.addSerializer(Object.class, serializer);
return super.registerModule(hm).writeValueAsBytes(value);
}
public byte[] generateJsonFormat2(Object value, BaseSerializer serialiser) throws IOException, JsonGe nerationException, JsonMappingException {
SimpleModule sm = new SimpleModule();
sm.addSerializer(Object.class, serialiser);
return super.registerModule(hm).writeValueAsBytes(value);
}
}
上面的代码是我自己的应用程序的片段。我希望它能提出这个想法。
答案 1 :(得分:1)
一个想法可能是创建和配置启动时所需的所有映射器作为spring bean。
然后创建默认对象映射器,它将作为其他对象映射器的调度程序(或作为后备映射程序),并且可能知道当前的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){...}
}
通过这种方式你不会使用对象映射器的引用来污染你的控制器,你可以继续使用@ResponseBody(感谢@RestController)..
我确信,在春季流程中集成类似解决方案可以获得相同结果的更简洁方法,现在无法更好地查看。