記一次springboot透過jackson渲染到前端,出現大寫字母變成小寫問題

linyb極客之路發表於2023-04-04

前言

最近業務部門接手了外包供應商的專案過來自己運維,該部門的小夥伴發現了一個問題,比如後端的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

相關文章