前言
最近業(yè)務部門接手了外包供應商的項目過來自己運維,該部門的小伙伴發(fā)現(xiàn)了一個問題,比如后端的DTO有個屬性名為nPrice的字段,通過json渲染到前端后,變成nprice,而預期的字段是要為nPrice。于是他們就找到我們部門,希望我們能幫忙解決一下這個問題,本文就聊聊如何解決問題,至于為什么會出現(xiàn)這個問題,后面留個彩蛋
解法
注: 本文的json都是通過springboot默認的jackson進行渲染解析,因此本文的解法都是針對jackson
方法一:在屬性字段上加@JsonProperty注解
示例
@JsonProperty(value = "nPropriceFactory")
private BigDecimal nPropriceFactory;
因為業(yè)務接手的項目的字段的屬性大量都是首字母小寫,第二個字母大寫的形式,比如nHelloWorld,因此業(yè)務部門的小伙伴,覺得一個個加太麻煩了,有沒有更簡潔點辦法。于是就有了第二種方法
方法二:通過自定義
com.fasterxml.jackson.databind.PropertyNamingStrategy策略
具體邏輯形如如下
public class CustomPropertyNamingStrategy extends PropertyNamingStrategy {
@Override
public String nameForGetterMethod(MApperConfig<?> config, AnnotatedMethod method, String defaultName) {
if (isSpecialPropertyName(defaultName)) {
//將屬性的get方法去除get,然后首字母轉小寫
return StringUtils.uncapitalize(method.getName().substring(3));
}
return super.nameForGetterMethod(config,method,defaultName);
}
@Override
public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
if (isSpecialPropertyName(defaultName)) {
//將屬性的set方法去除set,然后首字母轉小寫
return StringUtils.uncapitalize(method.getName().substring(3));
}
return super.nameForSetterMethod(config,method,defaultName);
}
}
在application.yml做如下配置
spring:
jackson:
property-naming-strategy: com.Github.lybgeek.jackson.CustomPropertyNamingStrategy
這樣就可以解決了,不過業(yè)務部門的研發(fā),基本上都是被慣壞的小孩,為了讓他們更方便的使用,我們就更近一步,也不要在yml進行配置了,讓他們直接引入jar就好。于是我們做了如下操作
public final class EnvUtils {
private EnvUtils(){}
private static final String JACKSON_PROPERTY_NAMING_STRATEGY_KEY = "spring.jackson.property-naming-strategy";
public static void postProcessEnvironment(ConfigurableEnvironment environment){
String isCustomJsonFormatEnaled = environment.getProperty(CUSTOM_JSON_FORMAT_ENABLE_KEY,"true");
if("true".equalsIgnoreCase(isCustomJsonFormatEnaled)){
setCustomJacksonPropertyNamingStrategy(environment);
}
}
private static void setCustomJacksonPropertyNamingStrategy(ConfigurableEnvironment environment) {
MutablePropertySources propertySources = environment.getPropertySources();
Map<String, Object> mapPropertySource = new HashMap<>();
mapPropertySource.put(JACKSON_PROPERTY_NAMING_STRATEGY_KEY, CustomPropertyNamingStrategy.class.getName());
PropertySource propertySource = new MapPropertySource("custom-json-format-properties",mapPropertySource);
propertySources.addFirst(propertySource);
}
}
public class CustomJacksonFormatEnvironmentApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
EnvUtils.postProcessEnvironment(environment);
}
}
在resouce下新建META-INF/spring.factories,并指定如下內容
org.springframework.context.ApplicationContextInitializer=
com.github.lybgeek.jackson.env.CustomJacksonFormatEnvironmentApplicationContextInitializer
自此業(yè)務部門只要引入這個包,就可以解決jackson渲染到前端,出現(xiàn)大寫字母變成小寫問題
注:如果用實現(xiàn)
org.springframework.boot.env.EnvironmentPostProcessor來實現(xiàn)屬性配置也可以,不過要注意如果是使用springcloud,則可能會出現(xiàn)在配置在application.yml的屬性,通過
environment.getProperty(CUSTOM_JSON_FORMAT_ENABLE_KEY);
拿不到值的情況。因此推薦用實現(xiàn)
org.springframework.context.ApplicationContextInitializer來進行環(huán)境變量獲取或者設置
總結
以上兩種方式,一種是采用局部的方式,另一種是采用全局的方式,采用全局的方式,要做好測試,不然影響很大,我們采用全局的方式,一來是業(yè)務那邊要求,二來是當時我們和業(yè)務部門做好溝通,我們根據(jù)他們的業(yè)務規(guī)則來做定制,并跟他們說明采用全局的方式可能遇到的問題。
至于為啥jackson渲染到前端,出現(xiàn)大寫字母變成小寫問題,大家如果有空debug跟到
com.fasterxml.jackson.databind.util.BeanUtil#legacyManglePropertyName這個方法,應該就會有答案。如果沒空的話,就可以查看如下鏈接
https://blog.csdn.NET/weixin_42511702/article/details/112520749
進行解讀
demo鏈接
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-json-format