fastjson+mybatis-plus中枚举类的使用

fastjson+mybatis-plus中枚举类的使用

在使用mybaits-plus中(官网链接:链接)的时候,有个枚举类的功能的十分常见,因为在实际开发中,少不了约定一些状态码以及特殊含义的数字等,这就与枚举类中的意义相同,fastjson+mybatis-plus可以让实际开发中

  1. 动态转换成相应的描述,无需进行显式、重复的状态转换
  2. 约定需修改时,也方便统一修改

一、 定义枚举类

  • 要点
  1. 建议实现 IEnum接口
  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 {
    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 userList = userService.lambdaQuery().list();
        for (User user : userList) {
            System.out.println(JSON.toJSONString(user));
        }
    }

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

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

    @Test
    public void selectList4() {
        System.out.println("----------test4--------------");
        List 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()));
    }
}

结果
fastjson+mybatis-plus中枚举类的使用_第1张图片

为什么要先用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 属性。

你可能感兴趣的:(笔记,Java后端,fastJson,枚举类,mybatis-plus)