《程序猿入职必会(10) · SpringBoot3 整合 MyBatis-Plus》

news2024/9/27 17:21:46

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,欢迎多多交流。👍

文章目录

    • 写在前面的话
    • MyBatis-Plus
      • 技术简介
      • 整合步骤
      • 功能改造
      • 过程复盘
      • LambdaQueryWrapper
    • 总结陈词

CSDN.gif

写在前面的话

本系列博文已连载到第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;

    ...省略其他代码
}

对应表信息:
image.png

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 测试一下效果,如下所示。
image.png
效果还可以,至此,基础整合工作算完成了。


功能改造

之前 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 还有很多基础和扩展用法,可以自行掌握,加油!
💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。

CSDN_END.gif

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

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

相关文章

使用samba在ubuntu和windows之间共享文件

1、在ubuntu上安装samba 在终端输入命令 sudo apt update sudo apt install samba 2、配置samba 打开samba 的配置文件 sudo nano /etc/samba/smb.conf 在文件末尾添加以下内容 [shared] path /home/lzx available yes valid users lzx read only no browsable yes…

【Redis进阶】Redis的持久化RDB和AOF

目录 持久化 RDB持久化 概念 原理 RDB 持久化的详细工作流程 1触发持久化&#xff1a; 2创建子进程&#xff1a; 3数据写入 RDB 文件&#xff1a; 4替换旧文件&#xff1a; 5回收子进程&#xff1a; RDB持久化的触发方式 1.手动触发&#xff1a; 2.自动触发&#…

鸿蒙应用服务开发【获取天气数据】

获取天气数据 介绍 Weather Service Kit&#xff08;天气服务&#xff09;是鸿蒙生态下的一个数据提供服务&#xff0c; Weather Service Kit融合了多家气象行业TOPs供应商&#xff0c;提供专业、精准、稳定的超本地化天气数据服务&#xff0c; 开发者可以通过Weather Servic…

Tomcat 漏洞

1.CVE-2017-12615 抓包&#xff0c;将get改为put jsp文件后加/ 访问木马使用蚁剑连接 2.弱口令 点击后输入默认用户名、密码&#xff1a;tomcat/tomcat 登录成功&#xff0c;在文件上传位置上传war包 使用哥斯拉生成一个jsp木马&#xff0c;打包&#xff0c;改后缀为war,上传…

如何有效防御短信接口遭受恶意攻击?

短信接口若遭遇恶意攻击&#xff0c;不仅加剧企业运营成本&#xff0c;更将严重损害企业形象。为有效预防此类风险&#xff0c;以下策略值得采纳&#xff1a; 1.设定合理的发送间隔&#xff1a;针对同一手机号码&#xff0c;设定合理的重复发送短信时间间隔&#xff0c;建议范…

Unity动态修改按钮点击效果

动态修改按钮色块&#xff0c;达到保留选中效果。 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;public class Demo: MonoBehaviour {private Button _frontBtn;private Button _backBtn;public ColorBlock NormalC…

【React】深入解析ref的使用与潜在问题

文章目录 一、ref的基本用法二、常见错误解析三、实例解析四、错误分析与解决五、注意事项六、总结 在React开发中&#xff0c;ref常用于访问DOM元素或组件实例。正确使用ref可以极大地提升用户体验&#xff0c;特别是在需要与DOM交互的场景中。然而&#xff0c;错误或不当的re…

奥运会Ⅷ--生成式人工智能的力量倍增器

生成式人工智能在商业领域的崭新时代 随着 OpenAI 的ChatGPT、Anthropic 的Claude和 Google 的Bard的推出&#xff0c;大规模文本分析和自然语言处理 (NLP) 的长期梦想瞬间成为现实。AI 不仅令人信服地通过了图灵测试&#xff0c;还催化了企业战略的范式转变。突然之间&#x…

8.5 day bug

