前言
最近在寫需求的過程中,需要返回給前端一個欄位,表示賬單是否結清,那麼理所當然的我把這個欄位命名為了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出現。