fastjson+mybatis-plus中枚舉類的使用

fastjson+mybatis-plus中枚舉類的使用

在使用mybaits-plus中(官網鏈接:鏈接)的時候,有個枚舉類的功能的十分常見,因爲在實際開發中,少不了約定一些狀態碼以及特殊含義的數字等,這就與枚舉類中的意義相同,fastjson+mybatis-plus可以讓實際開發中

  1. 動態轉換成相應的描述,無需進行顯式、重複的狀態轉換
  2. 約定需修改時,也方便統一修改

一、 定義枚舉類

  • 要點
  1. 建議實現 IEnum<T>接口
  2. @EnumValue標記在數據庫存的字段上,下述例子數據存的就是 code字段,即 0,1
  3. 重寫toString方法,返回相應的描述,這個在序列化時會替換成這個描述
package com.example.demo.user.enumClass;

import com.baomidou.mybatisplus.annotation.EnumValue;
import com.baomidou.mybatisplus.core.enums.IEnum;

/**
 * Create by Lingo
 */
//@JSONType(serializeEnumAsJavaBean = true)
public enum  GenderEnum implements IEnum<Integer> {
    MALE(1,"男"),
    FEMALE(0,"女");
    @EnumValue
    private final int code;
    private final String descp;
    GenderEnum(int code, String descp) {
        this.code = code;
        this.descp = descp;
    }
    @Override
    public String toString() {
        return this.descp;
    }
    @Override
    public Integer getValue() {
        return code;
    }
}

二、 定義實體類

  • 要點
  1. 實現Serializable接口,以便可以序列化
  2. 需要轉換的字段的類型應該是 枚舉類,而不是數據庫的類型,如本例的 gender 數據庫的類型是tinyint(1),而定義的時候類型是GenderEnum
  3. 需要轉換的字段應加入 @JSONField(serialzeFeatures= SerializerFeature.WriteEnumUsingToString)註解,以便進行局部設置
package com.example.demo.user.entity;

import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.example.demo.user.enumClass.GenderEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

import java.io.Serializable;

