首页 » java

springboot mybatisplus enum 枚举返回中文描述, 动态转换成相应的描述

   发表于:java评论 ()   热度:113

springboot mybatisplus enum 枚举返回描述

背景:  我根据例子写了个 枚举类 ArticleStateEnum  然后在实体类 Article 中的 articleState 字段得类型改成  ArticleStateEnum 然后运行查询的时候,  返回的是枚举类的 "变量名字"

例如:  NotReviewed(0, "未审核") 这里  NotReviewed 就是变量名, 

其实这里返回的是枚举类一条数据的一个对象比如NotReviewed(0, "未审核")"返回的是这一条数据的对象,然后你可以 用这个对象 调用 如下枚举类中的"getCode()" 和  "getDesc()" 等方法, 但是这对象转成json输出后 就  只剩了 变量名  NotReviewed 了, 我想要  json输出  "未审核  

但是我 想要 在查询中返回的是 描述 即 "NotReviewed(0, "未审核") 中的"未审核"这几个字

解决:  在枚举类里  加一个  public String toString()  方法  具体如下  枚举类 中  然后在实体类相应的   字段 上方添加注解   @JSONField(serialzeFeatures= SerializerFeature.WriteEnumUsingToString)  如下实体类中  然后重启运行 , 状态输出中文了

枚举类:

package com.wenhe.blogdao.model.enums;

import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.Getter;
import java.util.Objects;

@Getter
public enum ArticleStateEnum  {

    NotReviewed(0, "未审核"),
    Reviewed(1, "审核通过"),
    Reject(2, "驳回");

    @EnumValue
    private final Integer code;

    public int getCode() {
        return this.code;
    }
    @JsonValue
    private final String desc;

    public String getDesc(){
        return desc;
    }

    ArticleStateEnum(Integer code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public static   String getDesc(int code) {
        for (ArticleStateEnum value : ArticleStateEnum.values()) {
            if (Objects.equals(code, value.getCode())) {
                return value.getDesc();
            }
        }
        return null;
    }

    @Override
    public String toString() {
        return this.desc;
    }
}

实体类:

package com.wenhe.blogdao.model;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import java.time.LocalDateTime;
import java.io.Serializable;
import com.wenhe.blogdao.model.enums.ArticleStateEnum;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
import lombok.experimental.Accessors;


@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("bk_article")
public class Article extends Model<Article> {

    private static final long serialVersionUID = 1L;


    @TableId(value = "article_id", type = IdType.AUTO)
    private Integer articleId;


    /**
     * 0 未审核 不显示  ,, 1  会员发布未审核,,2 审核通过 ,, 3 草稿箱 ,, 4回收站  ,,
     */
    @JSONField(serialzeFeatures= SerializerFeature.WriteEnumUsingToString)
    @TableField("article_state")
    private ArticleStateEnum articleState;


    @Override
    protected Serializable pkVal() {
        return this.articleId;
    }

}

application.yml mybatisplus 配置
 

mybatis-plus:
  mapper-locations: classpath*:com/wenhe/blogdao/mapper/mapping/**.xml
  type-aliases-package: com.wenhe.blogdao.model
  global-config:
    db-config:
      id-type: AUTO  #0:数据库ID自增   1:用户输入id  2:全局唯一id(IdWorker)  3:全局唯一ID(uuid)
      logic-delete-value: 0
      logic-not-delete-value: 1

  configuration:
    map-underscore-to-camel-case: false
    cache-enabled: true #配置的缓存的全局开关
    lazyLoadingEnabled: true #延时加载的开关
    multipleResultSetsEnabled: true #开启的话,延时加载一个属性时会加载该对象全部属性,否则按需加载属性
    default-enum-type-handler: org.apache.ibatis.type.EnumOrdinalTypeHandler
  type-enums-package: com.wenhe.blogdao.model.enums
#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印sql语句,调试用

 

参考资料

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":"test1@baomidou.com","gender":"女","name":"Jone"}
{"age":24,"email":"test2@baomidou.com","gender":"女","name":"Jack"}
{"age":24,"email":"test3@baomidou.com","gender":"男","name":"Tom"}
{"age":24,"email":"test4@baomidou.com","gender":"男","name":"Sandy"}
{"age":24,"email":"test5@baomidou.com","gender":"女","name":"Billie"}
----------test2--------------
{"gender":"FEMALE","name":"Jone","age":24,"email":"test1@baomidou.com"}
{"gender":"FEMALE","name":"Jack","age":24,"email":"test2@baomidou.com"}
{"gender":"MALE","name":"Tom","age":24,"email":"test3@baomidou.com"}
{"gender":"MALE","name":"Sandy","age":24,"email":"test4@baomidou.com"}
{"gender":"FEMALE","name":"Billie","age":24,"email":"test5@baomidou.com"}
----------test3--------------
User(name=Jone, age=24, email=test1@baomidou.com, gender=女)
User(name=Jack, age=24, email=test2@baomidou.com, gender=女)
User(name=Tom, age=24, email=test3@baomidou.com, gender=男)
User(name=Sandy, age=24, email=test4@baomidou.com, gender=男)
User(name=Billie, age=24, email=test5@baomidou.com, gender=女)
----------test4--------------
User(name=Jone, age=24, email=test1@baomidou.com, gender=女)
User(name=Jack, age=24, email=test2@baomidou.com, gender=女)
User(name=Tom, age=24, email=test3@baomidou.com, gender=男)
User(name=Sandy, age=24, email=test4@baomidou.com, gender=男)
User(name=Billie, age=24, email=test5@baomidou.com, gender=女)
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();
}

(。・v・。)
喜欢这篇文章吗?欢迎分享到你的微博、QQ群,并关注我们的微博,谢谢支持。