一个极易踩坑的例子,希望大家引以为戒

时间:2024-11-23 21:05:03

前言

最近在写需求的过程中,需要返回给前端一个字段,表示账单是否结清,那么理所当然的我把这个字段命名为了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出现。