当前位置: 首页 > news >正文

MybatisPlus(一)扩展功能

扩展功能

  • 一、静态工具
  • 二、逻辑删除
  • 三、通用枚举
    • 1、定义枚举
    • 2、配置枚举处理器
    • 3、测试
  • 四、JSON类型处理器
    • 1、定义实体
    • 2、使用类型处理器
  • 五、分页
    • 1、配置分页插件
    • 2、分页API
    • 3、示例

一、静态工具

有的时候Service之间也会相互调用,为了避免出现循环依赖问题,MybatisPlus提供一个静态工具类:Db,其中的一些静态方法与IService中方法签名基本一致,也可以帮助我们实现CRUD功能:
在这里插入图片描述
实例:

@Test
void testDbGet() {User user = Db.getById(1L, User.class);System.out.println(user);
}@Test
void testDbList() {// 利用Db实现复杂条件查询List<User> list = Db.lambdaQuery(User.class).like(User::getUsername, "o").ge(User::getBalance, 1000).list();list.forEach(System.out::println);
}@Test
void testDbUpdate() {Db.lambdaUpdate(User.class).set(User::getBalance, 2000).eq(User::getUsername, "Rose");
}

传入实体类的class字节码,拿到字节码就能通过反射拿到实体类的相关信息,从而拿到注解上的信息诸如类名、表名等,以此实现CURD。
Db静态类其实很原始service的方法使用基本一致,只是多了一个实体类的class字节码。

二、逻辑删除

对于一些比较重要的数据,我们往往会采用逻辑删除的方案,即:

  • 在表中添加一个字段标记数据是否被删除
  • 当删除数据时把标记置为true
  • 查询时过滤掉标记为true的数据
    一旦采用了逻辑删除,所有的查询和删除逻辑都要跟着变化,非常麻烦。

为了解决这个问题,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,基本不用考虑代码逻辑问题。还是非常方便的。
注意:
逻辑删除本身也有自己的问题,比如:

  • 会导致数据库表垃圾数据越来越多,从而影响查询效率
  • SQL中全都需要对逻辑删除字段做判断,影响查询效率

因此,我不太推荐采用逻辑删除功能,如果数据不能删除,可以采用把数据迁移到其它表的办法。

三、通用枚举

User类中有一个用户状态字段:
在这里插入图片描述

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

1、定义枚举

我们定义一个用户状态的枚举:
在这里插入图片描述

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 注解来标记枚举属性:
在这里插入图片描述

2、配置枚举处理器

在application.yaml文件中添加配置:

mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

3、测试

@Test
void testService() {List<User> list = userService.list();list.forEach(System.out::println);
}

在这里插入图片描述
同时,为了使页面查询结果也是枚举格式,我们需要修改UserVO中的status属性:

在这里插入图片描述
并且,在UserStatus枚举中通过@JsonValue注解标记JSON序列化时展示的字段:

在这里插入图片描述

最后,在页面查询,结果如下:

在这里插入图片描述

四、JSON类型处理器

数据库的user表中有一个info字段,是JSON类型:
在这里插入图片描述

格式像这样:

{"age": 20, "intro": "佛系青年", "gender": "male"}

而目前User实体类中却是String类型:
在这里插入图片描述

这样一来,我们要读取info中的属性时就非常不方便。如果要方便获取,info的类型最好是一个Map或者实体类。

而一旦我们把info改为对象类型,就需要在写入数据库时手动转为String,再读取数据库时,手动转换为对象,这会非常麻烦。

因此MybatisPlus提供了很多特殊类型字段的类型处理器,解决特殊字段类型与数据库类型转换的问题。例如处理JSON就可以使用JacksonTypeHandler处理器。

1、定义实体

我们定义一个单独实体类来与info字段的属性匹配:

package com.itheima.mp.domain.po;import lombok.Data;@Data
public class UserInfo {private Integer age;private String intro;private String gender;
}

2、使用类型处理器

接下来,将User类的info字段修改为UserInfo类型,并声明类型处理器:
在这里插入图片描述
同时,在User类上添加一个注解,声明自动映射:

在这里插入图片描述

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

在这里插入图片描述

五、分页

在未引入分页插件的情况下,MybatisPlus是不支持分页功能的,IService和BaseMapper中的分页方法都无法正常起效。
所以,我们必须配置分页插件。

1、配置分页插件

在项目中新建一个配置类:
在这里插入图片描述

其代码如下:

