我有一个控制器,其响应是camelCase json值。现在我们用新版本重写代码,所需的响应是snake_case。
我添加了一个消息转换器和修改后的对象映射器来设置setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
public class ResponseJSONConverter extends MappingJackson2HttpMessageConverter {
@Autowired
public ResponseJSONConverter(ObjectMapper objectMapper) {
setObjectMapper(objectMapper);
}
}
我已经用弹簧注册了这个转换器,它按预期工作。现在我希望我的旧端点在camelCase中返回,以便我的使用者和使用snake_case的新端点向后兼容。
我尝试使用简单的对象映射器再创建一个消息转换器,而不将camelCase设置为Snake case属性并使用spring注册。根据spring配置中声明的顺序,只应用一个消息转换器。
我们有什么方法可以做到这一点?根据条件加载邮件转换器?
修改
添加了我的弹簧配置文件
<beans xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<bean id="moneySerializer" class="api.serialize.MoneySerializer"/>
<bean id="moneyDeserializer" class="api.serialize.MoneyDeserializer"/>
<bean id="serializationModule" class="api.serialize.SerializationModule">
<constructor-arg index="0" ref="moneySerializer"/>
<constructor-arg index="1" ref="moneyDeserializer"/>
</bean>
<bean id="customObjectMapper" class="api.serialize.CustomObjectMapper" primary="true">
<constructor-arg ref="serializationModule"/>
</bean>
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="api.serialize.ResponseJSONConverterCamelCaseToSnakeCase" >
<constructor-arg ref="customObjectMapper"/>
</bean>
<bean class="api.serialize.ResponseJSONConverter">
<constructor-arg ref="objectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper"/>
</beans>
EDIT 2.0
我的servlet.xml
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="com.tgt.promotions.api.serialize.ServiceJSONConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
CustomMessageConverter
public class ServiceJSONConverter extends MappingJackson2HttpMessageConverter {
@Autowired
public ServiceJSONConverter(SnakeCaseObjectMapper snakeCaseObjectMapper) {
setObjectMapper(snakeCaseObjectMapper);
}
}
自定义对象映射器
@Component
public class SnakeCaseObjectMapper extends ObjectMapper {
@Autowired
public SnakeCaseObjectMapper(PropertyNamingStrategy propertyNamingStrategy) {
setSerializationInclusion(JsonInclude.Include.NON_NULL);
setPropertyNamingStrategy(propertyNamingStrategy);
}
}
自定义属性命名策略
@Component
public class CustomPropertyNamingStrategy extends PropertyNamingStrategy {
@Autowired
private HttpServletRequest request;
private final PropertyNamingStrategy legacyStrategy = PropertyNamingStrategy.LOWER_CASE;
private final PropertyNamingStrategy defaultStrategy = PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES;
@Override
public String nameForConstructorParameter(MapperConfig<?> config, AnnotatedParameter ctorParam, String defaultName) {
return getStrategy().nameForConstructorParameter(config, ctorParam, defaultName);
}
@Override
public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
return getStrategy().nameForField(config, field, defaultName);
}
@Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
return getStrategy().nameForGetterMethod(config, method, defaultName);
}
@Override
public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
return getStrategy().nameForSetterMethod(config, method, defaultName);
}
private PropertyNamingStrategy getStrategy() {
if (isLegacyEndpoint(request)) {
return legacyStrategy;
} else {
return defaultStrategy;
}
}
private boolean isLegacyEndpoint(HttpServletRequest request) {
return request != null && request.getRequestURL() != null && !request.getRequestURL().toString().contains("/v3");
}
}
答案 0 :(得分:0)
我建议创建PropertyNamingStrategy
的自定义实现,而不是使用2个不同的对象映射器,而是使用其他2个策略:
public class AwesomePropertyNamingStrategy extends PropertyNamingStrategy {
private PropertyNamingStrategy legacyStrategy = PropertyNamingStrategy.LOWER_CASE;
private PropertyNamingStrategy defaultStrategy = PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES;
@Override
public String nameForConstructorParameter(MapperConfig<?> config, AnnotatedParameter ctorParam, String defaultName) {
return getStrategy().nameForConstructorParameter(config, ctorParam, defaultName);
}
// TODO: implement other nameForXXX methods
private PropertyNamingStrategy getStrategy() {
if (isLegacyEndpoint()) {
return legacyStrategy;
} else {
return defaultStrategy;
}
}
private boolean isLegacyEndpoint() {
// TODO: get hold of the RequestContext or some other thead-local context
// that allows you to know it's an old or a new endpoint
return false;
}
}
您应该想出一种在旧模式和新模式之间切换的方法:
@LegacyResponse
注释。答案 1 :(得分:0)
好吧,经过多次尝试后没有任何效果。最后最终定义了两个不同的servlet。一个没有任何版本,一个没有v1版本。
<强>的web.xml 强>
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="com.tgt.promotions.api.serialize.DataJSONConverter">
<constructor-arg ref="snakeCaseObjectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
相应地定义了两个servlet snake-case-servlet.xml和camel-case-servlet.xml。
<强>蛇区分servlet.xml中强>
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="com.tgt.promotions.api.serialize.DataJSONConverter">
<constructor-arg ref="objectMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<强>驼的病例servlet.xml中强>
UITextField *txtField1 = [self.view viewWithTag:0];
UITextField *txtField2 = [self.view viewWithTag:1];
UITextField *txtField3 = [self.view viewWithTag:2];
UITextField *txtField4 = [self.view viewWithTag:3];
UITextField *txtField5 = [self.view viewWithTag:4];
if(txtField1.text.length > 0)
{
}
现在,对于使用/ v1 *的任何请求,使用snakeCaseObjectMapper,而对于其他请求,则使用默认对象映射器。