springboot 整合 mybatis-plus

一.前言

        1. mybatis-plus是什么

        mybatis-plus是一个对mybati框架的拓展框架,它在mybatis框架基础上做了许多的增强,帮助我们快速的进行代码开发。目前企业开发中,使用mybati的项目基本会选择使用mybatis-plus来提升开发效率。

        2.官网地址:MyBatis-Plus 🚀 为简化开发而生

二.项目集成

        1. 项目中集成(示例用的springboot2.x+mysql)

        step1.引入依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.7</version>
</dependency>

        step2.配置数据源

spring: 
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.**.**:3306/rui
    username: root
    password: ******

        step3.启动类添加注解 @MapperScan 指向mapper接口所在包

@SpringBootApplication
@MapperScan("com.rui.mapper")
@EnableFeignClients(defaultConfiguration = MyFeignConfiguration.class)
public class AdminServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(AdminServerApplication.class, args);
    }
}

        step4.定义实体类

        step5.编码测试:

(编码测试演示比较接近实际开发的代码,如果只是简单验证,用baseMapper就行了)

以下代码均为mybatis-plus提供的代码生成器生成的,如何使用在后续段落会讲,这里先看一下代码样子,眼熟以下

代码结构:

controller层:

@Slf4j
@RestController
@RequestMapping("/configInfo")
public class ConfigInfoController {

    @Autowired
    private IConfigInfoService configInfoService;

    @GetMapping("/list")
    public List<ConfigInfo>  listConfigs () {
        return configInfoService.list();
    }

}

service层:

        interface:

public interface IConfigInfoService extends IService<ConfigInfo> {

}

        impl:

** 注意,这里继承了一个ServiceImpl 它是mybatis-plus提供的类,帮我们完成许DB操作**

@Service
public class ConfigInfoServiceImpl extends ServiceImpl<ConfigInfoMapper, ConfigInfo> implements IConfigInfoService {

}

mapper层:

        mapper接口:

** 注意,我们的mapper实现了 BaseMapper ,它是mybatis-plus提供的接口,有常用的CRUD**

public interface ConfigInfoMapper extends BaseMapper<ConfigInfo> {

}

        mapper.xml: (其实就是空的,如果后面开始有自定义sql,需要这里写)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.rui.mapper.ConfigInfoMapper">

</mapper>

        以上操作结束后,启动项目,postMan访问接口,发现可以正常访问数据库:

在测试环节,大家可以发现我的service和mapper都是空的,但是却可以调用list方法访问数据库。

其实,上面的编码中,我们在自己的业务Service中继承了抽象类ServiceImpl,ServiceImpl实现了IService这个接口中的方法,并定义了四个成员变量 baseMapper,entityClass, mapperClass,log,且这四个成员变量都是protected的,因此,在我们的业务Service中,我们可以直接调用IService的方法诸如saveAndUpdate,list,page等,也可以通过this.baseMapper 的方式来获取baseMapper对象,来调用baseMapper的方法

