Mybatis-Plus通用枚举功能 [MyBatis-Plus系列] - 第493篇

历史文章(文章累计490+)

《国内最全的Spring Boot系列之一》

《国内最全的Spring Boot系列之二》

《国内最全的Spring Boot系列之三》

《国内最全的Spring Boot系列之四》

《国内最全的Spring Boot系列之五》

《国内最全的Spring Boot系列之六》

SpringBoot集成MyBatis-Plus + MyBatis-Plus代码生成器[MP系列] - 第490篇

MyBatis-Plus主键生成策略[MyBatis-Plus系列] - 第491篇

MyBatis-Plus实现逻辑删除[MyBatis-Plus系列] - 492篇

悟纤:师傅,你觉得生命的本质是什么?

师傅:生命的本质是能量

师傅:喜怒哀乐都是能量

师傅:话语是能量的载体

师傅:平和的语气,合适的词语,都会安抚心灵。

师傅:如果话语太锋利了,就会影响对方的情绪和心情,也就是能量紊乱

悟纤:那两个人相处之道,不就是需要注意使用平和的语气和用合适的词语来表达了?

师傅:平和的语气能够让人听着很舒服,情绪不容易上头。

师傅:不同的词语虽然都能够表达清楚意思,但用合适的词语,听起来让人觉得舒服的词语进行表达,能够让人在心里上更加愿意去接受。

悟纤:听师傅一席话,胜读十年书。

导读

Hi,大家好,我是悟纤。过着爱谁谁的生活,活出不设限的人生。

通常在开发中,有这样的需求:枚举类型存入数据库存的是编码code,然而返回给前端的时候是名称name,我们每次入库的时候都要getCode()以及返回给前端的时候要getName(),很繁琐,并且字段属于那种枚举类型的可读性也不高

基于以上问题:我们会尝试着定制一些逻辑专门去处理,一般是自定义枚举转换器实现,然而mybatis-plus提供了优雅的实现方式。

一、枚举的使用场景和好处

在实际的使用当中,当某个对象或者某个属性,需要有多个可供选择的状态或者描述,例如人的性别支付的状态错误的类型等等,都可以使用枚举。

好处:

(1)可读性高, 易理解。

(2)统一参数类型,避免传参错误。

(3)线程安全,全局唯一,无法修改。

二、版本区别

Mybatis-Plus 不同的版本,通用枚举配置是不一样的,稍早一些的需要实现 IEnum 接口,并且需要在配置文件中配置 typeEnumsPackage 或者编写配置类,这难免有些复杂。

而 Mybatis-Plus 从 3.5.2 版本开始只需使用 @EnumValue 注解枚举属性,简单来说就是一个注解解决了一系列配置,本文也将讲解 @EnumValue 注解枚举属性这种方式!

三、通用枚举实战

接下来用具体的例子看一下mybatis-plus通用枚举的使用。

3.1定义枚举

3.1.1方式1:@EnumValue标注入库映射字段

使用注解@EnumValue定义存储到数据库的值:

package com.kfit.user.enums;import com.baomidou.mybatisplus.annotation.EnumValue;import com.fasterxml.jackson.annotation.JsonValue;/** * author:悟纤「公众号SpringBoot」 * date:2023/9/15 */public enum GradeEnum {    PRIMARY(1, "小学"),    SECONDORY(2, "中学"),    HIGH(3, "高中");    @EnumValue//标记数据库存的值是code    private final int code;    @JsonValue //标注该字段要开启自定义序列化返回值    private final String desc;    GradeEnum(int code, String desc) {        this.code = code;        this.desc = desc;    }}

说明:注解@JsonValue注解是开启序列化返回的值。

3.1.2方式2:枚举属性实现 IEnum 接口

实现接口IEnum定义存储到数据库的值:

package com.kfit.user.enums;import com.baomidou.mybatisplus.annotation.IEnum;import com.fasterxml.jackson.annotation.JsonValue;/** * author:悟纤「公众号SpringBoot」 * date:2023/9/15 */public enum AgeEnum implements IEnum<Integer> {    ONE(1, "一岁"),    TWO(2, "二岁"),    THREE(3, "三岁");    private int value;    @JsonValue //标注该字段要开启自定义序列化返回值    private String desc;    AgeEnum(int value, String desc) {        this.value = value;        this.desc = desc;    }    @Override    public Integer getValue() {        return this.value;    }//    @Override//    public String toString() {//        return this.desc;//    }}

说明:上面两种方式定义的枚举都是可以的,使用注解@EnumValue在使用起来会更简单一些。

3.2 在实体类中使用枚举

在需要的实体类中使用上面定义的枚举,这里重新创建一个实体类:

package com.kfit.user.model;import com.kfit.user.enums.AgeEnum;import com.kfit.user.enums.GradeEnum;import lombok.Data;/** * author:悟纤「公众号SpringBoot」 * date:2023/9/15 */@Datapublic class Student {    private Long id;    private String name;    /**     * 年龄,IEnum接口的枚举处理     * 数据库字段:age INT(3)     */    private AgeEnum age;    /**     * 年级,原生枚举(带{@link com.baomidou.mybatisplus.annotation.EnumValue}):     * 数据库字段:grade INT(2)     */    private GradeEnum grade;}

3.3 定义Mapper

由于实体类是新的,定义个Mapper进行数据库的操作,如果是在原实体添加的忽略这一个步骤:

package com.kfit.user.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.kfit.user.model.Student;/** * author:悟纤「公众号SpringBoot」 * date:2023/9/15 */public interface StudentMapper extends BaseMapper<Student> {}

3.4 在表中添加对应的列

在表中添加对应的列,这里实体类是新的,需要创建一个表:

CREATE TABLE student (     `id` bigint(0) NOT NULL AUTO_INCREMENT,     `name` varchar(255) NULL,     `age` int(3) NULL,     `grade` int(2) NULL,     PRIMARY KEY (`id`));

3.5 后端测试

接下来进行简单的后端测试。

3.5.1 保存测试

先来看下保存数据的测试:

@Autowiredprivate StudentMapper studentMapper;@Testpublic void testInsert(){    Student student = new Student();    student.setName("张三");    student.setAge(AgeEnum.ONE);    student.setGrade(GradeEnum.HIGH);    studentMapper.insert(student);}

执行结果:

3.5.2 修改测试

看下修改:

@Testpublic void testUpdate(){    Student student = new Student();    student.setId(1L);    student.setName("李四");    student.setAge(AgeEnum.TWO);    student.setGrade(GradeEnum.SECONDORY);    studentMapper.updateById(student);}

运行结果:

3.5.3 查询测试

看下返回的数据情况:

@Testpublic void testSelctById(){    Student student = studentMapper.selectById(1);    System.out.println(student);}

运行结果:

这里显示的希望是中文的描述的话,那么需要重写AgeEnum和GradeEnum的toString()方法:

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

这时候在运行一下:

3.6 前端测试

最后在进行一下前端测试,就是从前端请求到控制层,然后进行操作。

3.6.1 定义一个controller

首先定义controller:

package com.kfit.user.controller;import com.kfit.user.mapper.StudentMapper;import com.kfit.user.model.Student;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * author:悟纤「公众号SpringBoot」 * date:2023/9/15 */@RestController@RequestMapping("/student")public class StudentController {    @Autowired    private StudentMapper studentMapper;}

3.6.2 查询测试

进行查询测试:

@RequestMapping("/select")public Student selectStudent(){    return studentMapper.selectById(1);}

请求地址:

http://127.0.0.1:8080/student/select

请求结果:

结果显示很正常,如果显示的不是中文的话,那么看看有没有在属性上添加了@JsonValue的注解,如果使用的是其它的JSON框架的话,那么对应的是什么注解。

3.6.3 保存测试

编写保存测试代码:

@RequestMapping("/save")public int save(@RequestBody Student student){    return studentMapper.insert(student);}

请求地址:

http://127.0.0.1:8080/student/save

请求体:

{    "name": "wuqian",    "age": "二岁",    "grade": "高中"}

请求结果:

除了 "age": "二岁","age": 1 也能达到相同的效果,需要注意的是:"age": 1 对枚举类的要求苛刻,需要保证枚举数字从0开始并按顺序排列,因为它是按顺序取枚举的。

也就是说:

设置age=0,那么对应的是ONE(1, "一岁");

设置age=1,那么对应的是TWO(2, "二岁");

如果要使用这种方式,最好是code从0开始,并且是顺序排列的,不然可能会出现莫名其妙的错误。

3.6.4 保存测试2

​上面保存是使用的JSON的方式,如果使用get请求地址这样的请求呢?

@RequestMapping("/save1")public int save1(Student student){    return studentMapper.insert(student);}

请求地址:

http://127.0.0.1:8080/student/save1?name=wuqian&age=二岁

请求报错:

Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors<EOL>Field error in object 'student' on field 'age': rejected value [二岁]; codes [typeMismatch.student.age,typeMismatch.age,typeMismatch.com.kfit.user.enums.AgeEnum,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [student.age,age]; arguments []; default message [age]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'com.kfit.user.enums.AgeEnum' for property 'age'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [com.kfit.user.enums.AgeEnum] for value [二岁]; nested exception is java.lang.IllegalArgumentException: No enum constant com.kfit.user.enums.AgeEnum.二岁]]

所以这种方式不能够这样子请求,可以这样子请求:

http://127.0.0.1:8080/student/save1?name=wuqian&age=ONE

请求结果:

那能不能传递value值呢 ?这个就需要重写StringToEnumConverterFactory的,可以自行去了解一下。

小结

本节介绍了MP的通用枚举功能,对于本文的知识重点总结一下:

(1)通用枚举定义的两种方式:其一使用注解@EnumValue;其二实现接口IEnum。

(2)后端测试想要返回对应的描述,可以重写toString()方法。

(3)前端测试想要返回对应的描述,可以添加注解@JsonValue。

(4)如果请求方式是json的方式,那么可以直接进行转换。

(5)如果请求方式是x-www-form-urlencoded,那么要使用name的方式,否则要重写类StringToEnumConverterFactory。

1000道互联网Java工程师面试题

包括了:MyBatis、ZK、Dubbo、EL、Redis、MySQL、并发编程、Java面试、Spring、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题(共 485 页,32W字)

领取方式:关注公众号「SpringBoot」,回复[面试资料]

👍 点赞、转发、评论,伸出你的双手666…


🐜i 你就是你,不一样的小蚂蚁!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/124348.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GB/T 24718-2023 防眩板检测

防眩板是为解决对向车灯眩光&#xff0c;生产制造的安装在高速公路中央分隔带上的一种交通安全产品&#xff0c;多设置于高速公路中央分隔带护栏上或护栏中间&#xff0c;也有一些设置在中央开口活动护栏上&#xff0c;从材质上分钢制防眩板、塑料防眩板、玻璃钢防眩板。 GB/T…

NOIP2023模拟6联测27 点餐

题目大意 有 n n n样菜品&#xff0c;每样菜品都有两个权值 a i a_i ai​和 b i b_i bi​&#xff0c;如果你选择了 k k k个菜品&#xff0c;分别为 p 1 , … , p k p_1,\dots,p_k p1​,…,pk​&#xff0c;则你的花费为 ∑ i 1 k a p i max ⁡ i 1 k b p i \sum\limits_{i…

3D LUT 滤镜 shader 源码分析

最近在做滤镜相关的渲染学习&#xff0c;目前大部分 LUT 滤镜代码实现都是参考由 GPUImage 提供的 LookupFilter 的逻辑&#xff0c;整个代码实现不多。参考网上的博文也有各种解释&#xff0c;参考了大量博文之后终于理解了&#xff0c;所以自己重新整理了一份&#xff0c;方便…

【无标题】Linux VMware安装centos之后设置静态IP

查看本地IP&#xff1a;ip addr;修改启动协议BOOTPROTOstatic&#xff1b;手动配置IP地址&#xff1b;vi /etc/sysconfig/network-scripts/ifcfg-ens33在最下面增加如下配置 # IP地址 &#xff08;根据自己的环境修改&#xff09; IPADDR192.168.8.101 # 子网掩码 NETMASK255.…

JMeter的使用——傻瓜式学习【中】

目录 前言 1、JMeter参数化 1.1、什么是参数化 1.2、用户定义的变量 1.2.1、什么时候使用用户定义的变量 1.2.2、使用“用户定义的变量”进行参数化的步骤&#xff1a; 1.2.3、案例 1.3、用户参数 1.3.1、什么时候使用用户参数&#xff1f; 1.3.2、使用“用户参数”进…

C现代方法(第15章)笔记——编写大型程序

文章目录 第15章 编写大型程序15.1 源文件15.2 头文件15.2.1 #include指令15.2.2 共享宏定义和类型定义15.2.3 共享函数原型15.2.4 共享变量声明15.2.5 嵌套包含15.2.6 保护头文件15.2.7 头文件中的#error指令 15.3 把程序划分成多个文件15.4 构建多文件程序15.4.1 makefile15.…

10、设置视图组件的Head页面头部标签信息

export default {name: "IndexPage",head() {return {title: "中华小英雄电影第二部",bodyAttrs: {style: "background-color: red;",},meta: [// hid覆盖同名的meta信息{ hid: "description", name: "这是一个关于上学励志教育故…

JSON和Protobuf序列化

文章目录 一、粘包和拆包1、半包问题2、半包现象原理 二、JSON协议通信1、通用类库2、JSON传输的编码器和解码器 三、Protobuf协议通信1、一个简单的proto文件的实践案例2、生成POJO和Builder3、消息POJO和Builder的使用案例1&#xff09;构造POJO消息对象2&#xff09;序列化和…

LeetCode 面试题 16.06. 最小差

文章目录 一、题目二、C# 题解 一、题目 给定两个整数数组 a 和 b&#xff0c;计算具有最小差绝对值的一对数值&#xff08;每个数组中取一个值&#xff09;&#xff0c;并返回该对数值的差 示例&#xff1a; 输入&#xff1a;{1, 3, 15, 11, 2}, {23, 127, 235, 19, 8} 输出&…

基于时间的一次性密码 TOTP 详解

什么是基于时间的一次性密码 TOTP ? 基于时间的一次性密码 TOTP&#xff08;Time-Based One-Time Password&#xff09;&#xff0c;也被称为时间同步动态密码&#xff0c;是一种基于时间的一次性密码算法&#xff0c;通常用于两步验证和多因素身份验证&#xff0c;用于增强静…

【CSDN 每日一练 ★★☆】【二叉树/BSF】二叉树的层序遍历

【CSDN 每日一练 ★★☆】【二叉树/BSF】二叉树的层序遍历 二叉树 BSF 题目 给你一个二叉树&#xff0c;请你返回其按 层序遍历 得到的节点值。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例&#xff1a; 二叉树&#xff1a;[3,9,20,null,nul…

Android Studio Giraffe 添加 maven { url “https://jitpack.io“ }报错

Android Studio Giraffe 添加 maven { url “https://jitpack.io” }报错 settings.gradle.kts:13:21: Unexpected tokens (use ; to separate expressions on the same line)解决方法 新版maven写法发生了改变&#xff1a; maven { url uri("https://jitpack.io"…

VScode 调试 linux内核

VScode 调试 linux内核 这里调试的 linux 内核是通过 LinuxSD卡(rootfs)运行的内核 gdb 命令行调试 编辑 /home/tyustli/.gdbinit 文件&#xff0c;参考 【GDB】 .gdbinit 文件 set auto-load safe-path /home/tyustli/code/open_source/kernel/linux-6.5.7/.gdbinit在 lin…

PFAF-Net

I 1 _1 1​和I 2 _2 2​是多模态图像&#xff0c;I F _F F​是融合图像。FT 1 _1 1​是基于空间注意力的融合&#xff0c;FT 2 _2 2​是基于通道注意力的融合 作者未提供代码

docker的安装部署nginx和mysql

小白自己整理&#xff0c;如有错误请指示&#xff01; 自我理解&#xff1a;docker就是把应用程序所用的依赖程序&#xff0c;函数库等相关文件打包成镜像文件&#xff0c;类似系统光盘&#xff0c;然后可以在任意电脑上安装使用&#xff08;方便运维人员部署程序&#xff09;…

jenkins+sonar

参考&#xff1a; 1、jenkins集成sonar 1&#xff09;jenkins集成sonar流水线部署 jenkins集成sonar流水线部署_sonar jenkins-CSDN博客 2&#xff09;jenkinssonar 实现代码检测 jenkinssonar 实现代码检测_jenkins sonar_dsdasun的博客-CSDN博客 2、配置&#xff1a;son…

论文阅读——RoBERTa

一、LM效果好但是各种方法之间细致比较有挑战性&#xff0c;因为训练耗费资源多、并且在私有的不同大小的数据集上训练&#xff0c;不同超参数选择对结果影响很大。使用复制研究的方法对BERT预训练的超参数和数据集的影响细致研究&#xff0c;发现BERT训练不够&#xff0c;提出…

《Effective Java》读书笔记(1-2章)

第一章 创建和销毁对象 1. 考虑用静态代替构造方法 想要获取一个类的实例&#xff0c;一种传统的方式是通过共有的构造器&#xff0c;当然还可以使用另一种技术&#xff1a;提供共有的静态工厂方法。 什么是静态工厂&#xff1f; public static Boolean valueOf(boolean b) …

Ansible的安装和部署

目录 1.Ansible的安装 2.构建Ansible清单 直接书写受管主机名或ip 设定受管主机的组[组名称] 主机规格的范围化操作 指定其他清单文件 ansible命令指定清单的正则表达式 3.Ansible配置文件参数详解 配置文件的分类与优先级 常用配置参数 4.构建用户级Ansible操作环…

Spring面试题:(一)IoC,DI,AOP和BeanFactory,ApplicationContext

IoC&#xff0c;DI&#xff0c;AOP思想 IOC就是控制反转&#xff0c;是指创建对象的控制权的转移。以前创建对象的主动权和时机是由自己把控的&#xff0c;而现在这种权力转移到Spring容器中&#xff0c;并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系。对象与对…