bug1 没有适当的引号&#xff0c;引言就不是真正的引言 问了通义&#xff0c;原来用引言需要使用单引号括起来 bug2 没理解题意&#xff0c;挺好一网站可惜是英文的&#xff0c;顺便帮翻译还没反馈渠道帮… 问了通义&#xff0c;原来是要改变continueLoop的值 bug3 好家伙&a…

ts-node报错ERR_UNKNOWN_FILE_EXTENSION

问题 有个monorepo项目&#xff0c;在最外层一次性打包 3 个项目的脚本已经成功实现&#xff0c;如下&#xff1a; "build:test": "cross-env NODE_ENVtest vite build --mode test && esno ./build/script/postBuild.ts", "build:prod"…

一行代码实现图片懒加载?分享 1 段优质 HTML 代码片段!

本内容首发于工粽号&#xff1a;程序员大澈&#xff0c;每日分享一段优质代码片段&#xff0c;欢迎关注和投稿&#xff01; 大家好&#xff0c;我是大澈&#xff01; 本文约 700 字&#xff0c;整篇阅读约需 1 分钟。 今天分享一段优质 HTML 代码片段&#xff0c;只需一行代码…

MBD软件开发之数据管理

模块化开发中&#xff0c;模型集成和代码集成是很多工程师非常关心的问题。 常见的代码集成方式有两种&#xff0c;一是单元级模型上生成代码&#xff0c;在代码上做集成&#xff0c;一是模型集成之后&#xff0c;再去生成集成级别的代码。无论采用哪种方式&#xff0c;模型级…

网络端口转发

一. 如图网络拓扑 光猫改桥接之前光猫自身也会有一层局域网&#xff0c;光猫ip为局域网额的192.168.1.1 当改桥接之后&#xff0c;只有一层路由器的局域网&#xff0c;路由器为局域网的192.168.31.1 此时从公网对内网进行访问时&#xff0c;先访问到路由器的公网ip的某个端口…

从零开始搭建监控系统 (二)

从零开始搭建监控系统 (二) 监控系统架构 部署 文件目录 rootchuango:/opt/prometheus# tree -L 1 . ├── docker-compose.yml ├── grafana_data ├── grafana.ini ├── prometheus_data └── prometheus.yml # grafana_data, prometheus_data 2个文件为空目录do…

下载安装ansible后,缺失pyyaml,pip安装时又出错,升级时又由于时Python2.7,不好升级遇到的一系列问题。

经过上一篇文章&#xff0c;我虽然误删了CentOs自带的python和yum&#xff0c;但是我重新将他们恢复了。这里记住默认的python版本是2.7.5。 我使用yum安装好ansible后&#xff0c;检查我的ansible版本的时候&#xff0c;发生了错误&#xff0c;提示没有yaml模块。 1 验证ans…

js事件循环机制(宏微任务队列都是先进先出)

文章目录 1.什么是事件循环2.主线程、任务队列、同步任务、异步任务、微任务、宏任务&#xff08;1&#xff09;主线程&#xff08;2&#xff09;同步任务&#xff08;3&#xff09;异步任务&#xff08;微任务、宏任务&#xff09;&#xff08;4&#xff09;任务队列 3.执行流…

乔布斯对产品,团队,人才的理解

乔布斯的设计理念和管理理念是他领导Apple取得成功的核心因素。以下是对他在产品设计和团队管理方面理念的详细描述 乔布斯的设计理念 1. 简约主义 简洁与直观&#xff1a;乔布斯强调设计的简约性。他相信产品应该尽可能简单且易于使用&#xff0c;去除一切不必要的复杂性。例如…

AIoT新技术融合基础设计课程开发与运营案例分析

本文来自下面的论文的第4部分&#xff1a;《Research on Basic Engineering Design Course Development and Application of New Technology AIoT (Artificial Intelligence of Things) Convergence Education》&#xff0c;作者是Yunja Hwang&#xff0c;来自韩国檀国大学工学…

IDEA左下角不显示本地修改的localChanges信息-git

IDEA左下角不显示本地修改的localChanges信息-git 取消勾选这个