三.使用技巧

        1.理解mybatis-plus在代码中做的事情

        mybatis-plus为我们提供的最核心的功能其实就是对Mybatis的Mapper接口的增强,它提供了一个BaseMapper,一个mybatis的mapper接口继承了BaseMapper的话,就会被mybatis-plus进行增强,实现一系列的常用的数据库操。使用mybatis-plus最简单的办法其实就是引入mybatis-plus的依赖后,定义好Entity对象(实体对象),然后让mapper继承BaseMapper,最终我们使用baseMaper中的方法来进行开发。

        看一个使用baseMapper的例子:

        todo

        但是直接使用baseMaper的话,有许多操作我们还需要自己写代码,比如一些批量操作,如batchSave(批量插入)等。所以,mybatis-plus还提供了ServiceImpl,来帮我们实现这些。

        上面的编码中,我们在自己的业务Service中继承了抽象类ServiceImpl,ServiceImpl实现了IService这个接口中的方法,并定义了四个成员变量 baseMapper,entityClass, mapperClass,log,且这四个成员变量都是protected的,因此,在我们的业务Service中,我们可以直接调用IService的方法诸如saveAndUpdate,list,page等,也可以通过this.baseMapper 的方式来获取baseMapper对象,来调用baseMapper的方法。

        2.使用QueryWrapper进行查询

        以该service为例:

        QueryWrapper是我们工作中每天都啊哟使用的,场景非常多,我列出一些常见的场景,方便大家查阅

                1.1. 新增

        ConfigInfo configInfo = mockData();
        this.baseMapper.insert(configInfo);

                1.2. 删除

        LambdaQueryWrapper<ConfigInfo> configInfoQueryWrapper = new LambdaQueryWrapper<>();
        configInfoQueryWrapper.eq(ConfigInfo::getId, 500L);
        this.baseMapper.delete(configInfoQueryWrapper);

                1.3. 修改

        // 方法1 根据id更新,直接传入对象
        ConfigInfo configInfo = mockData();
        this.baseMapper.updateById(configInfo);

        //方法2 使用wrapper更新 set代表要修改的字段 eq是条件为相等的isi
        UpdateWrapper<ConfigInfo> configInfoUpdateWrapper = Wrappers.update();
        configInfoUpdateWrapper.set("appName","chengxuyuanA");
        configInfoUpdateWrapper.set("groupId", "groupA");
        configInfoUpdateWrapper.eq("id", 500L);
        this.baseMapper.update(configInfoUpdateWrapper);

                1.4. 查询

                列表查询

                        简单查询(简单的条件查询)

        // 查润groupId 为 5001的数据
        LambdaQueryWrapper<ConfigInfo> configInfoQueryWrapper = new LambdaQueryWrapper<>();
        configInfoQueryWrapper.eq(ConfigInfo::getGroupId, "5001");
        List<ConfigInfo> res = this.baseMapper.selectList(configInfoQueryWrapper);

                        复杂查询  (场景太多了,我就用一个包含 and, or, in ,between ,order by 的sql来表示一下用法)

        // select *
        // from config_info
        // where app_name like '%app%'
        //  and id between 1 and 50
        //  or (src_ip in ('1.0.1.1', '196.123.1.1', '0.0.0.0') and effect is not null)
        LambdaQueryWrapper<ConfigInfo> configInfoQueryWrapper = new LambdaQueryWrapper<>();
        configInfoQueryWrapper.like(ConfigInfo::getAppName, "app")
                        .between(ConfigInfo::getId, 1, 50);
        configInfoQueryWrapper.or(w->w.in(ConfigInfo::getSrcIp,srcips).isNotNull(ConfigInfo::getEffect));

                        分组聚合(其实这个一般不会用,考虑性能和优化,聚合的东西一般自己写sql)

        LambdaQueryWrapper<ConfigInfo> configInfoQueryWrapper = new LambdaQueryWrapper<>();
        configInfoQueryWrapper.groupBy(ConfigInfo::getGroupId);

        Long res = this.baseMapper.selectCount(configInfoQueryWrapper);

                分页查询

        Page page = new Page();
        page.setCurrent(1);
        page.setSize(10);

        LambdaQueryWrapper<ConfigInfo> configInfoQueryWrapper = new LambdaQueryWrapper<>();
        configInfoQueryWrapper.eq(ConfigInfo::getGroupId, "5001");
        IPage<ConfigInfo> pageData = this.page(page, configInfoQueryWrapper);

        3.自定义sql查询

                3.1.使用自定义sql

                和使用mybatis完全一样,这里不赘述了

                3.2.对自定义sql分页

                interface层

IPage<ConfigRation> selectUserPage(Page page, @Param("configration") ConfigRation configrationVo);

                同mybatis的正常使用,但是在第一个参数加上一个Page入参

        4.字段映射及一些注解使用技巧

                普通映射

                默认不需要注解,只要把数据库的字段的_去掉,换成小驼峰就行了

                如果需要对象属性名和数据库字段名称不同,可以用如下注解:

@TableField(value = "data_Source")
private String dataType;

                java对象的属性在数据库中不存在

@TableField(exist = false)
@Schema(description = "是否绑定告警通知规则,true是。false否")
private Boolean isBindNoticeRule;
                枚举映射

枚举注解@EnumValue,需要在枚举对象和java的实体类上都加:

public enum GenderEnum {
   
    MALE(0, "男"),
    FEMALE(1, "女");

    @EnumValue
    private final int code;
    private final String desc;

