在使用MybatisPlus以后,基础的Mapper、Service、PO代码相对固定,重复编写也比较麻烦。因此MybatisPlus官方提供了代码生成器根据数据库表结构生成PO、Mapper、Service等相关代码。只不过代码生成器同样要编码使用,也很麻烦。

这里推荐大家使用一款MybatisPlus的插件,它可以基于图形化界面完成MybatisPlus的代码生成,非常简单。
在Idea的plugins市场中搜索并安装MyBatisPlus插件:

然后重启你的Idea即可使用。
刚好数据库中还有一张address表尚未生成对应的实体和mapper等基础代码。我们利用插件生成一下。
首先需要配置数据库地址,在Idea顶部菜单中,找到other,选择Config Database:

在弹出的窗口中填写数据库连接的基本信息:

点击OK保存。
然后再次点击Idea顶部菜单中的other,然后选择Code Generator:

在弹出的表单中填写信息:

最终,代码自动生成到指定的位置了:

对于一些比较重要的数据,我们往往会采用逻辑删除的方案,即:
一旦采用了逻辑删除,所有的查询和删除逻辑都要跟着变化,非常麻烦。为了解决这个问题,MybatisPlus就添加了对逻辑删除的支持。
注意,只有MybatisPlus生成的SQL语句才支持自动的逻辑删除,自定义SQL需要自己手动处理逻辑删除。
:::
例如,我们给address表添加一个逻辑删除字段:
- alter table address
- add deleted bit default b'0' null comment '逻辑删除';
然后给Address实体添加deleted字段:

接下来,我们要在application.yml中配置逻辑删除字段:
- mybatis-plus:
- global-config:
- db-config:
- logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
- logic-delete-value: 1 # 逻辑已删除值(默认为 1)
- logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
测试:
首先,我们执行一个删除操作:
- @Test
- void testDeleteByLogic() {
- // 删除方法与以前没有区别
- addressService.removeById(59L);
- }
方法与普通删除一模一样,但是底层的SQL逻辑变了:

查询一下试试:
- @Test
- void testQuery() {
- List<Address> list = addressService.list();
- list.forEach(System.out::println);
- }
会发现id为59的确实没有查询出来,而且SQL中也对逻辑删除字段做了判断:

综上, 开启了逻辑删除功能以后,我们就可以像普通删除一样做CRUD,基本不用考虑代码逻辑问题。还是非常方便的。
注意:
逻辑删除本身也有自己的问题,比如:
因此,不太推荐用逻辑删除功能,如果数据不能删除,可以采用把数据迁移到其它表的办法。
User类中有一个用户状态字段:

像这种字段我们一般会定义一个枚举,做业务判断的时候就可以直接基于枚举做比较。但是我们数据库采用的是int类型,对应的PO也是Integer。因此业务操作时必须手动把枚举与Integer转换,非常麻烦。
因此,MybatisPlus提供了一个处理枚举的类型转换器,可以帮我们把枚举类型与数据库类型自动转换。
我们定义一个用户状态的枚举:

代码如下:
- package com.itheima.mp.enums;
-
- import com.baomidou.mybatisplus.annotation.EnumValue;
- import lombok.Getter;
-
- @Getter
- public enum UserStatus {
- NORMAL(1, "正常"),
- FREEZE(2, "冻结")
- ;
- private final int value;
- private final String desc;
-
- UserStatus(int value, String desc) {
- this.value = value;
- this.desc = desc;
- }
- }
然后把User类中的status字段改为UserStatus 类型:

要让MybatisPlus处理枚举与数据库类型自动转换,我们必须告诉MybatisPlus,枚举中的哪个字段的值作为数据库值。
MybatisPlus提供了@EnumValue注解来标记枚举属性:

在application.yaml文件中添加配置:
- mybatis-plus:
- configuration:
- default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
- @Test
- void testService() {
- List<User> list = userService.list();
- list.forEach(System.out::println);
- }
最终,查询出的User类的status字段会是枚举类型:

数据库的user表中有一个info字段,是JSON类型:

格式像这样:
{"age": 20, "intro": "佛系青年", "gender": "male"}
而目前User实体类中却是String类型:

这样以来,我们要读取info中的属性时就非常不方便。如果要方便获取,info的类型最好是一个Map或者实体类。
而一旦我们把info改为对象类型,就需要在写入数据库(Json类型)时手动转为String,再读取数据库时,手动转换为对象,这会非常麻烦。
因此MybatisPlus提供了很多特殊类型字段的类型处理器,解决特殊字段类型与数据库类型转换的问题。例如处理JSON就可以使用JacksonTypeHandler处理器。
选用Jackson的理由:他是JSON处理器最常用的对象

接下来,我们就来看看这个处理器该如何使用。
首先,我们定义一个单独实体类来与info字段的属性匹配:

代码如下:
- package com.itheima.mp.domain.po;
-
- import lombok.Data;
-
- @Data
- public class UserInfo {
- private Integer age;
- private String intro;
- private String gender;
- }
接下来,将User类的info字段修改为UserInfo类型,并声明类型处理器:

第一次测试info没查出来,是因为对象嵌套没配resultMap,要加autoResultMap

第二次测试可以发现,所有数据都正确封装到UserInfo当中了:

目前我们配置文件中的很多参数都是明文,如果开发人员发生流动,很容易导致敏感信息的泄露。所以MybatisPlus支持配置文件的加密和解密功能。
我们以数据库的用户名和密码为例。
首先,我们利用AES工具生成一个随机秘钥,然后对用户名、密码加密:
- package com.itheima.mp;
-
- import com.baomidou.mybatisplus.core.toolkit.AES;
- import org.junit.jupiter.api.Test;
-
- class MpDemoApplicationTests {
- @Test
- void contextLoads() {
- // 生成 16 位随机 AES 密钥
- String randomKey = AES.generateRandomKey();
- System.out.println("randomKey = " + randomKey);
-
- // 利用密钥对用户名加密
- String username = AES.encrypt("root", randomKey);
- System.out.println("username = " + username);
-
- // 利用密钥对用户名加密
- String password = AES.encrypt("MySQL123", randomKey);
- System.out.println("password = " + password);
-
- }
- }
打印结果如下:
- randomKey = 6234633a66fb399f
- username = px2bAbnUfiY8K/IgsKvscg==
- password = FGvCSEaOuga3ulDAsxw68Q==
修改application.yaml文件,把jdbc的用户名、密码修改为刚刚加密生成的密文:
- spring:
- datasource:
- url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
- driver-class-name: com.mysql.cj.jdbc.Driver
- username: mpw:QWWVnk1Oal3258x5rVhaeQ== # 密文要以 mpw:开头
- password: mpw:EUFmeH3cNAzdRGdOQcabWg== # 密文要以 mpw:开头
在启动项目的时候,需要把刚才生成的秘钥添加到启动参数中,像这样:
--mpw.key=6234633a66fb399f
单元测试的时候不能添加启动参数,所以要在测试类的注解上配置:

然后随意运行一个单元测试,可以发现数据库查询正常。
