fastjson+mybatis-plus中枚舉類的使用
在使用mybaits-plus中(官網鏈接:鏈接)的時候,有個枚舉類的功能的十分常見,因爲在實際開發中,少不了約定一些狀態碼以及特殊含義的數字等,這就與枚舉類中的意義相同,fastjson+mybatis-plus可以讓實際開發中
- 動態轉換成相應的描述,無需進行顯式、重複的狀態轉換
- 約定需修改時,也方便統一修改
一、 定義枚舉類
- 要點
- 建議實現
IEnum<T>
接口 @EnumValue
標記在數據庫存的字段上,下述例子數據存的就是 code字段,即 0,1- 重寫
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;
}
}
二、 定義實體類
- 要點
- 實現
Serializable
接口,以便可以序列化 - 需要轉換的字段的類型應該是 枚舉類,而不是數據庫的類型,如本例的 gender 數據庫的類型是
tinyint(1)
,而定義的時候類型是GenderEnum
- 需要轉換的字段應加入
@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-plus
的CodeGenerator
來自動生成,此處不再演示,具體請看Mybatis-plus
的官網
三、配置 Mybatis-plus
# application.yml
# 指定掃描枚舉類所在包
mybatis-plus:
type-enums-package: com.example.demo.user.enumClass
四 、測試類
- 要點
- 要使用
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);
}
}
}
- 當實體類中有
@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; } }
- 當實體類中有
@JSONField
註解時,1 號代碼中將會返回ASMSerializer_x_xxx
如(ASMSerializer_1_User
),估計是在項目初始化的期間通過反射產生的,斷點調試時此時2號代碼會調用Serializable.writeDirect()
方法,由於在代碼上這個方法是返回 boolean類型的,且名稱也不對,並沒有對輸出做什麼操作,猜測是使用了Aop技術(具體是什麼沒有做深入研究)。這裏會直接將所有的Field
值轉成json格式,而fastjson是默認使用Name
屬性的,如本例的(MALE/FEMALE
)
JSON.toJSON()
if (clazz.isEnum()) {
return ((Enum)javaObject).name();
}
正是這行代碼決定了 JSON.toJSON()
返回的是枚舉類的Name 屬性。