package com.itheima.mp.config;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MybatisConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {// 初始化核心插件MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}

2、分页API

编写一个分页查询的测试:

@Test
void testPageQuery() {// 1.分页查询,new Page()的两个参数分别是:页码、每页大小Page<User> p = userService.page(new Page<>(2, 2));// 2.总条数System.out.println("total = " + p.getTotal());// 3.总页数System.out.println("pages = " + p.getPages());// 4.数据List<User> records = p.getRecords();records.forEach(System.out::println);
}

在这里插入图片描述
这里用到了分页参数,Page,即可以支持分页参数,也可以支持排序参数。常见的API如下:

int pageNo = 1, pageSize = 5;
// 分页参数
Page<User> page = Page.of(pageNo, pageSize);
// 排序参数, 通过OrderItem来指定
page.addOrder(new OrderItem("balance", false));userService.page(page);

3、示例

现在要实现一个用户分页查询的接口,接口规范如下:
在这里插入图片描述

controller.java

package com.itheima.mp.controller;import com.itheima.mp.domain.dto.PageDTO;
import com.itheima.mp.domain.query.PageQuery;
import com.itheima.mp.domain.vo.UserVO;
import com.itheima.mp.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("users")
@RequiredArgsConstructor
public class UserController {private final UserService userService;@GetMapping("/page")public PageDTO<UserVO> queryUsersPage(UserQuery query){return userService.queryUsersPage(query);}// 。。。 略
}

然后在IUserService中创建queryUsersPage方法:

PageDTO<UserVO> queryUsersPage(PageQuery query);

接下来,在UserServiceImpl中实现该方法:

@Override
public PageDTO<UserVO> queryUsersPage(PageQuery query) {// 1.构建条件// 1.1.分页条件Page<User> page = Page.of(query.getPageNo(), query.getPageSize());// 1.2.排序条件if (query.getSortBy() != null) {page.addOrder(new OrderItem(query.getSortBy(), query.getIsAsc()));}else{// 默认按照更新时间排序page.addOrder(new OrderItem("update_time", false));}// 2.查询page(page);// 3.数据非空校验List<User> records = page.getRecords();if (records == null || records.size() <= 0) {// 无数据,返回空结果return new PageDTO<>(page.getTotal(), page.getPages(), Collections.emptyList());}// 4.有数据,转换List<UserVO> list = BeanUtil.copyToList(records, UserVO.class);// 5.封装返回return new PageDTO<UserVO>(page.getTotal(), page.getPages(), list);
}
http://www.dtcms.com/a/268817.html

相关文章:

  • MS51224 一款 16 位、3MSPS、双通道、同步采样模数转换器(ADC)
  • LMH1219RTWR-富利威-3G/12G-SDI
  • 【mini-spring】【更新中】第一章 IOC与Bean源码及思路解析
  • 如何用 Mockito 玩转单元测试
  • 闲庭信步使用图像验证平台加速FPGA的开发:第三课——YCbCr转RGB的FPGA实现
  • 搜广推校招面经八十八
  • Linux批量执行工具脚本使用指南:一键运行多个release-dev.sh脚本
  • macOS运行python程序遇libiomp5.dylib库冲突错误解决方案
  • 【STM32】const 变量存储学习笔记
  • 【论文阅读】CogView: Mastering Text-to-Image Generation via Transformers
  • 文心一言4.5开源模型测评:ERNIE-4.5-0.3B超轻量模型部署指南
  • React19 新增Hooks:useOptimistic
  • 巧借东风:32位栈迁移破解ciscn_2019_es_2的空间困局
  • maven 发布到中央仓库-01-概览
  • 23、企业租赁管理(Rent)全流程指南:从资产盘活到价值最大化的数字化实践
  • Dify工作流实战:输入接口名,自动生成带源码的Markdown API文档(附完整Prompt)
  • Linux 文件系统与日志分析(补充)
  • 报错 400 和405解决方案
  • 海外短剧系统开发:PC端与H5端的全栈实践与深度解析
  • Day07- 管理并发和并行挑战:竞争条件和死锁
  • 在bash shell 函数传递数组的问题2
  • 【DeepSeek实战】17、MCP地图服务集成全景指南:高德、百度、腾讯三大平台接入实战
  • PCIE Ack/Nak机制详解
  • Unity 实现与 Ollama API 交互的实时流式响应处理
  • ES 压缩包安装
  • socket接口api的深度探究
  • 初识Neo4j之Cypher
  • 【Unity笔记】Unity 粒子系统 Triggers 使用解析:监听粒子进入与离开区域并触发事件
  • 在 macOS 上安装和测试 LibreOffice
  • 深入解析TCP:可靠传输的核心机制与实现逻辑(三次握手、四次挥手、流量控制、滑动窗口、拥塞控制、慢启动、延时应答、面向字节流、粘包问题)