📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,欢迎多多交流。👍
文章目录
- 写在前面的话
- MyBatis-Plus
- 技术简介
- 整合步骤
- 功能改造
- 过程复盘
- LambdaQueryWrapper
- 总结陈词
写在前面的话
本系列博文已连载到第10篇,在前几篇文章基础上,我们已经得到了一个完整的前后端项目,并且后端已经接入了MyBatis 完成了教师表的 CURD 操作,本篇文章在此基础上,整合MyBatis-Plus
,从而进一步强化功能。
关联文章:
《程序猿入职必会(1) · 搭建拥有数据交互的 SpringBoot 》
《程序猿入职必会(2) · 搭建具备前端展示效果的 Vue》
《程序猿入职必会(3) · SpringBoot 各层功能完善 》
《程序猿入职必会(4) · Vue 完成 CURD 案例 》
《程序猿入职必会(5) · CURD 页面细节规范 》
《程序猿入职必会(6) · 返回结果统一封装》
《程序猿入职必会(7) · 前端请求工具封装》
《程序猿入职必会(8) · 整合 Knife4j 接口文档》
《程序猿入职必会(9) · 用代码生成器快速开发》
MyBatis-Plus
技术简介
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
更详细的内容介绍,建议直接看官网,这边不展开赘述,直接上实操,下文简称为“MP”。
整合步骤
引言:这边是基于之前的 SpringBoot3 后端项目,并且已经整合 MyBatis 的基础上介绍,之前内容可以参考 《程序猿入职必会(1) · 搭建拥有数据交互的 SpringBoot 》和《程序猿入职必会(3) · SpringBoot 各层功能完善 》。
**Step1、引入依赖 **
<!-- 整合MyBatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.5</version>
</dependency>
<!-- 整合MyBatis -->
<!--<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>-->
引入MyBatis-Plus相关依赖,这里有两个注意事项:
1、这里要引入适配SpringBoot3的版本,而不是mybatis-plus-boot-starter。这里的 mybatis-plus-spring-boot3-starter 是专门为 Spring Boot 3.x 版本设计的启动器,支持 Spring Boot 3.x 的特性和依赖。而 mybatis-plus-boot-starter 通常是为较早版本的 Spring Boot(如 2.x)设计的启动器。
Tips:网上很多教程,都是写 mybatis-plus-boot-starter,导致不少问题。
2、MyBatis-Plus 的依赖包含了 MyBatis 的,这里建议把后者的依赖注释,除非你可以保障两者的版本一致,否则可能会引发一系列意想不到的问题。
Step2、修改配置
和 MP 相关的配置,无非就是 datasource 和 Mybatis,在之前的基础上,只需要将属性 mybatis 改成 mybatis-plus,其他都不需要调整。
mybatis-plus:
mapper-locations: classpath:/mappings/**/*Mapper.xml
type-aliases-package: com.lw.sbdemo2.entity
config-location: classpath:mybatis-config.xml
Step3、修改实体类
这里只需要添加一个 @TableId 注解,标识一下主键即可(这里由于主键字段不是id,所以需要加注解)。
其他都是表和字段,由于也是基于表生成的代码,遵循约定大于配置
原则,可以不需要调整。
正常情况使用 @TableField 标识字段,@TableName 标识表名,自动支持驼峰转下划线。
public class ZyTeacherInfo {
@TableId
@Schema(description = "教师编号")
@NotBlank(message = "教师编号不能为空")
private java.lang.String teaCode;
@Schema(description = "教师名称")
@Size(min = 2, max = 8, message = "教师名称长度需在2-8位")
private java.lang.String teaName;
...省略其他代码
}
对应表信息:
Step4、修改 Mapper
这里直接选择新建一个 Mapper,以示区别,因为旧的 Mapper 已经有继承一个自己封装的基类了。
创建一个 Mapper 接口,继承 MP 的BaseMapper,如下所示:
package com.lw.sbdemo2.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lw.sbdemo2.entity.ZyTeacherInfo;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ZyTeacherInfoMpMapper extends BaseMapper<ZyTeacherInfo> {
}
Step5、编写测试 Controller
这里先临时写一个接口,这里只为测试,正常不直接注入Mapper。
@Autowired
private ZyTeacherInfoMpMapper zyTeacherInfoMpMapper;
@GetMapping("")
public List<ZyTeacherInfo> findList(ZyTeacherInfo zyTeacherInfo) {
QueryWrapper<ZyTeacherInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("tea_name", zyTeacherInfo.getTeaName());
List<ZyTeacherInfo> zyTeacherInfos = zyTeacherInfoMpMapper.selectList(queryWrapper);
for (ZyTeacherInfo teacherInfo : zyTeacherInfos) {
System.out.println(teacherInfo);
}
return zyTeacherInfos;
}
启动程序,用 Knife4j 测试一下效果,如下所示。
效果还可以,至此,基础整合工作算完成了。
功能改造
之前 MyBatis 的版本实现了 CURD 的完整功能,那整合完 MP 之后,也不能落下。
使用前面的 ZyTeacherInfoMpMapper,已经可以实现大部分的功能,它提供的方法可不少。
但总不能在 Controller 层,直接操作 Mapper 吧,而且一些操作毕竟还是要组装 QueryWrapper 等实现,不够清爽。
那就把常用的方法,封装到业务 Service 类里面即可。
这里上一段示例代码:
@Slf4j
@Service
public class ZyTeacherInfoMpService extends ServiceImpl<ZyTeacherInfoMpMapper, ZyTeacherInfo> {
/**
* 插入用户
*/
public void addUser(ZyTeacherInfo user) {
this.save(user);
}
/**
* 删除用户
*/
public void deleteUser(Long id) {
this.removeById(id);
}
/**
* 更新用户
*/
public void updateUser(ZyTeacherInfo user) {
this.updateById(user);
}
/**
* 根据ID查询用户
*/
public ZyTeacherInfo getUserById(Long id) {
return this.getById(id);
}
/**
* 查询所有用户
*/
public List<ZyTeacherInfo> getAllUsers() {
return this.list();
}
/**
* 根据条件查询用户(LambdaQueryWrapper方式)
*/
public List<ZyTeacherInfo> getUsersByName(String name) {
LambdaQueryWrapper<ZyTeacherInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ZyTeacherInfo::getTeaName, name);
return this.list(queryWrapper);
}
/**
* 更新电话(LambdaUpdateWrapper方式)
*/
public void updateUserPhone(Long userId, String phone) {
LambdaUpdateWrapper<ZyTeacherInfo> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(ZyTeacherInfo::getTeaCode, userId)
.set(ZyTeacherInfo::getTeaPhone, phone);
this.getBaseMapper()
.update(null, updateWrapper);
}
}
可以看到了选择多样化,更复杂的一些场景,可以借助 LambdaQueryWrapper 和 LambdaUpdateWrapper 实现。
上面只是部分示例,并不是完整代码,同时实战时,框架层面可以考虑进一步的封装。
过程复盘
可以看到,整个过程相当丝滑,大部分操作 MP 都提供了 Service 和 Mapper 层的基类,主要是去除了 SQL-XML。
虽然都是代码生成器生成的,但还是减少不少代码量,最主要是操作数据更贴近了程序猿的思维。
当然,一些复杂的多表查询,或者想提升SQL的性能,那还是继续选择 XML 的方式较为合适。
MP 允许无缝使用 MyBatis 原有的功能,两者并不冲突。
LambdaQueryWrapper
LambdaQueryWrapper 是 MyBatis-Plus 提供的一个非常强大的查询构造器,它允许你以 Lambda 表达式的方式构建查询条件。以下是一些复杂场景的示例,展示如何使用 LambdaQueryWrapper 进行多条件查询、组合条件、排序等操作。
假设我们有一个 User 实体,包含字段 name、age 和 email。
1、多条件查询
我们想要查询年龄大于 18 且名字包含 “John” 的用户。
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper
.gt(User::getAge, 18) // 年龄大于 18
.like(User::getName, "John"); // 名字包含 "John"
List<User> users = userService.list(queryWrapper);
2、组合条件查询
假设我们想要查询年龄在 20 到 30 之间的用户,并且邮箱不为空。
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper
.between(User::getAge, 20, 30) // 年龄在 20 到 30 之间
.isNotNull(User::getEmail); // 邮箱不为空
List<User> users = userService.list(queryWrapper);
3、使用 OR 条件
假设我们想要查询名字为 “Alice” 或者年龄小于 25 的用户。
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper
.gt(User::getAge, 18) // 年龄大于 18
.like(User::getName, "John"); // 名字包含 "John"
List<User> users = userService.list(queryWrapper);
4、排序和分页
假设我们想要查询所有用户,按照年龄降序排列,并且只获取前 10 条记录。
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper
.orderByDesc(User::getAge) // 按照年龄降序排列
.last("LIMIT 10"); // 只获取前 10 条记录
List<User> users = userService.list(queryWrapper);
5、复杂的嵌套条件
假设我们想要查询年龄大于 18 且(名字包含 “John” 或者邮箱以 “@example.com” 结尾的用户)。
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper
.gt(User::getAge, 18) // 年龄大于 18
.and(wrapper -> wrapper // 嵌套条件
.like(User::getName, "John")
.or()
.likeRight(User::getEmail, "@example.com")); // 邮箱以 "@example.com" 结尾
List<User> users = userService.list(queryWrapper);
6、动态条件查询
在某些情况下,查询条件可能是动态的。假设我们有一个查询条件对象,用户可以选择性地输入查询条件。
public List<User> dynamicQuery(UserQueryDTO queryDTO) {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
if (queryDTO.getName() != null) {
queryWrapper.like(User::getName, queryDTO.getName());
}
if (queryDTO.getAge() != null) {
queryWrapper.eq(User::getAge, queryDTO.getAge());
}
if (queryDTO.getEmail() != null) {
queryWrapper.eq(User::getEmail, queryDTO.getEmail());
}
return userService.list(queryWrapper);
}
LambdaQueryWrapper 提供了灵活的方式来构建复杂的查询条件,支持多种操作,如条件组合、排序、分页等。通过使用 Lambda 表达式,可以避免硬编码字段名,从而提高代码的可读性和安全性。
总结陈词
此篇文章介绍了MyBatis-Plus
的基础整合过程,整体还是挺好用的,推荐,仅供学习参考。
简单列了一下实战,关于 MP 还有很多基础和扩展用法,可以自行掌握,加油!
💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。