    GenderEnum(int code, String desc) {
   
        this.code = code;
        this.desc = desc;
    }
}
@TableName("user")
public class User {
   
    @TableId
    private Long id;

    @TableField("gender")
    @EnumValue
    private GenderEnum gender;

    // 省略其他属性和方法
}
                逻辑删除注解

逻辑删除需要进行一些配置:

step1:增加配置

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted # 全局逻辑删除字段名
      logic-delete-value: 1 # 逻辑已删除值
      logic-not-delete-value: 0 # 逻辑未删除值

step2:在实体类中使用 @TableLogic 注解

public class User {
    // 其他字段...

    @TableLogic
    private Integer deleted;
}
                多数据源注解

多数据源支持需要一个包  dynamic-datasource

step1:maven增加依赖

<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  <version>${version}</version>
</dependency>

step2:数据源配置:

spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        slave_1:
          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        slave_2:
          url: ENC(xxxxx)
          username: ENC(xxxxx)
          password: ENC(xxxxx)
          driver-class-name: com.mysql.jdbc.Driver

step3:使用 @DS 切换数据源

@Service
@DS("slave")
public class UserServiceImpl implements UserService {

  @Autowired
  private JdbcTemplate jdbcTemplate;

  @Override
  @DS("slave_1")
  public List selectByCondition() {
    return jdbcTemplate.queryForList("select * from user where age >10");
  }
}
                字段忽略注解
@TableField(exist = false)
private String companyname;

四.常用插件

       1.插件介绍

        介绍两个插件DataPermissionInterceptor, PaginationInnerInterceptor

        DataPermissionInterceptor:

        我们在开发中,很多项目有多租户,多组织的需求,不同租户和组织能看到的数据内容不同。假如业务数据我们用一个字段tenent_id区分不同租户的数据,那么我们希望开发者在编码时候,不需要刻意关注这个字段,正常写业务逻辑就好,有一个统一的拦截器能帮助我们在调用数据库时候把 tenent_id = {user_tenent_id} 这段sql加到查询语句中,DataPermissionInterceptor就是帮我们做这个事情的。

        实际开发中,基本涉及到多组织,多租户的项目都会使用这个插件。如果大家在开发中发现使用了mybatis-plus的项目默认拼接了一些sql,可以尝试搜索DataPermissionInterceptor来找一下加的地方。

        PaginationInnerInterceptor

        分页插件, 对于单一数据库类型来说,都建议配置该值,避免每次分页都去抓取数据库类型,使用方法很简单,直接new PaginationInnerInterceptor(dataType就好)

        2.实战使用

step1: 注册拦截器,加入了上面介绍的俩插件

@Configuration
public class MybatisAutoConfiguration implements WebMvcConfigurer {

	@Bean
	public MybatisPlusInterceptor mybatisPlusInterceptor(@Autowired(required = false) DataPermissionHandler dataPermissionHandler) {
		MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
		if (dataPermissionHandler != null) {
			interceptor.addInnerInterceptor(new DataPermissionInterceptor(dataPermissionHandler));
		}
		interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
		return interceptor;
	}
}

 step2:DataPermissionHandler编码

public class DataPermissionHandler extends MultiDataPermissionHandler {
    @Override
    public Expression getSqlSegment(Table table, Expression where, String mappedStatementId) {
        // 在此处编写自定义数据权限逻辑
        try {
            String sqlSegment = "..."; // 数据权限相关的 SQL 片段
            return CCJSqlParserUtil.parseCondExpression(sqlSegment);
        } catch (JSQLParserException e) {
            e.printStackTrace();
            return null;
        }
    }
}

五.使用代码生成器

        关于代码生成器

        代码生成器在工作中其实很常用,所以我觉得不了解的道友还是需要了解一下。

        1.代码生成器配置

        我使用的mybatis-plus是3.5.7,低于3.5版本的话,可能略有不同

        step1:引入两个依赖包:

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.7</version>
        </dependency>

        <!-- freemarker模板 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
            <version>3.1.2</version>
        </dependency>

       step2:创建一个java类,用来生成代码,我一般喜欢在项目中建一个dev文件夹,放一些开发工具

        结构如图:

代码:

