Mybatis-Plus mybatis-plus学习笔记,参考B站视频 
参考博客 
Mybatis-Plus官方文档 
快速入门 使用mybatis-plus的基础步骤 
引入mybatisPlus的Maven依赖,代替原始Mybatis依赖
1 2 3 4 5 <dependency >     <groupId > com.baomidou</groupId >      <artifactId > mybatis-plus-boot-starter</artifactId >      <version > 3.5.3.1</version >  </dependency > 
定义Mapper接口继承自BaseMapper
1 2 3 4 public  interface  UserMapper  extends  BaseMapper <User> {} 
单元测试即可直接使用
mapper存在一系列增删改查的方法可以直接调用
 
小插曲 
测试如下方法
1 2 3 4 5 @Test void  testQueryByIds ()  {    List<User> users = userMapper.selectBatchIds(List.of(1L , 2L , 3L , 4L ));     users.forEach(System.out::println); } 
一直报错:
1 java: 找不到符号   符号:   方法 of(long,long,long,long)   位置: 接口 java.util.List 
原因:
List.of()是JDK9之后才有的版本
解决方法:提升java编译的JDK版本
修改如下位置(注意:无论修改ProjectStructure还是pom.xml中的java版本均无效)
常见注解 MyBatisPlus 通过扫描实体类,并基于反射获取实体类信息作为数据库表信息。
基本约定 
常用注解 
@TableName :用来指定表名@TableId :用来指定表中的主键字段信息@TableField :用来指定表中的普通字段信息 
注意的点:
当实体类和数据库不满足既定的约定的话,就必须要使用对应的注解
对于@TableId是用来指定主键字段,对于数据库中主键存在一些属性(比如自增),所以注解中有时也要注明主键类型
IdType枚举:
AUTO:数据库自增长 
INPUT:通过set方法自行输入 
ASSIGN_ID:分配 ID,接口IdentifierGenerator的方法nextId来生成id,默认实现类为DefaultIdentifierGenerator雪花算法 
 
 
默认采用雪花算法 
 
 
使用@TableField的常见场景:
成员变量名与数据库字段名不一致 
成员变量名以is开头,且是布尔值
 
成员变量名与数据库关键字冲突
 
成员变量不是数据库字段
 
 
 
 
常见配置 MyBatisPlus 的配置项继承了MyBatis原生配置和一些自己特有的配置。
1 2 3 4 5 6 7 8 9 10 mybatis-plus: 	type-aliases-package: com.itheima.mp.domain.po # 别名扫描包 	mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper.xml文件地址,默认值 	configuration: 		map-underscore-to-camel-case: true # 是否开启下划线和驼峰的映射 		cache-enabled: false # 是否开启二级缓存  	global-config: 		db-config: 			id-type: assign_id # id为雪花算法生成 			update-strategy: not_null # 更新策略:只更新非空字段 
具体可参考官方文档:使用配置  | MyBatis-Plus (baomidou.com) 
总结 Mybatis-Plus使用的基本流程
引入起步依赖 
自定义Mapper,继承自BaseMapper 
在实体类上添加注解申明信息 
在application.yml中根据需要添加配置 
 