/**
 * @author Lingo
 * @since 2019-08-06
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="User對象", description="")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;
    private String name;
    private Integer age;
    private String email;
    
    @JSONField(serialzeFeatures= SerializerFeature.WriteEnumUsingToString)
    private GenderEnum gender;
    // setter/getter方法已經由lombok 在編譯時自動生成
}

實體類\Controller\Service都可以使用Mybatis-plusCodeGenerator來自動生成,此處不再演示,具體請看Mybatis-plus的官網

三、配置 Mybatis-plus

# application.yml
# 指定掃描枚舉類所在包
mybatis-plus:
  type-enums-package: com.example.demo.user.enumClass

四 、測試類

  • 要點
  1. 要使用Json.toJsonString的方法才能獲取描述(調用枚舉類的toString方法)。當使用Json.toJson()的時候,則不會替換成描述。原因請看後面
package com.example.demo;

import com.alibaba.fastjson.JSON;
import com.example.demo.user.entity.User;
import com.example.demo.user.service.IUserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    @Autowired
    IUserService userService;

    @Test
    public void selectList1(){
        System.out.println("----------test1--------------");
        List<User> userList = userService.lambdaQuery().list();
        for (User user : userList) {
            System.out.println(JSON.toJSONString(user));
        }
    }

    @Test
    public void selectList2(){
        System.out.println("----------test2--------------");
        List<User> userList = userService.lambdaQuery().list();
        for (User user : userList) {
            System.out.println(JSON.toJSON(user));
        }
    }

    @Test
    public void selectList3() {
        System.out.println("----------test3--------------");
        List<User> userList = userService.lambdaQuery().list();
        for (User user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void selectList4() {
        System.out.println("----------test4--------------");
        List<User> userList = userService.lambdaQuery().list();
        userList.forEach(System.out::println);
    }
}

結果

----------test1--------------
{"age":24,"email":"[email protected]","gender":"女","name":"Jone"}
{"age":24,"email":"[email protected]","gender":"女","name":"Jack"}
{"age":24,"email":"[email protected]","gender":"男","name":"Tom"}
{"age":24,"email":"[email protected]","gender":"男","name":"Sandy"}
{"age":24,"email":"[email protected]","gender":"女","name":"Billie"}
----------test2--------------
{"gender":"FEMALE","name":"Jone","age":24,"email":"[email protected]"}
{"gender":"FEMALE","name":"Jack","age":24,"email":"[email protected]"}
{"gender":"MALE","name":"Tom","age":24,"email":"[email protected]"}
{"gender":"MALE","name":"Sandy","age":24,"email":"[email protected]"}
{"gender":"FEMALE","name":"Billie","age":24,"email":"[email protected]"}
----------test3--------------
User(name=Jone, age=24, [email protected], gender=女)
User(name=Jack, age=24, [email protected], gender=女)
User(name=Tom, age=24, [email protected], gender=男)
User(name=Sandy, age=24, [email protected], gender=男)
User(name=Billie, age=24, [email protected], gender=女)
----------test4--------------
User(name=Jone, age=24, [email protected], gender=女)
User(name=Jack, age=24, [email protected], gender=女)
User(name=Tom, age=24, [email protected], gender=男)
User(name=Sandy, age=24, [email protected], gender=男)
User(name=Billie, age=24, [email protected], gender=女)

五、 Controller中返回Json

package com.example.demo.user.controller;

import com.alibaba.fastjson.JSON;
import com.example.demo.user.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Lingo
 * @since 2019-08-06
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    IUserService userService;

    @RequestMapping("/list")
    public Object list(){
    // 至於爲什麼要先變成JSONString 再組裝成 JSON,請看後文
        return JSON.toJSON(JSON.toJSONString(userService.lambdaQuery().list()));
    }
}

結果
前端調用結果

爲什麼要先用toJsonString再組裝成Json對象

JSON.toJSONString()

在研究toJsonString()方法的時候,發現fastjson自己也有一個ObjectSerializer的對象池,當你在實體類中標記了@JSONField註解的時候,它就會根據 實體類的類型返回相對應的ObjectSerializer(序列化器),先看以下代碼:

public final void write(Object object) {
        if (object == null) {
            this.out.writeNull();
        } else {
            Class<?> clazz = object.getClass();
            ObjectSerializer writer = this.getObjectWriter(clazz); //  1 號代碼

            try {
                writer.write(this, object, (Object)null, (Type)null, 0);  // 2號代碼
            } catch (IOException var5) {
                throw new JSONException(var5.getMessage(), var5);
            }
        }
    }
  1. 當實體類中有 @JSONField註解時,1 號代碼中將會返回 JavaBeanSerializer,此時2號代碼將會調用 javaBeanSerializer的write 方法,期間,FieldSerializer會判斷這個Field是不是Enum,如果是,則取 toString的值。關鍵代碼如下:
    if (this.fieldInfo.isEnum) { //here
    	if (this.writeEnumUsingName) {
    		serializer.out.writeString(((Enum)propertyValue).name());
    		return;
    	}
    	if (this.writeEnumUsingToString) {
    		serializer.out.writeString(((Enum)propertyValue).toString());
    		return;
    	}
    }
    
  2. 當實體類中有 @JSONField註解時,1 號代碼中將會返回 ASMSerializer_x_xxx如(ASMSerializer_1_User),估計是在項目初始化的期間通過反射產生的,斷點調試時此時2號代碼會調用Serializable.writeDirect()方法,由於在代碼上這個方法是返回 boolean類型的,且名稱也不對,並沒有對輸出做什麼操作,猜測是使用了Aop技術(具體是什麼沒有做深入研究)。這裏會直接將所有的Field值轉成json格式,而fastjson是默認使用Name屬性的,如本例的(MALE/FEMALE)

JSON.toJSON()

toJson時直接返回name屬性

if (clazz.isEnum()) {
	return ((Enum)javaObject).name();
}

正是這行代碼決定了 JSON.toJSON() 返回的是枚舉類的Name 屬性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章