public class CodeGenerator {

    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql://192.168.**.**:3306/rui",
                        "root",
                        "******")
                .globalConfig(builder -> builder
                        .author("rui")
                        .outputDir(Paths.get(System.getProperty("user.dir")) +
                                "/services/admin-server" +
                                "/src/main/java")
                        .commentDate("yyyy-MM-dd")
                )
                .packageConfig(builder -> builder
                        .parent("com.rui")
                        .entity("entity")
                        .mapper("mapper")
                        .service("service")
                        .serviceImpl("service.impl")
                        .xml("mapper.xml")
                )
                .strategyConfig(builder -> builder
                        // 要生成代码的表名称,不加下面这行就是全库生成
                        .addInclude("config_info") 
                        .entityBuilder()
                        .enableLombok()
                )
                .templateEngine(new FreemarkerTemplateEngine())
                .execute();
    }

}

        2.代码生成器使用

        直接右键执行即可,执行后就会在项目中生成对应文件。默认的模板controller,service中是没有方法的,可以自己配置一下模板,放一些和前端交互的CRUD。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Study--Oracle-06-Oracler网络管理

一、ORACLE的监听管理 1、ORACLE网络监听配置文件 cd /u01/app/oracle/product/12.2.0/db_1/network/admin 2、在Oracle数据库中&#xff0c;监听器&#xff08;Listener&#xff09;是一个独立的进程&#xff0c;它监听数据库服务器上的特定端口上的网络连接请求&#xff0c…

四十篇:内存巨擘对决:Redis与Memcached的深度剖析与多维对比

内存巨擘对决&#xff1a;Redis与Memcached的深度剖析与多维对比 1. 引言 在现代的系统架构中&#xff0c;内存数据库已经成为了信息处理的核心技术之一。这类数据库系统的高效性主要来源于其对数据的即时访问能力&#xff0c;这是因为数据直接存储在RAM中&#xff0c;而非传统…

p2p、分布式,区块链笔记: 通过libp2p的Kademlia网络协议实现kv-store

Kademlia 网络协议 Kademlia 是一种分布式哈希表协议和算法&#xff0c;用于构建去中心化的对等网络&#xff0c;核心思想是通过分布式的网络结构来实现高效的数据查找和存储。在这个学习项目里&#xff0c;Kademlia 作为 libp2p 中的 NetworkBehaviour的组成。 以下这些函数或…

AI 会淘汰程序员吗?

前言 前些日子看过一篇文章&#xff0c;说国外一位拥有 19 年编码经验、会 100% 手写代码的程序员被企业解雇了&#xff0c;因为他的竞争对手&#xff0c;一位仅有 4 年经验、却善于使用 Copilot、GPT-4 的后辈&#xff0c;生产力比他更高&#xff0c;成本比他更低&#xff0c…

基于java+springboot+vue实现的家政服务平台(文末源码+Lw)299

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本家政服务平台就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&a…

2. Python+Playwright playwright的API

Playwright支持同步和异步两种API&#xff0c;使用异步API需要导入asyncio库&#xff0c;它是一个可以用来实现Python协程的库&#xff0c;更详细介绍可参考Python协程 。我们可以根据自己的偏好选择适合的模式。 同步与异步模式原理 同步操作方式&#xff1a;在代码执行时&am…

SpringBoot 整合 Minio 实现文件切片极速上传技术

Centos7安装Minio 创建目标文件夹 mkdir minio使用docker查看目标镜像状况 大家需要注意&#xff0c;此处我们首先需要安装docker&#xff0c;对于相关安装教程&#xff0c;大家可以查看我之前的文章&#xff0c;按部就班就可以&#xff0c;此处不再赘述&#xff01;&#x…

学习和发展人工智能:新兴趋势和成功秘诀

人工智能(AI)继续吸引组织&#xff0c;因为它似乎无穷无尽地提高生产力和业务成果。在本博客中&#xff0c;了解学习和发展(L&D)部门如何利用人工智能改进流程&#xff0c;简化工作流程&#xff1f; 学习与发展(L&D)部门领导开始探索如何提高和支持人工智能能力的劳动…

Linux Swap机制关键点分析

1. page被swap出去之后,再次缺页是怎么找到找个换出的页面? 正常内存的页面是通过pte映射找到page的,swap出去的page有其特殊的方式:swap的页面page->private字段保存的是:swap_entry_t通过swap_entry_t就能找到该页面的扇区号sector_t,拿到扇区号就可以从块设备中读…

