gpt4 book ai didi

java - 如何根据条件应用Spring消息转换器?

转载 作者:行者123 更新时间:2023-12-02 03:19:56 25 4
gpt4 key购买 nike

我有一个 Controller ,其响应是驼峰式 json 值。现在我们正在用新版本重写代码,所需的响应位于snake_case中。

我添加了消息转换器并修改了对象映射器来设置setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);

public class ResponseJSONConverter extends MappingJackson2HttpMessageConverter {

@Autowired
public ResponseJSONConverter(ObjectMapper objectMapper) {
setObjectMapper(objectMapper);
}
}

我已经向 spring 注册了这个转换器,并且它按预期工作。现在,我希望我的旧端点以驼峰命名法返回,以便向后兼容我的消费者,并以蛇形命名法返回新端点。

我尝试再使用一个带有简单对象映射器的消息转换器,而无需将camelCase设置为Snake case属性并在spring中注册。根据 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>

编辑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>

自定义消息转换器

    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");
}
}

最佳答案

我建议创建一个 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;
}
}

您应该想出一种在旧模式和新模式之间切换的方法:

  1. 通过以某种方式访问​​请求上下文来使用端点 URL
  2. 如果您的旧端点使用不同的响应对象,请使用正在转换的对象的类来确定旧类/普通类或您自己的所有旧类上的自定义 @LegacyResponse 注释。<

关于java - 如何根据条件应用Spring消息转换器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42219676/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com