Java 如何根据条件应用spring消息转换器?
我有一个响应为camelCase json值的控制器。现在我们正在用新版本重新编写代码,需要的响应是snake_案例 我添加了一个消息转换器,并修改了对象映射器来设置Java 如何根据条件应用spring消息转换器?,java,spring,spring-mvc,jackson2,Java,Spring,Spring Mvc,Jackson2,我有一个响应为camelCase json值的控制器。现在我们正在用新版本重新编写代码,需要的响应是snake_案例 我添加了一个消息转换器,并修改了对象映射器来设置setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL\u CASE\u到带有下划线的\u LOWER\u CASE\u) 我已经向spring注册了这个转换器,它的工作情况与预期的一样。现在,我希望旧端点以camelCase的形式返回,以向后兼容我的消费者和snake_case
setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL\u CASE\u到带有下划线的\u LOWER\u CASE\u)代码>
我已经向spring注册了这个转换器,它的工作情况与预期的一样。现在,我希望旧端点以camelCase的形式返回,以向后兼容我的消费者和snake_case的新端点
我曾尝试过在不将camelCase设置为Snake-case属性并向spring注册的情况下,再使用一个带有简单对象映射器的消息转换器。根据spring配置中声明的顺序,只应用一个消息转换器
我们有没有办法做到这一点?根据条件加载消息转换器
编辑
添加了我的spring配置文件
编辑2.0
myservlet.xml
自定义对象映射器
自定义属性命名策略
@组件
公共类CustomPropertyNamingStrategy扩展了PropertyNamingStrategy{
@自动连线
私有HttpServletRequest;
private final PropertyNamegstrategy legacyStrategy=PropertyNamegstrategy.LOWER_CASE;
private final PropertyNamingStrategy defaultStrategy=PropertyNamingStrategy.CAMEL\u CASE\u TO\u LOWER\u CASE\u,带下划线;
@凌驾
ConstructorParameter的公共字符串名称(MapperConfig配置,AnnotatedParameter ctorParam,String defaultName){
返回getStrategy().nameForConstructorParameter(配置、参数、默认名称);
}
@凌驾
公共字符串名称字段(MapperConfig配置,AnnotatedField字段,字符串默认名称){
返回getStrategy().nameForField(配置、字段、默认名称);
}
@凌驾
公共字符串名称遗忘方法(MapperConfig配置,AnnotatedMethod方法,字符串默认名称){
返回getStrategy().NameForferMethod(配置、方法、默认名称);
}
@凌驾
SetterMethod的公共字符串名称(MapperConfig配置、AnnotatedMethod方法、字符串defaultName){
返回getStrategy().nameForSetterMethod(配置、方法、默认名称);
}
私有财产名称策略getStrategy(){
if(isLegacyEndpoint(请求)){
回归策略;
}否则{
回报策略;
}
}
私有布尔isLegacyEndpoint(HttpServletRequest){
返回请求!=null&&request.getRequestURL()!=null&&request.getRequestURL().toString()包含(“/v3”);
}
}
我建议创建属性名称策略的自定义实现,相应地使用其他两种策略,而不是使用两种不同的对象映射器:
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;
}
}
public类AwesomePropertyNamingStrategy扩展了PropertyNamingStrategy{
private PropertyNamingStrategy legacyStrategy=PropertyNamingStrategy.LOWER_CASE;
private PropertyNamingStrategy defaultStrategy=PropertyNamingStrategy.CAMEL\u CASE\u TO\u LOWER\u CASE\u,带下划线;
@凌驾
ConstructorParameter的公共字符串名称(MapperConfig配置,AnnotatedParameter ctorParam,String defaultName){
返回getStrategy().nameForConstructorParameter(配置、参数、默认名称);
}
//TODO:为XXX方法实现其他名称
私有财产名称策略getStrategy(){
if(isLegacyEndpoint()){
回归策略;
}否则{
回报策略;
}
}
私有布尔值isLegacyEndpoint(){
//TODO:获取RequestContext或其他一些thead本地上下文
//这允许您知道它是旧端点还是新端点
返回false;
}
}
您应该想出一种在旧模式和新模式之间切换的方法:
通过以某种方式访问请求上下文来使用端点URL
如果旧端点使用不同的响应对象,请使用正在转换的对象的类来确定所有旧类上的遗留/正常或您自己的自定义@LegacyResponse
注释
好吧,经过多次尝试,什么都没用。最终定义了两个不同的servlet。一个没有任何版本,另一个有v1版本
web.xml
<servlet>
<servlet-name>snake-case</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>snake-case</servlet-name>
<url-pattern>/v1</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>camel-case</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>camel-case</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<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>
<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>
蛇壳
org.springframework.web.servlet.DispatcherServlet
1.
蛇壳
/v1
骆驼箱
org.springframework.web.servlet.DispatcherServlet
1.
骆驼箱
/
相应地定义了两个servlet snake-case-servlet.xml和camel-case-servlet.xml
snake-case-servlet.xml
<servlet>
<servlet-name>snake-case</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>snake-case</servlet-name>
<url-pattern>/v1</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>camel-case</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>camel-case</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<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>
<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>
camel-case-servlet.xml
<servlet>
<servlet-name>snake-case</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>snake-case</servlet-name>
<url-pattern>/v1</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>camel-case</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>camel-case</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<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>
<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>
现在,对于使用/v1*的任何请求,将使用snakeCaseObjectMapper,对于其他请求,将使用默认对象映射器。请添加spring xml配置或更多支持代码。感谢您的回复。我试着照你的建议去做。我已经创建了一个消息转换器,并按照您的建议传递customObjectMapper和设置awesomePropertyName策略。但我得到的回应是小案件和蛇案策略的混合。我需要做些什么来解决这个问题吗?你能分享你提出的解决方案吗,特别是你区分传统和新的部分吗?我正在类中自动连接HttpServletRequest请求并加载AwesomePropertyNa