前言
最近業務部門接手了外包供應商的專案過來自己運維,該部門的小夥伴發現了一個問題,比如後端的DTO有個屬性名為nPrice的欄位,透過json渲染到前端後,變成nprice,而預期的欄位是要為nPrice。於是他們就找到我們部門,希望我們能幫忙解決一下這個問題,本文就聊聊如何解決問題,至於為什麼會出現這個問題,後面留個彩蛋
解法
注: 本文的json都是透過springboot預設的jackson進行渲染解析,因此本文的解法都是針對jackson
方法一:在屬性欄位上加@JsonProperty註解
示例
@JsonProperty(value = "nPropriceFactory")
private BigDecimal nPropriceFactory;
因為業務接手的專案的欄位的屬性大量都是首字母小寫,第二個字母大寫的形式,比如nHelloWorld,因此業務部門的小夥伴,覺得一個個加太麻煩了,有沒有更簡潔點辦法。於是就有了第二種方法
方法二:透過自定義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
這樣就可以解決了,不過業務部門的研發,基本上都是被慣壞的小孩,為了讓他們更方便的使用,我們就更近一步,也不要在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
自此業務部門只要引入這個包,就可以解決jackson渲染到前端,出現大寫字母變成小寫問題
注:如果用實現org.springframework.boot.env.EnvironmentPostProcessor來實現屬性配置也可以,不過要注意如果使用springcloud,則可能會出現在配置在application.yml的屬性,透過
environment.getProperty(CUSTOM_JSON_FORMAT_ENABLE_KEY);
拿不到值的情況。因此推薦用實現org.springframework.context.ApplicationContextInitializer來進行環境變數獲取或者設定
總結
以上兩種方式,一種是採用區域性的方式,另一種是採用全域性的方式,採用全域性的方式,要做好測試,不然影響很大,我們採用全域性的方式,一來是業務那邊要求,二來是當時我們和業務部門做好溝通,我們根據他們的業務規則來做定製,並跟他們說明採用全域性的方式可能遇到的問題。
至於為啥jackson渲染到前端,出現大寫字母變成小寫問題,大家如果有空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