核心功能 条件构造器 Mybatis-Plus支持各种复杂的where条件,可以满足日常开发的各种需求
下图中方法参数中的wrapper其实就是条件构造器
案例 基于QueryWrapper的查询 
①查询出名字中带o的,存款大于等于1000元的人的id、username、info、balance字段
1 2 3 4 5 6 7 8 9 10 11 @Test public  void  testQueryWrapper () {         QueryWrapper<User> wrapper = new  QueryWrapper <User>()         .select("id" ,"username" ,"info" ,"balance" )         .like("username" ,"o" )         .ge("balance" ,1000 );          List<User> userList = userMapper.selectList(wrapper);     userList.forEach(System.out::println); } 
②更新用户名为jack的用户的余额为2000
1 2 3 4 5 6 7 8 9 10 11 @Test public  void  testUpdateByQueryWrapper () {         User  user  =  new  User ();     user.setBalance(2000 );          QueryWrapper<User> wrapper = new  QueryWrapper <User>()         .eq("username" ,"jack" );          userMapper.update(user,wrapper); } 
基于UpdateWrapper的更新 
需求:更新id为1,2,4的用户的余额,扣200
1 2 3 4 5 6 7 8 9 10 @Test public  void  testUpdateWrapper () {         List<Long> ids = List.of(1L ,2L ,4L );     UpdateWrapper<User> wrapper = new  UpdateWrapper <User>()         .setSql("balance=balance-200" )         .in("id" ,ids);          userMapper.update(null ,wrapper); } 
基于LambdaQueryWrapper 的查询
1 2 3 4 5 6 7 8 9 10 11 @Test public  void  testLambdaQueryWrapper () {         LambdaQueryWrapper<User> wrapper = new  LambdaQueryWrapper <User>()         .select(User::getId,User::getUsername,User::getInfo,User::getBalance)         .like(User::getUsername,"o" )         .ge(User::getBalance,10 );          List<User> userList = userMapper.selectList(wrapper);     userList.forEach(System.out::println); } 
总结 
QueryWrapper和LambdaQueryWrapper通常用来构建select、delete、update的where条件部分 
UpdateWrapper和LambdaUpdateWrapper通常只有在set语句比较特殊才使用 
尽量使用LambdaQueryWrapper和LambdaUpdateWrapper,避免硬编码 
 
自定义SQL 我们可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,然后自己定义SQL语句中剩下的部分。
需求:将id在指定范围的用户(例如1、2、4 )的余额扣减指定值
背景 
直接写SQL语句,where条件语句比较繁琐 
全部用Wrapper来完成,不符合业务逻辑规范(参数往往只允许在Service层去定义) 
 
自定义SQL流程 ①基于Wrapper构建where条件
1 2 3 4 5 List<Long> ids = List.of(1L ,2L ,4L ); int  amount=-20000 ;LambdaQueryWrapper<User> lambdaQueryWrapper = new  LambdaQueryWrapper <User>()     .in(User::getId,ids); userMapper.updateBalanceById(lambdaQueryWrapper,amount); 
②在mapper方法参数中用Param注解声明wrapper变量名称,必须是ew
1 2 3 4 5 public  interface  UserMapper  extends  BaseMapper <User> {    void  updateBalanceById (@Param("ew") LambdaQueryWrapper<User> wrapper,@Param("amount")  int  amount) ; } 
③自定义SQL,并使用Wrapper条件
1 2 3 <update  id ="updateBalanceById" >     Update user SET balance = balance - #{amount} ${ew.customSqlSegment} </update > 
Service接口 Mybatis-Plus还提供了Service层的接口,有一系列可用的增删改查方法
Mybatis-Plus Service接口使用流程 
自定义Service接口继承IService接口
1 2 public  interface  IUserService  extends  IService <User> {} 
自定义Service实现类,实现自定义接口并继承ServiceImpl类
1 2 3 @Service public  class  UserServiceImpl  extends  ServiceImpl <UserMapper, User> implements  IUserService  {} 
 
