一個極易踩坑的例子,希望大家引以為戒

程序员博博發表於2024-11-23

前言

最近在寫需求的過程中,需要返回給前端一個欄位,表示賬單是否結清,那麼理所當然的我把這個欄位命名為了isSettle

踩坑過程

明眼人一看就知道問題所在,非常經典的錯誤,當時聊天記錄大概是這樣的。

後端:這個欄位一直顯示錯誤,有空幫忙看下
前端:你這邊返回的是settle,我看文件上是isSettle
後端:好的,我去看下文件
a few seconds later
後端:靠,有坑,我修改下

非常經典的錯誤,我當時一看就立馬明白是序列化的問題。之前一直知道有這個坑,寫的時候沒太注意,差點釀成了大禍,這可是直接給使用者看的,賬單是否結清,非常重要的一個欄位。

原理

在java的世界裡,尤其是java web的世界裡面。框架幫我們承擔了一切,尤其是springboot的出現,更加降低了入門門檻。基本都是spring一把梭,上來就是spring全家桶。

這對打工人的確有好處,因為可以專心於業務,但是因為封裝的太好了,導致現在很多人其實不清楚其中的原理,框架幫你做了什麼,如果出了問題,你如何解決,這些都是培訓班or應屆生欠缺的,迴歸正題。

後端返回給前端,其中springmvc會幫我們將資料進行一個轉換。具體的轉化器是在這裡MappingJackson2HttpMessageConverter。它是在springboot啟動的時候,透過自動裝配WebMvcAutoConfiguration就載入到spring容器中了,而其中預設使用的序列化就是jackson。

例子1

我現在有一個person類如下

@Data
public class Person {
    private int age;
    private String name;
    private boolean isSettle; // isxxx需注意
}

使用主流的json轉化器如下

Person person = new Person();
person.setAge(18);
person.setName("zhangsan");
person.setSettle(true);

// 1. gson
System.out.println("gson -->  " + GsonUtils.toJson(person));

// 2. fastjson
System.out.println("fastjson -->  " + JSON.toJSONString(person));

// 3. fastjson2
System.out.println("fastjson2 -->  " + com.alibaba.fastjson2.JSON.toJSONString(person));

// 4. jackson
ObjectMapper objectMapper = new ObjectMapper();
System.out.println("jackson -->  " + objectMapper.writeValueAsString(person));

結果如下。我們發覺除了gson是以isXxx輸出,其他的全部把is給預設去掉了

gson -->  {"age":18,"name":"zhangsan","isSettle":true}
fastjson -->  {"age":18,"name":"zhangsan","settle":true}
fastjson2 -->  {"age":18,"name":"zhangsan","settle":true}
jackson -->  {"age":18,"name":"zhangsan","settle":true}

例子2

我們嘗試去修改springmvc的序列化轉換器。非常簡單,修改MessageConverters即可。
其中PrettyPrinting是為了更加方便看出修改gson已經成功了

@Configuration
public class MessageConverterConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
       converters.clear();  // 移除jackson,或者在pom中完全排除jackson
       GsonHttpMessageConverter gsonConverter = new GsonHttpMessageConverter();
       gsonConverter.setGson(new GsonBuilder().setPrettyPrinting().create()); // setPrettyPrinting 明確可以看出使用了gson
       converters.add(gsonConverter);
    }
}

我們現在有一個controller介面如下

@RequestMapping("/test/message")
public Person test() {
    Person person = new Person();
    person.setAge(18);
    person.setName("zhangsan");
    person.setOk(true);
    return person;
}

結果如下。發覺boolean isOk的值返回完全不同了,一個是有is,一個是沒有is的,符合我們的預期

預設jackson的輸入  --> {"name":"zhangsan","age":18,"ok":true}

修改成gson轉換器的輸出 -->  
{
  "name": "zhangsan",
  "age": 18,
  "isOk": true
}

最後

這是一個非常非常簡單基礎的例子,其實稍微有點經驗的程式設計師都應該避免,只是有時候大意疏忽會導致各種各樣的問題。本質上我還是想提醒大家,雖然框架幫助我們做了很多,但我們還是需要理解其底層實現原理,每當出現問題的時候,如果你懂原理,非常容易的可以快速解決問題,這也是高階程式設計師和碼農的一個區別吧。其中在阿里的規約裡面,已經明確禁止使用isxxx這種命名方式。

最後祝所有程式設計師,寫的程式碼無bug,世界上不再有bug出現。

相關文章