充电宝哪个牌子比较好用?好用的充电宝推荐!

在如今这个电子设备不离手的时代&#xff0c;充电宝已经成为了我们生活中的必备好物。但面对市面上琳琅满目的充电宝品牌和产品&#xff0c;相信很多朋友都曾陷入过纠结&#xff1a;充电宝哪个牌子比较好用呢&#xff1f;为了解决大家的困惑&#xff0c;经过我精心的筛选和试用…

8.x86游戏实战-OD详解

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 上一个内容&#xff1a;7.x86游戏实战-C实现跨进程读写-跨进程写内存 工具下载&#xff1a;下载 OllyI…

【信即是功夫】人皆有良知在心中

良知就是做人、做事的准则&#xff0c;良知就是天理&#xff1b;实实在在地自信 每个人心中都有一个圣人&#xff0c;只因自己不能真的相信&#xff0c;把这个圣人埋没了 良知在每个人心中&#xff0c;无论你如何做&#xff0c;也无法泯灭它。即使身为盗贼的人&#xff0c;他…

【LeetCode的使用方法】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 🔮LeetCode的使用方法 🔮LeetCode 是一个在线编程平台,广泛…

掌握Go语言邮件发送:net/smtp实用教程与最佳实践

掌握Go语言邮件发送&#xff1a;net/smtp实用教程与最佳实践 概述基本配置与初始化导入net/smtp包设置SMTP服务器基本信息创建SMTP客户端实例身份验证 发送简单文本邮件配置发件人信息构建邮件头部信息编写邮件正文使用SendMail方法发送邮件示例代码 发送带附件的邮件邮件多部分…

STM32之五:TIM定时器(2-通用定时器)

目录 通用定时器&#xff08;TIM2~5&#xff09;框图 1、 输入时钟源选择 2、 时基单元 3 、输入捕获&#xff1a;&#xff08;IC—Input Capture&#xff09; 3.1 输入捕获通道框图&#xff08;TI1为例&#xff09; 3.1.1 滤波器&#xff1a; 3.1.2 边沿检测器&#xf…

CesiumJS【Basic】- #058 绘制网格填充多边形(Entity方式)-使用shader

文章目录 绘制网格填充多边形(Entity方式)-使用shader1 目标2 代码2.1 main.ts绘制网格填充多边形(Entity方式)-使用shader 1 目标 使用Entity方式绘制绘制网格填充多边形 - 使用shader 2 代码 2.1 main.ts import * as Cesium from cesium;// 创建 Cesium Viewer 实例…

安装Gitlab+Jenkins

GItlab概述 GitLab概述&#xff1a; 是一个利用 Ruby on Rails 开发的开源应用程序&#xff0c;实现一个自托管的Git项目仓库&#xff0c;可通过Web界面进行访问公开的或者私人项目。 Ruby on Rails 是一个可以使你开发、部署、维护 web 应用程序变得简单的框架。 GitLab拥有与…

ESP32-VScode环境设置

目录 前言 一、安装VSCode 二、安装ESP32环境 1.安装ESP-IDF 2.ESP-IDF设置 3:开始配置环境 4.打开example进行验证 5.烧录 6.调整波特率 总结 前言 环境&#xff1a;Visual Studio Code 芯片&#xff1a;ESP32 说实话&#xff0c;这是我装的时间最长的一个环境&…

C++ 和C#的差别

首先把眼睛瞪大&#xff0c;然后憋住一口气&#xff0c;读下去&#xff1a; 1、CPP 就是C plus plus的缩写&#xff0c;中国大陆的程序员圈子中通常被读做"C加加"&#xff0c;而西方的程序员通常读做"C plus plus"&#xff0c;它是一种使用非常广泛的计算…

【分布式系统】监控平台Zabbix对接grafana

以前两篇博客为基础 【分布式系统】监控平台Zabbix介绍与部署&#xff08;命令截图版&#xff09;-CSDN博客 【分布式系统】监控平台Zabbix自定义模版配置-CSDN博客 一.安装grafana并启动 添加一台服务器192.168.80.104 初始化操作 systemctl disable --now firewalld set…