实例一:基于Restful风格实现下面的接口 
引入对应依赖 1 2 3 4 5 6 7 8 9 10 11 <dependency >     <groupId > com.github.xiaoymin</groupId >      <artifactId > knife4j-openapi2-spring-boot-starter</artifactId >      <version > 4.1.0</version >  </dependency > <dependency >     <groupId > org.springframework.boot</groupId >      <artifactId > spring-boot-starter-web</artifactId >  </dependency > 
swagger配置信息 本实例借助Swagger实现接口功能的在线测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 knife4j:   enable:  true    openapi:      title:  用户管理接口文档      description:  "用户管理接口文档"      email:  bang@bang.cn      concat:  bang      url:  https://www.bang.cn      version:  v1.0.0      group:        default:          group-name:  default          api-rule:  package          api-rule-resources:            -  com.itheima.mp.controller  
创建对应的实体类 
userFormDTO:代表新增用户的表单UserVO:代表查询的返回结果 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package  com.itheima.mp.domain.dto;import  com.baomidou.mybatisplus.annotation.TableField;import  com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;import  io.swagger.annotations.ApiModel;import  io.swagger.annotations.ApiModelProperty;import  lombok.Data;@Data @ApiModel(description = "用户表单实体") public  class  UserFormDTO  {    @ApiModelProperty("id")      private  Long id;     @ApiModelProperty("用户名")      private  String username;     @ApiModelProperty("密码")      private  String password;     @ApiModelProperty("注册手机号")      private  String phone;     @ApiModelProperty("详细信息,JSON风格")      private  String info;     @ApiModelProperty("账户余额")      private  Integer balance; } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package  com.itheima.mp.domain.vo;import  io.swagger.annotations.ApiModel;import  io.swagger.annotations.ApiModelProperty;import  lombok.Data;@Data @ApiModel(description = "用户VO实体") public  class  UserVO  {         @ApiModelProperty("用户id")      private  Long id;          @ApiModelProperty("用户名")      private  String username;          @ApiModelProperty("详细信息")      private  String info;     @ApiModelProperty("使用状态(1正常 2冻结)")      private  Integer status;          @ApiModelProperty("账户余额")      private  Integer balance; } 
创建响应结果实体类 1 2 3 4 5 6 7 8 @Data @NoArgsConstructor @AllArgsConstructor public  class  JsonResult <T>{    private  T data;      private  Integer status;      private  String message;  } 
按照restful风格编写Controller接口方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 @Api(tags = "用户管理接口") @RequiredArgsConstructor @RestController @RequestMapping("/users") public  class  UserController  {         private  final  IUserService userService;          @ApiOperation("新增用户接口")      @PostMapping      public  JsonResult<UserVO> saveUser (@RequestBody  UserFormDTO userFormDTO) {                  User  user  =  BeanUtil.copyProperties(userFormDTO, User.class);                  userService.save(user);         JsonResult  result  =  new  JsonResult <UserVO>(null ,200 ,"新增用户成功" );         return  result;     }          @ApiOperation("删除用户接口")      @DeleteMapping("/{id}")      public  JsonResult<UserVO> deleteUserById (@ApiParam("用户id")  @PathVariable("id")  Long id) {         userService.removeById(id);         JsonResult<UserVO> result = new  JsonResult <UserVO>(null ,200 ,"删除用户成功" );         return  result;     }          @ApiOperation("根据id查询用户接口")      @GetMapping("/{id}")      public  JsonResult<UserVO> queryUserById (@ApiParam("用户id")  @PathVariable("id")  Long id) {                  User  user  =  userService.getById(id);                  UserVO  userVO  =  BeanUtil.copyProperties(user,UserVO.class);         JsonResult<UserVO> result = new  JsonResult <UserVO>(userVO,200 ,"查询成功" );         return  result;     }          @ApiOperation("根据id批量查询接口")      @GetMapping      public  JsonResult<List<UserVO>> queryUserByIds (@ApiParam("用户id集合")  @RequestParam("ids")  List<Long> ids) {                  List<User> userList = userService.listByIds(ids);                  List<UserVO> userVOList = BeanUtil.copyToList(userList, UserVO.class);         JsonResult<List<UserVO>> result = new  JsonResult <>(userVOList,200 ,"查询成功" );         return  result;     }          @ApiOperation("根据id扣减余额接口")      @PutMapping("/{id}/deduction/{money}")      public  JsonResult<UserVO> reductionBalanceById (@ApiParam("用户id")  @PathVariable("id")  Long id,@ApiParam("扣减金额")  @PathVariable("money")  Integer money) {         boolean  r  =  userService.reductionBalanceById(id,money);         JsonResult<UserVO> result;         if (r) result = new  JsonResult <UserVO>(null ,200 ,"扣减余额成功" );         else  result = new  JsonResult <UserVO>(null ,500 ,"扣减余额失败" );         return  result;     } } 
对于需求5,删减指定用户金额,业务逻辑无法借助`Mybatis-plus现提供的方法,所以需要自定义方法
UserMapper接口
1 void  updateBalanceById (@Param("ew") LambdaQueryWrapper<User> wrapper,@Param("amount")  int  amount) ;
UserMapper.xml
1 2 3 <update  id ="updateBalanceById" >         Update user SET balance = balance - #{amount} ${ew.customSqlSegment}  </update >  
IUserService接口
1 2 3 public  interface  IUserService  extends  IService <User> {    public  boolean  reductionBalanceById (Long id,Integer money) ; } 
IUserService接口实现方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Service @RequiredArgsConstructor public  class  UserServiceImpl  extends  ServiceImpl <UserMapper, User> implements  IUserService  {    private  final  UserMapper userMapper;     @Override      public  boolean  reductionBalanceById (Long id, Integer money)  {                  User  user  =  getById(id);         if (user==null  || user.getBalance()<money){             return  false ;         }                  LambdaQueryWrapper<User> lambdaQueryWrapper = new  LambdaQueryWrapper <User>().eq(User::getId,id);         userMapper.updateBalanceById(lambdaQueryWrapper,money);         return  true ;     } } 
访问localhost:8080/doc.html即可测试
实例二:IService的Lambda查询 需求:实现一个根据复杂条件查询用户的接口,查询条件如下:
name:用户名关键字,可以为空
status:用户状态,可以为空
minBalance:最小余额,可以为空
maxBalance:最大余额,可以为空
 
上述功能其实就是多条件筛选,如果采用传统自己编写SQL语句的话,会非常繁琐
如果采用IService提供的lambdaQuery的话会非常简洁
在IUserServiceImpl中实现如下方法
1 2 3 4 5 6 7 8 @Override public  List<User> queryUsersByCondition (String name, Integer status, Integer minBalance, Integer maxBalance)  {    return  lambdaQuery().like(name!=null ,User::getUsername,name)         .eq(status!=null ,User::getStatus,status)         .gt(minBalance!=null ,User::getBalance,minBalance)         .lt(maxBalance!=null ,User::getBalance,maxBalance)         .list(); } 
UserController添加的代码
1 2 3 4 5 6 7 8 9 10 11 12     @ApiOperation("根据条件查询用户接口")      @GetMapping("/list")      public  JsonResult<List<UserVO>> queryUsers (UserQuery userQuery) {                  List<User> userList = userService.queryUsersByCondition(userQuery.getName(), userQuery.getStatus()                 , userQuery.getMinBalance(), userQuery.getMaxBalance());                  List<UserVO> userVOS = BeanUtil.copyToList(userList, UserVO.class);         JsonResult<List<UserVO>> result = new  JsonResult <>(userVOS, 200 , "查询成功" );         return  result;     } 
案例三:IService的Lambda更新 需求:改造根据id修改用户余额的接口,要求如下
①完成对用户状态校验
②完成对用户余额校验
③如果扣减后余额为0,则将用户status修改为冻结状态(2)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Override     public  boolean  reductionBalanceById (Long id, Integer money)  {                  User  user  =  getById(id);         if (user==null  || user.getBalance()<money){             return  false ;         }                  int  remainBalance  =  user.getBalance()-money;         lambdaUpdate().set(User::getBalance,remainBalance)                 .set(remainBalance==0 ,User::getStatus,2 )                 .eq(User::getId,id)                 .eq(User::getBalance,user.getBalance())                  .update();         return  true ;     } 
  案例四:Iservice批量新增 需求:批量插入10万条用户数据,并作出对比:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Test public  void  testSaveByFor () {    long  start  =  System.currentTimeMillis();     for (int  i=0 ;i<100000 ;i++){         userService.save(buildUser(i));     }     long  end  =  System.currentTimeMillis();     System.out.printf("耗费时间:" +(end-start)+" ms" ); } @Test public  void  testSaveByBatch () {    List<User> list = new  ArrayList <>(1000 );     long  start  =  System.currentTimeMillis();     for (int  i=0 ;i<100000 ;i++){         list.add(buildUser(i));                  if (i%1000 ==0 ){             userService.saveBatch(list);             list.clear();         }     }     long  end  =  System.currentTimeMillis();     System.out.printf("耗费时间:" +(end-start)+" ms" ); } 
循环插入所需时间
批次插入所需时间
开启rewriteBatchedStatements参数
1 url: jdbc:mysql://localhost:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true 
结论 
批处理方案:
扩展功能 代码生成 Mybatis-plus使用流程
定义数据库对应的实体类 
定义mapper接口并继承自BaseMapper 
定义xxService接口并继承自IService 
定义xxService实现类,并继承自ServiceImpl 
 
Mybatis-Plus提供了这些代码的自动生成,官方文档 
利用MybatisPlus插件来生成对应代码
使用步骤 
静态工具 静态工具中的方法与IService中的方法比较相似,其由于是静态的,不用创建出对象即可调用;但是需要传入数据库对应实体类的class(泛型)
案例:静态工具查询 需求:
①改造根据id查询用户的接口,查询用户的同时,查询出用户对应的所有地址
②改造根据id批量查询用户的接口,查询用户的同时,查询出用户对应的所有地址
③实现根据用户id查询收货地址功能,需要验证用户状态,冻结用户抛出异常(练习)
上次需求的实现如果按照常规实现方式时,就会出现循环依赖 ,UserService中会注入AddressService,AddressService中也会注入UserService
此时如借助静态工具,则无需相互注入,解决循环依赖问题
创建地址数据表VO类 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @Data @ApiModel(description = "收货地址VO") public  class  AddressVO {    @ApiModelProperty("id")      private  Long id;     @ApiModelProperty("用户ID")      private  Long userId;     @ApiModelProperty("省")      private  String province;     @ApiModelProperty("市")      private  String city;     @ApiModelProperty("县/区")      private  String town;     @ApiModelProperty("手机")      private  String mobile;     @ApiModelProperty("详细地址")      private  String street;     @ApiModelProperty("联系人")      private  String contact;     @ApiModelProperty("是否是默认 1默认 0否")      private  Boolean isDefault;     @ApiModelProperty("备注")      private  String notes; } 
改写UserVO,新增地址属性 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Data @ApiModel(description = "用户VO实体") public  class  UserVO  {    @ApiModelProperty("用户id")      private  Long id;     @ApiModelProperty("用户名")      private  String username;     @ApiModelProperty("详细信息")      private  String info;     @ApiModelProperty("使用状态(1正常 2冻结)")      private  Integer status;     @ApiModelProperty("账户余额")      private  Integer balance;     @ApiModelProperty("收货地址列表")      private  List<AddressVO> addresss; } 
根据Id查询单个用户信息及其收货地址 改写UserController 中的queryUserById方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @ApiOperation("根据id查询用户接口") @GetMapping("/{id}") public  JsonResult<UserVO> queryUserById (@ApiParam("用户id")  @PathVariable("id")  Long id) {                                  UserVO  userVO  =  userService.queryUserAndAddressById(id);     if (userVO==null ){         return  new  JsonResult <>(null ,600 ,"查询失败" );     }else {         return  new  JsonResult <>(userVO,200 ,"查询成功" );     } } 
新增IUserService 中的queryUserAndAddressById方法
1 UserVO queryUserAndAddressById (Long id) ; 
新增UserServiceImpl 中的queryUserAndAddressById方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Override public  UserVO queryUserAndAddressById (Long id)  {         User  user  =  getById(id);          if (user==null  || user.getStatus()==2 ){         return  null ;     }          UserVO  userVO  =  BeanUtil.copyProperties(user, UserVO.class);     List<Address> addressList = Db.lambdaQuery(Address.class)         .eq(Address::getUserId, id)         .list();          if (CollUtil.isNotEmpty(addressList)){         List<AddressVO> addressVOS = BeanUtil.copyToList(addressList, AddressVO.class);         userVO.setAddresses(addressVOS);     }     return  userVO; } 
根据id列表查询多个用户信息及其收货地址 改写UserController 中的queryUserByIds方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @ApiOperation("根据id批量查询接口") @GetMapping public  JsonResult<List<UserVO>> queryUserByIds (@ApiParam("用户id集合")  @RequestParam("ids")  List<Long> ids) {                                  List<UserVO> userVOS = userService.listUserAndAddressByIds(ids);     if (userVOS==null ) return  new  JsonResult <>(null ,600 ,"查询失败" );     else  return  new  JsonResult <>(userVOS,200 ,"查询成功" ); } 
新增IUserService 中的queryUserAndAddressByIds方法
1 List<UserVO> listUserAndAddressByIds (List<Long> ids) ; 
新增UserServiceImpl 中的queryUserAndAddressByIds方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 @Override public  List<UserVO> listUserAndAddressByIds (List<Long> ids)  {         List<User> userList = listByIds(ids);     if (CollUtil.isEmpty(userList)){         return  null ;     }                    List<Address> addressList = Db.lambdaQuery(Address.class)         .in(Address::getUserId, ids)         .list();     List<UserVO> userVOS = BeanUtil.copyToList(userList, UserVO.class);     if (CollUtil.isNotEmpty(addressList)){         List<AddressVO> addressVOS = BeanUtil.copyToList(addressList, AddressVO.class);                  Map<Long, List<AddressVO>> map = addressVOS.stream().collect(Collectors.groupingBy(AddressVO::getUserId));                  for  (UserVO userVO : userVOS) {             userVO.setAddresses(map.get(userVO.getId()));         }     }     return  userVOS;                                                                       } 
逻辑删除 逻辑删除 就是基于代码逻辑模拟删除效果,但并不会真正删除数据。思路如下:
在表中添加一个字段标记数据是否被删除
当删除数据时把标记置为1
查询时只查询标记为0的数据
 
背景:淘宝中的购物订单模块,用户点击订单删除按钮,本地会消失,但是实际上数据库中该数据并未被删除,应为对于商家而言,订单数据比较重要;此时采用的就是逻辑删除 逻辑,用户查询时不会查询该数据,但该数据在数据库中仍然存在
MybatisPlus 提供了逻辑删除功能,无需改变方法调用的方式,而是在底层帮我们自动修改CRUD的语句。我们要做的就是在application.yaml文件中配置逻辑删除的字段名称和值即可:
1 2 3 4 5 6 mybatis-plus: 	global-config: 		db-config: 			logic-delete-field: flag # 全局逻辑删除的实体字段名,字段类型可以是boolean、integer 			logic-delete-value: 1 # 逻辑已删除值(默认为 1) 			logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) 
注意 
逻辑删除本身也有自己的问题,比如:
因此,我不太推荐采用逻辑删除功能,如果数据不能删除,可以采用把数据迁移到其它表的办法。
枚举处理器 Java中的枚举类型与数据库整数类型之间的转换问题
实现PO类中的枚举变量与数据库字段的转换 ①给枚举中的与数据库对应value值添加@EnumValue注解
②在配置文件中配置统一的枚举处理器,实现类型转换
1 2 3 mybatis-plus: 	configuration: 		default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler 
实例 定义Status字段对应的枚举类 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Getter public  enum  UserStatus  {    Normal(1 ,"正常" ),     FREEZE(2 ,"冻结" );          @EnumValue      private  int  value;     private  String description;     UserStatus(int  value, String description) {         this .value = value;         this .description = description;     } } 
配置文件中定义Mybatis枚举处理器 
1 2 3 mybatis-plus:   configuration:     default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler 
将UserPO和UserVO类中的Status属性改成枚举类型 
枚举类型属性返回值的更改 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Getter public  enum  UserStatus  {    Normal(1 ,"正常" ),     FREEZE(2 ,"冻结" );          @EnumValue      private  int  value;          @JsonValue      private  String description;     UserStatus(int  value, String description) {         this .value = value;         this .description = description;     } } 
JSON处理器 Java数据类型与数据库中Json数据类型的转换
Json处理器使用流程 
在VO/PO实体类的对应属性上添加typeHandler属性,让对应处理器生效 
在实体类的@TableName注解中开启autoResultMap,对象嵌套过程中的自动映射 
 
实例 创建数据库Json字段对应的实体类 
1 2 3 4 5 6 7 8 @Data @NoArgsConstructor @AllArgsConstructor(staticName = "of") public  class  UserInfo  {    private  Integer age;     private  String intro;     private  String gender; } 
修改实体类User 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 @Data @TableName(value = "user",autoResultMap = true) public  class  User  {         @TableId("id")      private  Long id;          @TableField("`username`")      private  String username;          private  String password;          private  String phone;          @TableField(typeHandler = JacksonTypeHandler.class)      private  UserInfo info;          private  UserStatus status;          private  Integer balance;          private  LocalDateTime createTime;          private  LocalDateTime updateTime; } 
更改VO实体类 
插件功能 MyBatisPlus基于MyBatis的Interceptor实现了一个基础拦截器,并在内部保存了MyBatisPlus的内置拦截器的集合
MyBatisPlus提供的内置拦截器有下面这些
其中最常用的是分页插件 
分页插件 分页插件的配置 首先,要在配置类中注册MyBatisPlus的核心插件,同时添加分页插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Configuration public  class  MybatisConfig  {         @Bean      public  MybatisPlusInterceptor mybatisPlusInterceptor () {                  MybatisPlusInterceptor  interceptor  =  new  MybatisPlusInterceptor ();                  PaginationInnerInterceptor  pageInterceptor  =  new  PaginationInnerInterceptor ();         pageInterceptor.setMaxLimit(1000L );                   interceptor.addInnerInterceptor(pageInterceptor);         return  interceptor;     } } 
分页API的使用 
实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Test public  void  testPage () {         int  pageNo=1 ;     int  pageSize=5 ;          Page<User> page = Page.of(pageNo, pageSize);          page.addOrder(new  OrderItem ("balance" ,true ));          Page<User> p = userService.page(page);          System.out.println("total=" +p.getTotal());          System.out.println("pages=" +p.getPages());          List<User> records = page.getRecords();     records.forEach(System.out::println); } 
通用分页实体 实例:简单分页查询 需求:遵循下面的接口规范,编写一个UserController接口,实现User的分页查询
返回值类
创建通用的查询参数实体 
1 2 3 4 5 6 7 8 9 10 11 12 @Data @ApiModel("查询通用实体") public  class  PageQuery  {    @ApiModelProperty("页码")      private  Integer pageNo;     @ApiModelProperty("页大小")      private  Integer pageSize;     @ApiModelProperty("排序字段")      private  String sortBy;     @ApiModelProperty("是否升序")      private  boolean  isAsc; } 
用户查询继承与查询实体类 
1 2 3 4 5 6 7 8 9 10 11 12 @Data @ApiModel(description = "用户查询条件实体") public  class  UserQuery  extends  PageQuery {    @ApiModelProperty("用户名关键字")      private  String name;     @ApiModelProperty("用户状态:1-正常,2-冻结")      private  Integer status;     @ApiModelProperty("余额最小值")      private  Integer minBalance;     @ApiModelProperty("余额最大值")      private  Integer maxBalance; } 
创建通用的查询结果实体 
1 2 3 4 5 6 7 8 9 10 @Data @ApiModel("通用查询结果实体类") public  class  QueryDTO <T> {    @ApiModelProperty("数据总数")      private  Long total;     @ApiModelProperty("页面总数")      private  Long pages;     @ApiModelProperty("当前页面数据")      private  List<T> data; } 
Service层编写对应方法 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Override public  QueryDTO<UserVO> queryUsersByPage (UserQuery query)  {    String  name  =  query.getName();     Integer  status  =  query.getStatus();          Page<User> page = Page.of(query.getPageNo(), query.getPageSize());     if (StrUtil.isNotEmpty(query.getSortBy())){         page.addOrder(new  OrderItem (query.getSortBy(),query.isAsc()));     }else {         page.addOrder(new  OrderItem ("update_time" ,false ));     }          Page<User> pages = lambdaQuery().like(name != null , User::getUsername, name)         .eq(status != null , User::getStatus, status)         .page(page);          QueryDTO<UserVO> userVOPageDTO = new  QueryDTO <>();     List<UserVO> userVOS = BeanUtil.copyToList(pages.getRecords(), UserVO.class);     userVOPageDTO.setTotal(pages.getTotal());     userVOPageDTO.setPages(pages.getPages());     userVOPageDTO.setData(userVOS);     return  userVOPageDTO; } 
编写对应的Controller层方法 
1 2 3 4 5 6 7 8 @ApiOperation("根据条件分页查询") @GetMapping("/page") public  JsonResult<QueryDTO<UserVO>> queryUsersByPage (UserQuery userQuery) {    QueryDTO<UserVO> userVOPageDTO = userService.queryUsersByPage(userQuery);     return  new  JsonResult <>(userVOPageDTO,200 ,"查询成功" ); } 
优化:函数封装 service层中page分页条件的构建和根据查询结果构造分页查询结果实体的代码与业务无关,可以单独抽取出来进行封装
在PageQuery中定义方法,将PageQuery对象转为MyBatisPlus中的Page对象 
在PageDTO中定义方法,将MyBatisPlus中的Page结果转为PageDTO结果 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Data @ApiModel("查询通用实体") public  class  PageQuery  {    @ApiModelProperty("页码")      private  Integer pageNo;     @ApiModelProperty("页大小")      private  Integer pageSize;     @ApiModelProperty("排序字段")      private  String sortBy;     @ApiModelProperty("是否升序")      private  boolean  isAsc;     public   <PO> Page<PO> toMybatisPage () {         Page<PO> page = Page.of(pageNo, pageSize);         if (StrUtil.isNotEmpty(sortBy)){             page.addOrder(new  OrderItem (sortBy,isAsc));         }else {             page.addOrder(new  OrderItem ("update_time" ,false ));         }         return  page;     } } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Data @ApiModel("通用查询结果实体类") public  class  QueryDTO <T> {    @ApiModelProperty("数据总数")      private  Long total;     @ApiModelProperty("页面总数")      private  Long pages;     @ApiModelProperty("当前页面数据")      private  List<T> data;     public  static  <PO,VO> QueryDTO<VO> toPageDTO (Page<PO> pages,Class<VO> clazz) {         QueryDTO<VO> userVOPageDTO = new  QueryDTO <>();         List<VO> userVOS = BeanUtil.copyToList(pages.getRecords(),clazz);         userVOPageDTO.setTotal(pages.getTotal());         userVOPageDTO.setPages(pages.getPages());         userVOPageDTO.setData(userVOS);         return  userVOPageDTO;     } } 
service层方法改写 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Override public  QueryDTO<UserVO> queryUsersByPage (UserQuery query)  {    String  name  =  query.getName();     Integer  status  =  query.getStatus();          Page<User> page = query.toMybatisPage();          Page<User> pages = lambdaQuery().like(name != null , User::getUsername, name)         .eq(status != null , User::getStatus, status)         .page(page);          return  QueryDTO.toPageDTO(pages, UserVO.class); }