柏竹 柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档

柏竹

奋斗柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档
  • Java基础

  • JavaWeb

  • 拓展技术

  • 框架技术

  • 数据库

  • 数据结构

  • Spring

  • SpringMVC

  • SpringBoot

    • SpringBoot
    • SpringBoot3基础特性
    • SpringBoot3核心原理
    • 框架整合

      • SpringBoot SpringMVC 整合
      • SpringBoot JDBC 整合
      • SpringBoot MyBatis 整合
      • SpringBoot tk-MyBatis 整合
      • SpringBoot Shiro 整合
      • SpringBoot Redis 整合
      • SpringBoot MyBatisPlus 整合
        • MyBatisPlus整合
          • 首次应用
          • 注解配置
          • 内置 CRUD
          • 自定义 SQL
          • 条件构造器
          • 传参操作
          • 多表查询
          • 分页插件
          • 内置分页
          • xml分页
          • pagehelper分页
          • 反向工程
          • 3.5.1之前
          • 3.5.1之后
          • SQL日志
      • SpringBoot JSON 整合
      • SpringBoot Thymeleaf 整合
      • 整合WebSocket实现聊天功能
    • SpringBoot部署
  • SpringClound

  • Ruoyi-Vue-Plus

  • 后端
  • SpringBoot
  • 框架整合
Bozhu12
2023-06-10
目录

SpringBoot MyBatisPlus 整合

# MyBatisPlus整合

MyBatis Plus是MyBatis的增强工具,在MyBatis的基础上做了增强不改变的开发实现,从而提高效率。

官方文档:https://baomidou.com (opens new window)

特点:

  • 无侵入。只做增强不做改变
  • 消耗小。启动只注入CURD
  • 增强CRUD操作。内置通用Mapper
  • 内置代码生成器。采用Maven插件生成映射
  • 分页插件多功能。支持多种数据库
  • 内置全局拦截器。可分析增删改过程进行阻断

# 首次应用

大致流程

  1. 引入pon.xml依赖
  2. 更改库数据相关配置
  3. 启动器类 添加@MapperScan注解

应用

  1. 引入依赖 pom.xml

    <!-- MyBatisPlus -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
    </dependency>
    <!-- mysql驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.48</version>
    </dependency>
    <!-- 连接池 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.20</version>
    </dependency>
    
  2. 配置文件 application

    # MyBatis
    # 连接池
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    # 驱动
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    # url/账号/密码
    spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false
    spring.datasource.username=root
    spring.datasource.password=root
    mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
    

    这里连接库的用户名和密码可以省略不写,或者随意设定

  3. 创建 库数据 和 创建实体类 (省略

  4. 创建 UserMapper接口

    @Mapper
    public interface UserMapper extends BaseMapper<User> {}
    

    继承实现Mapper通用方法

  5. SpringBoot 启动类 添加注解 @MapperScan

    @SpringBootApplication
    @MapperScan("com.mapper")
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class , args);
        }
    }
    

    @MapperScan注解 扫描 Mapper文件夹 的包路径

  6. 测试

    // 启动器Spring测试启动环境
    @RunWith(SpringRunner.class)
    // 启动类
    @SpringBootTest(classes = Application.class)
    public class UserMapperTest {
        
        @Autowired
        private UserMapper userMapper;
        
        @Test
        public void testFindByAll() {
            
            List<User> users = userMapper.selectList(null);
            users.forEach(System.out::println);
            // Assert.assertEquals(26 , users.size());
        }
    }
    

# 注解配置

常用注解说明:

注解 值 说明
@TableName value:纠正表名 表名注解
@TableId value:纠正主键字段名
type:主键策略类型
主键注解
@TableField value:纠正字段名
exist:是否为库字段
fill:默认值填充
字段注解(非主键)

更多注解:https://baomidou.com/pages/223848/

PS : @TableId/@TableField 纠正后 set方法也需要修改 , 因 使用set注入 , 否则失效

# 内置 CRUD

官网说明 : 更多详细 (opens new window)

CRUD测试

增加

增加测试 展开
@Test
public void testInsert() {
    Assert.assertTrue(userMapper.insert(new User().setName("张三").setAge(3)) > 0);
    userMapper.selectList(null).forEach(System.out::println);
}
/*
    User(id=1, name=Jone, age=18, email=test1@baomidou.com, phone=null)
    User(id=2, name=Jack, age=20, email=test2@baomidou.com, phone=null)
    User(id=3, name=Tom, age=28, email=test3@baomidou.com, phone=null)
    User(id=4, name=Sandy, age=21, email=test4@baomidou.com, phone=null)
    User(id=5, name=kaikeba, age=331, email=test4@baomidou.com, phone=null)
    User(id=6, name=Billie, age=24, email=test5@baomidou.com, phone=null)
    User(id=7, name=张三, age=3, email=null, phone=null)
*/

删除

删除测试 展开
@Test
    public void testDelById() {
        Assert.assertTrue(userMapper.deleteById(3) > 0);
        userMapper.selectList(null).forEach(System.out::println);
    }
    /*
        User(id=1, name=Jone, age=18, email=test1@baomidou.com, phone=null)
        User(id=2, name=Jack, age=20, email=test2@baomidou.com, phone=null)
        User(id=4, name=Sandy, age=21, email=test4@baomidou.com, phone=null)
        User(id=5, name=kaikeba, age=331, email=test4@baomidou.com, phone=null)
        User(id=6, name=Billie, age=24, email=test5@baomidou.com, phone=null)
     */
    
    @Test
    public void testDeletes1() {
        Assert.assertTrue(userMapper.delete(new QueryWrapper<User>().like("name","J")) > 0);
        userMapper.selectList(null).forEach(System.out::println);
    }
    /*
        User(id=3, name=Tom, age=28, email=test3@baomidou.com, phone=null)
        User(id=4, name=Sandy, age=21, email=test4@baomidou.com, phone=null)
        User(id=5, name=kaikeba, age=331, email=test4@baomidou.com, phone=null)
        User(id=6, name=Billie, age=24, email=test5@baomidou.com, phone=null)
     */
    
    @Test
    public void testDeletes2() {
        Assert.assertTrue(userMapper.delete(Wrappers.<User>query().like("name","J")) > 0);
        userMapper.selectList(null).forEach(System.out::println);
    }
    /*
        User(id=3, name=Tom, age=28, email=test3@baomidou.com, phone=null)
        User(id=4, name=Sandy, age=21, email=test4@baomidou.com, phone=null)
        User(id=5, name=kaikeba, age=331, email=test4@baomidou.com, phone=null)
        User(id=6, name=Billie, age=24, email=test5@baomidou.com, phone=null)
     */
    
    @Test
    public void testDeletes3() {
        Assert.assertTrue(userMapper.delete(Wrappers.<User>query().lambda().like(User::getName,"J")) > 0);
        userMapper.selectList(null).forEach(System.out::println);
    }
    /*
        User(id=3, name=Tom, age=28, email=test3@baomidou.com, phone=null)
        User(id=4, name=Sandy, age=21, email=test4@baomidou.com, phone=null)
        User(id=5, name=kaikeba, age=331, email=test4@baomidou.com, phone=null)
        User(id=6, name=Billie, age=24, email=test5@baomidou.com, phone=null)
    */
    
    @Test
    public void testDeletes4() {
        Assert.assertTrue(userMapper.delete(new QueryWrapper<User>().lambda().like(User::getName,"J")) > 0);
        userMapper.selectList(null).forEach(System.out::println);
    }
    /*
        User(id=3, name=Tom, age=28, email=test3@baomidou.com, phone=null)
        User(id=4, name=Sandy, age=21, email=test4@baomidou.com, phone=null)
        User(id=5, name=kaikeba, age=331, email=test4@baomidou.com, phone=null)
        User(id=6, name=Billie, age=24, email=test5@baomidou.com, phone=null)
    */

更改

更改测试 展开
@Test
    public void testUpdateById() {
        userMapper.updateById(new User().setId(3L).setName("先科"));
        userMapper.selectList(null).forEach(System.out::println);
    }
    /*
        User(id=1, name=Jone, age=18, email=test1@baomidou.com, phone=null)
        User(id=2, name=Jack, age=20, email=test2@baomidou.com, phone=null)
        User(id=3, name=先科, age=28, email=test3@baomidou.com, phone=null)
        User(id=4, name=Sandy, age=21, email=test4@baomidou.com, phone=null)
        User(id=5, name=kaikeba, age=331, email=test4@baomidou.com, phone=null)
        User(id=6, name=Billie, age=24, email=test5@baomidou.com, phone=null)
     */
    
    @Test
    public void testUpdate1() {
        userMapper.update(null, Wrappers.<User>update().set("name","kkkBbb").like("name","Tom"));
        userMapper.selectList(null).forEach(System.out::println);
    }
    /*
        User(id=1, name=Jone, age=18, email=test1@baomidou.com, phone=null)
        User(id=2, name=Jack, age=20, email=test2@baomidou.com, phone=null)
        User(id=3, name=先科, age=28, email=test3@baomidou.com, phone=null)
        User(id=4, name=Sandy, age=21, email=test4@baomidou.com, phone=null)
        User(id=5, name=kaikeba, age=331, email=test4@baomidou.com, phone=null)
        User(id=6, name=Billie, age=24, email=test5@baomidou.com, phone=null)
     */
    
    @Test
    public void testUpdate2() {
        userMapper.update(new User().setName("kkkBbb"), Wrappers.<User>update().like("name","Tom"));
        userMapper.selectList(null).forEach(System.out::println);
    }
    /*
        User(id=1, name=Jone, age=18, email=test1@baomidou.com, phone=null)
        User(id=2, name=Jack, age=20, email=test2@baomidou.com, phone=null)
        User(id=3, name=kkkBbb, age=28, email=test3@baomidou.com, phone=null)
        User(id=4, name=Sandy, age=21, email=test4@baomidou.com, phone=null)
        User(id=5, name=kaikeba, age=331, email=test4@baomidou.com, phone=null)
        User(id=6, name=Billie, age=24, email=test5@baomidou.com, phone=null)
     */

查询

查询测试 展开
@Test
    public void testFindByBasic() {
        System.out.println(userMapper.selectList(Wrappers.<User>query().eq("name","Jone")));
    }
    /*
        [User(id=1, name=Jone, age=18, email=test1@baomidou.com, phone=null)]
     */
    
    @Test
    public void testFindProjection1() {
        userMapper.selectList(new QueryWrapper<User>().select("id","name")).forEach(System.out::println);
    }
    /*
        User(id=1, name=Jone, age=null, email=null, phone=null)
        User(id=2, name=Jack, age=null, email=null, phone=null)
        User(id=3, name=Tom, age=null, email=null, phone=null)
        User(id=4, name=Sandy, age=null, email=null, phone=null)
        User(id=5, name=kaikeba, age=null, email=null, phone=null)
        User(id=6, name=Billie, age=null, email=null, phone=null)
     */
    
    @Test
    public void testFindProjection2() {
        userMapper.selectList(new QueryWrapper<User>().select("id","name").like("name","J")).forEach(System.out::println);
    }
    /*
        User(id=1, name=Jone, age=null, email=null, phone=null)
        User(id=2, name=Jack, age=null, email=null, phone=null)
     */
    
    @Test
    public void testFindProjection3() {
        userMapper.selectList(new QueryWrapper<User>().select("id","name").lambda().like(User::getName,"J")).forEach(System.out::println);
    }
    /*
        User(id=1, name=Jone, age=null, email=null, phone=null)
        User(id=2, name=Jack, age=null, email=null, phone=null)
     */

# 自定义 SQL

自定义SQL是写在 Mapper接口的方法上 , 值直接写SQL语句

注解 说明
@Insert 插入
@Update 更新
@Delete 删除
@Select 查询

CRUD按照指定的规则编写SQL即可 , 如果需要传递参数 点击跳转

@Mapper
public interface UserMapper extends BaseMapper<User> {
    @Select("select * from users")
    List<User> findAll();
}

# 条件构造器

条件构造器主要作用在 SQL语句中添加Where条件 , 从而自动生成约束的SQL . 主要比较贴合 Hibernate 的使用方式

条件构造器两大分类 : (它们的父类 AbstractWrapper抽象类)

  • QueryWrapper
  • UpdateWrapper

以上有各自独有的属性详细自行官网查询 条件构造器更多详细 (opens new window)

应用 :

// 最终Where约束语句 (默认全参存在)
// select xxx from xxx where
// 		(ex.del_flag=0 AND ex.examine_user_id=su.id AND su.office_id=so.id) and
// 		(ex.type=?) and (su.name like '%?%') and (so.id=?);
@Override
public List<ExamineDo> selectByCondition(Map<String, Object> map) {

    QueryWrapper<ExamineDo> query = new QueryWrapper<>();

    // 三表连接的 关键字段的 SQL约束代码
    query.apply("ex.del_flag=0 AND ex.examine_user_id=su.id AND su.office_id=so.id");

    /**
     * SQL约束拼接参数说明:
     *   参数1.判断该对象是否可行(指该属性数据是有效且不为空
     *   参数2.指定比较的字段 字符串(一般指定的字符串
     *   参数3.指定比较的数据 外面获取到的
     */
    query.eq(map.containsKey("type") && !ObjectUtils.isEmpty(map.get("type")),"ex.type",map.get("type"))
            .like(map.containsKey("name") && !ObjectUtils.isEmpty(map.get("name")),"su.name",map.get("name"))
            .eq(map.containsKey("officeId") && !ObjectUtils.isEmpty(map.get("officeId")),"so.id",map.get("officeId"));
	// Mapper传递对象即可
    return baseMapper.selectByCondition(query);
}

# 传参操作

手写SQL多多少少都会需要参数的传递 , 因此有以下三种方式进行传递参数 :

  1. 实体类 根据实体的 属性 进行匹配信息
  2. Map 根据Map哈希中的 K键 匹配 V值
  3. @Param 根据 参数值 映射匹配
  4. 条件构造器 只需添加一个对象即可自动生成 约束SQL 官方说明 : 条件构造器使用方式 (opens new window)

示例:

// 实体类
// 实体类包含的属性JSON展示 Users{id,name}
@Select("SELECT su.*  " +
        "FROM  " +
        "sys_user su " +
        "WHERE " +
        "su.id= #{id} " +
        "AND su.name= #{name} " )
List<SysUser> findByid(Users user);

// Map
// map = {id:23,name:"张三"}
@Select("SELECT su.*  " +
        "FROM  " +
        "sys_user su " +
        "WHERE " +
        "su.id= #{id} " +
        "AND su.name= #{name} " )
List<SysUser> findByid(Map<String,Object> map);

// @Param
@Select("SELECT su.*  " +
        "FROM  " +
        "sys_user su " +
        "WHERE " +
        "su.id= #{id} " )
List<SysUser> findByid(@Param("id")Integer id);

// 条件构造器
@Select("select * from mysql_data ${ew.customSqlSegment}")
List<MysqlData> getAll(@Param(Constants.WRAPPER) Wrapper wrapper);

# 多表查询

多个表查询难免会有些稍微复杂的SQL . 多表查询分为 一对多/一对一/多对多 三种类型

注解 以往标签 说明
@Result <id>/<Result> 结果集封装 . 包含有以下属性 :
- column : 数据表字段名称
- property : 类中对应的属性名
- one : 与@One搭配 , 进行一对一的映射
- many : 与@Many搭配 , 进行一对多的映射
@Results <resultMap> 和@Result 使用 , 封装 一个/多个 结果集
@One <assocation> 一对一结果集封装 , 使用格式如下 :
@Result(column="xx",property="xx",one=@One(select="xx",...))
@Many <collection> 一对多结果集封装 , 使用格式如下 :
@Result(column="xx",property="xx",many=@Many(select="xx",...))

注意 :

  • 一旦使用了 @Results注解 封装的当前对象全部属性都要重新手写
  • 使用 @One/@Many 注解 , 一般情况使用 select属性值 指定全限定名类的方法(如: ById/...)

应用

主要编写核心部分 , 其他代码简单表示即可

User 用户实体

类型 名称 表对应的字段 注解规则
int id id
String username username
String password password
List<User> orderList oid(提取二查) @TableField(exist = false)

Order 订单实体

类型 名称 表对应的字段 注解规则
String id id
Date ordertime ordertime
double total total
User user uid(提取二查) @TableField(exist = false)

一对多 一人有多个订单 UserMapper接口

@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 查所用用户并且包含订单
    @Select("select * from user")
    @Results({
            @Result(column = "id", property = "id"),
            @Result(column = "username", property = "username"),
            @Result(column = "password", property = "password"),
            @Result(column = "id", property = "orderList",javaType = List.class,
                    many = @Many(select = "com.sans.demoapplication.mapper.OrderMapper.findByUId"))
    })
    List<User> findAll();
}

@Many注解中属性seelct的值 : 是指定路径类的方法

多对多 每个订单必须有一个用户 OrderMapper接口

@Mapper
public interface OrderMapper extends BaseMapper<Order> {

    // 查所有
    @Select("SELECT  id,ordertime,total,uid  FROM `order`")
    @Results({
            @Result(column = "id",property = "id"),
            @Result(column = "ordertime",property = "ordertime"),
            @Result(column = "total",property = "total"),
            @Result(column = "uid", property = "user" ,javaType = User.class ,
                    one = @One(select = "com.sans.demoapplication.mapper.UserMapper.selectById"))
    })
    List<Order> findAllOrder();

    // 按uid 查订单
    @Select("select id,ordertime,total from `order` where uid=#{uid}")
    List<Order> findByUId(int uid);

}

@One注解中属性seelct的值 : 是指定路径类的方法 (该类继承有 BaseMapper接口 里面有内置的CRUD)

# 分页插件

以下分页功能的实现 , 基于以上的基础进行实现

分页应用方式有3种形式:

  • 内置分页
  • XML分页
  • PageHelper分页

三种分页区别

内置分页 XML分页 PageHelper分页
jar包引入 无 无 有
配置 拦截器配置 全局配置 + 手写SQL 引入Bean
分页信息 简略 自定义 详细
复杂度 低 高 一般

# 内置分页

  1. 创建 mp配置类 MybatisPlusConfig.java ,全限定名类 : com.config.MybatisPlusConfig

    package com.config;
    
    import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class MybatisPlusConfig {
        
        /**
         * 分页插件
         */
        @Bean
        public PaginationInterceptor paginationInterceptor() {
            PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
            // 开启 count 的 join 优化,只针对 left join !!!
            paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
            return paginationInterceptor;
        }
        
    }
    
  2. 测试

    @Autowired
    private UserMapper mapper;
    
    //····
    
    @Test
    public void testSelectPage() {
        
        Page<User> page = new Page<>(2, 3);
        Page<User> result = mapper.selectPage(page, Wrappers.<User>query());
    
        result.getRecords().forEach(System.out :: println);
        System.out.println("总数:" + result.getTotal());
        System.out.println("总页数:" + result.getPages());
        System.out.println("每行数:" + result.getSize());
    
        /**
         * 验证分页信息
         *      1. 总数 > 3
         *      2. 页总数 = 3
          */
        assertThat(result.getTotal()).isGreaterThan(3);
        assertThat(result.getRecords().size()).isEqualTo(3);
        
    }
    
    /*
    
    User(id=4, name=Jack, age=20, email=test2@baomidou.com)
    User(id=5, name=Jack, age=20, email=test2@baomidou.com)
    User(id=6, name=Jack, age=20, email=test2@baomidou.com)
    总数:17
    总页数:6
    每行数:3
    
    */
    

# xml分页

  1. 添加属性 ,全局配置文件 application.yml

    mybatis-plus :
      type-aliases-package : com.pojo.User
      mapper-locations: classpath:/mapper/*.xml
    
  2. 映射类添加方法 UserMapper.java

    @Mapper
    public interface UserMapper extends BaseMapper<User> {
        
        /**
         * 用户列表分页查询 (xml)
         * Param()注解:替换了原旧名称进行应用参数属性 如 p.属性、c.属性
         * @param page 分页对象
         * @param conditioin 约束查询数据
         * @return
         */
        public Page<User> selectUserByPage(@Param ("p") IPage<User> page, @Param("c") User conditioin);
    }
    
  3. 创建映射文件 UserMapper.xml ,路径 resources/mapper/UserMapper.xml

    <?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.mapper.UserMapper">
    
        <sql id="selectSql">
            SELECT `user`.id,`user`.name,`user`.age,`user`.email
            FROM user
        </sql>
    
        <select id="selectUserByPage" resultType="user">
            <include refid="selectSql"></include>
            <where>
                <if test="c.age !=null">
                    age = #{c.age}
                </if>
                <if test="c.email !=null">
                    and email like '%${c.email}%'
                </if>
            </where>
        </select>
    
    </mapper>
    

    注意: namespace 属性指定的值是 实现的接口

  4. 测试

    //xml分页
    @Test
    public void testSelectUserByPage() {
        Page<User> page = new Page<>(1,2);
    
        User u = new User();
        u.setAge(20);
        u.setEmail("test2");
        
        Page<User> pr = mapper.selectUserByPage(page , u);
        
        
        System.out.println("总数:" + pr.getTotal());
        System.out.println("总页数:" + pr.getPages());
        System.out.println("每行数:" + pr.getSize());
        System.out.println("===========");
        pr.getRecords().forEach(System.out::println);
    }
    
    /*
    
    总数:13
    总页数:7
    每行数:2
    ===========
    User(id=2, name=Jack, age=20, email=test2@baomidou.com)
    User(id=3, name=Jack, age=20, email=test2@baomidou.com)
    
    */
    

    注意: 约束条件查询结果条数 必须要 大于 分页每页数

# pagehelper分页

  1. 引入独有依赖 pom.xml

    <!--pagehelper分页-->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>5.1.11</version>
    </dependency>
    
  2. 编辑 mp配置类 MybatisPlusConfig.java ,全限定名:com.config.MybatisPlusConfig

    package com.config;
    
    import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
    import com.github.pagehelper.PageInterceptor;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @MapperScan("com.mapper")
    public class MybatisPlusConfig {
        
        //···
        
        /**
         * pagehelper的分页插件
         */
        @Bean
        public PageInterceptor pageInterceptor() {
            return new PageInterceptor();
        }
        
    }
    
  3. 映射类添加方法 UserMapper.java (可选测试)

    package com.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.baomidou.mybatisplus.core.metadata.IPage;
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.sans.pojo.User;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    
    @Mapper
    public interface UserMapper extends BaseMapper<User> {
        
        //···
        
        /**
         * 用户列表分页查询 (pagehelper)
         * @param conditioin 约束查询数据
         * @return
         */
        public List<User> selectUserByPage2(User conditioin);
        
    }
    
  4. 编辑映射文件 UserMapper.xml ,路径 resources/mapper/UserMapper.xml(可选测试)

    <?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.sans.mapper.UserMapper">
    
        <sql id="selectSql">
            SELECT `user`.id,`user`.name,`user`.age,`user`.email
            FROM user
        </sql>
    
        <!-- ····· -->
    
        <!-- pagehelper 映射分页查询-->
        <select id="selectUserByPage2" resultType="user">
            <include refid="selectSql"></include>
            <where>
                <if test="age !=null">
                    age = #{age}
                </if>
                <if test="email !=null">
                    and email like '%${email}%'
                </if>
            </where>
        </select>
    
    </mapper>
    
  5. 测试

    // pagehelper分页
    @Test
    public void testSelectUserByPage2() {
    
        User u = new User();
        u.setAge(20);
        u.setEmail("test2");
        PageInfo<User> page = PageHelper.startPage(1,2).doSelectPageInfo(() ->{
            // 方法选择测试 (他们测试结果一致)
            // 1. 自定义xml
            mapper.selectUserByPage2(u);
            // 2. mp 内置方法
            // mapper.selectList(Wrappers.<User>query().eq("age",20).like("email","test2"));
        });
    
        page.getList().forEach(System.out :: println);
    
        System.out.println("===========");
    
        System.out.println("总行数=" + page.getTotal());
        System.out.println("总页数=" + page.getPages());
        System.out.println("每页行数=" + page.getPageSize());
    
        System.out.println("当前页=" + page.getPageNum());
        System.out.println("起始行数=" + page.getStartRow());
    
        System.out.println("是第一页=" + page.isIsFirstPage());
        System.out.println("是最后页=" + page.isIsLastPage());
    
        System.out.println("还有下一页=" + page.isHasNextPage());
        System.out.println("还有上一页=" + page.isHasPreviousPage());
    
        System.out.println("页码列表" + Arrays.toString(page.getNavigatepageNums()));
    }
    
    /*
    
    User(id=2, name=Jack, age=20, email=test2@baomidou.com)
    User(id=3, name=Jack, age=20, email=test2@baomidou.com)
    ===========
    总行数=13
    总页数=7
    每页行数=2
    当前页=1
    起始行数=1
    是第一页=true
    是最后页=false
    还有下一页=true
    还有上一页=false
    页码列表[1, 2, 3, 4, 5, 6, 7]
    
    */
    

官方文档:MyBatis-Plus (baomidou.com) (opens new window)

# 反向工程

官方在 3.5.1 以上和以下 分别 生成方式都不一样,因此做了两个示例

工程配置文档:添加跳转 (opens new window)

# 3.5.1之前

步骤:

  1. 引入必要jar freemarker模板、lombok简化实体、mybatis-plus-generator生成核心

    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.31</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.4.1</version>
    </dependency>
    

    生成后可以直接删除 freemarker模板、mybatis-plus-generator生成核心

  2. 反向工程启动类

    必要提示说明:

    • 数据源配置
    • 作者
    • 生成路径
    • 模组名(启动输入
    • 表名(启动输入
    代码展开
    import com.baomidou.mybatisplus.annotation.FieldFill;
    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
    import com.baomidou.mybatisplus.core.toolkit.StringPool;
    import com.baomidou.mybatisplus.core.toolkit.StringUtils;
    import com.baomidou.mybatisplus.generator.AutoGenerator;
    import com.baomidou.mybatisplus.generator.InjectionConfig;
    import com.baomidou.mybatisplus.generator.config.*;
    import com.baomidou.mybatisplus.generator.config.po.TableFill;
    import com.baomidou.mybatisplus.generator.config.po.TableInfo;
    import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
    import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Scanner;
    
    public class MysqlGenerator {
    
        /**
         * <p>
         * 读取控制台内容
         * </p>
         */
        public static String scanner(String tip) {
            Scanner scanner = new Scanner(System.in);
            StringBuilder help = new StringBuilder();
            help.append("请输入" + tip + ":");
            System.out.println(help.toString());
            if (scanner.hasNext()) {
                String ipt = scanner.next();
                if (StringUtils.isNotBlank(ipt)) {
                    return ipt;
                }
            }
            throw new MybatisPlusException("请输入正确的" + tip + "!");
        }
    
        public static void main(String[] args) {
            // 代码生成器
            AutoGenerator mpg = new AutoGenerator();
    
            // 全局配置
            GlobalConfig gc = new GlobalConfig();
            String projectPath = System.getProperty("user.dir");
            /*
            指定工程名称
            指定作者
            *  */
            gc.setOutputDir(projectPath + "/NewsSys/src/main/java");
            gc.setAuthor("sasn");
            gc.setOpen(false);
            gc.setIdType(IdType.AUTO);//设置全局id自增
            gc.setBaseResultMap(true);//设置生成BaseResultMap
            // gc.setSwagger2(true); 实体属性 Swagger2 注解
            mpg.setGlobalConfig(gc);
    
            // 数据源配置
            /* 写自己的连接源 */
            DataSourceConfig dsc = new DataSourceConfig();
            dsc.setUrl("jdbc:mysql://localhost:3306/test?serverTimezone=UTC");
            // dsc.setSchemaName("public");
            dsc.setDriverName("com.mysql.jdbc.Driver");
            dsc.setUsername("root");
            dsc.setPassword("root");
            
            // 库数据 和 实体数据字段手动匹配配置
            dsc.setTypeConvert(new MySqlTypeConvert() {
                @Override
                public IColumnType processTypeConvert(@org.jetbrains.annotations.NotNull GlobalConfig globalConfig,
                                                      @org.jetbrains.annotations.NotNull String fieldType) {
                    // 比较库字段类型
                    if ("datetime".equals(fieldType)) {
                        // 满足则返回需要对应的实体类型
                        return DbColumnType.DATE;
                    }
                    if ("float".equals(fieldType)) {
                        return DbColumnType.BASE_DOUBLE;
                    }
                    switch (fieldType) {
                        case "text" :
                        case "mediumtext" :
                            return DbColumnType.STRING;
                        default:
                            break;
                    }
                    return super.processTypeConvert(globalConfig, fieldType);
                }
            }
            
            mpg.setDataSource(dsc);
    
            // 包配置
            /* 指定模块名称 */
            PackageConfig pc = new PackageConfig();
            pc.setModuleName(scanner("模块名"));
            pc.setParent("com.sans");
            mpg.setPackageInfo(pc);
    
            // 自定义配置
            InjectionConfig cfg = new InjectionConfig() {
                @Override
                public void initMap() {
                    // to do nothing
                }
            };
    
            // 如果模板引擎是 freemarker  从依赖包的 templates下查找模板
            String templatePath = "/templates/mapper.java.ftl";
            // 如果模板引擎是 velocity
            // String templatePath = "/templates/mapper.xml.vm";
    
            // 自定义输出配置
            List<FileOutConfig> focList = new ArrayList<>();
            // 自定义配置会被优先输出
            focList.add(new FileOutConfig(templatePath) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                    return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                            + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
                }
            });
            /*
            cfg.setFileCreate(new IFileCreate() {
                @Override
                public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
                    // 判断自定义文件夹是否需要创建
                    checkDir("调用默认方法创建的目录,自定义目录用");
                    if (fileType == FileType.MAPPER) {
                        // 已经生成 mapper 文件判断存在,不想重新生成返回 false
                        return !new File(filePath).exists();
                    }
                    // 允许生成模板文件
                    return true;
                }
            });
            */
            cfg.setFileOutConfigList(focList);
            mpg.setCfg(cfg);
    
            // 配置模板
           // TemplateConfig templateConfig = new TemplateConfig();
    
            // 配置自定义输出模板
            //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
            // templateConfig.setEntity("templates/entity2.java");
            // templateConfig.setService();
            // templateConfig.setController();
    
            //templateConfig.setXml(null);
           // mpg.setTemplate(templateConfig);
    
            // 策略配置
            StrategyConfig strategy = new StrategyConfig();
            strategy.setNaming(NamingStrategy.underline_to_camel);
            strategy.setColumnNaming(NamingStrategy.underline_to_camel);
    //        strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
            strategy.setEntityLombokModel(true);
            strategy.setRestControllerStyle(true);
            // 公共父类
    //        strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
            // 写于父类中的公共字段
    //        strategy.setSuperEntityColumns("id");
            strategy.setEnableSqlFilter(false);//开启支持输入正则表达式
            strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
            strategy.setControllerMappingHyphenStyle(true);
            strategy.setTablePrefix(pc.getModuleName() + "_");
    
            //设置生成自动填充注解的表字段
            ArrayList<TableFill> list = new ArrayList<>();
            list.add(new TableFill("update_date", FieldFill.INSERT_UPDATE));
            list.add(new TableFill("create_date", FieldFill.INSERT));
            list.add(new TableFill("del_flag", FieldFill.INSERT));
            strategy.setTableFillList(list);
            strategy.setLogicDeleteFieldName("del_flag");//设置生成逻辑删除注解对应表字段名
            mpg.setStrategy(strategy);
            mpg.setTemplateEngine(new FreemarkerTemplateEngine());
            mpg.execute();
        }
    }
    

# 3.5.1之后

步骤:

  1. 引入必要jar freemarker模板、annotations配置注解应用、mybatis-plus-generator生成核心

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.5.2</version>
    </dependency>
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.31</version>
    </dependency>
    <dependency>
        <groupId>org.jetbrains</groupId>
        <artifactId>annotations</artifactId>
        <version>16.0.1</version>
    </dependency>
    

    生成后可以直接删除 freemarker模板、mybatis-plus-generator生成核心

  2. 反向工程启动类

    注意参数的填充

    代码展开
    import com.baomidou.mybatisplus.generator.FastAutoGenerator;
    import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
    import com.baomidou.mybatisplus.generator.config.GlobalConfig;
    import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
    import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
    import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
    import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
    import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
    
    public class BuilderApplication {
    
        public static void main(String[] args) {
    
            String url = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
            String username = "root";
            String passwoed = "root";
            String baomidou = "柏竹";
            String packagePath = "com.sans";
            String generatePath = "D:\\Code\\Java\\Drill\\Guangdong embedded\\01 Study\\JavaEE\\220607SpringCloud\\220607WebService\\220607WebService\\Restful-Server\\src\\main\\java";
    
            DataSourceConfig.Builder dataSourceBuilder = new DataSourceConfig.Builder(url, username, passwoed)
                    .dbQuery(new MySqlQuery())
                    .typeConvert(new MySqlTypeConvert() {
                        @Override
                        public IColumnType processTypeConvert(@org.jetbrains.annotations.NotNull GlobalConfig globalConfig,
                                                              @org.jetbrains.annotations.NotNull String fieldType) {
                            // 比较库字段类型
                            if ("datetime".equals(fieldType)) {
                                // 满足则返回需要对应的实体类型
                                return DbColumnType.DATE;
                            }
                            return super.processTypeConvert(globalConfig, fieldType);
                        }
                    });
    
    
            /**
             * 配置文档:https://baomidou.com/pages/981406/
             */
            FastAutoGenerator.create(dataSourceBuilder)
                    // 全局配置
                    .globalConfig(builder -> {
                        builder.author(baomidou)
    //                            .enableSwagger()
                                .disableOpenDir()
                                .fileOverride()
                                .outputDir(generatePath); // 指定输出目录
                    })
                    // 包配置
                    .packageConfig(builder -> {
                        builder.parent(packagePath); // 设置父包名
    //                            .moduleName(moduleName); // 设置父包模块名
    //                            .pathInfo(Collections.singletonMap(OutputFile.mapper, XMLPath)); // 设置mapperXml生成路径
                    })
                    // 策略配置
                    .strategyConfig(builder -> {
                        // 指定表
                        builder.addInclude("book") // 设置需要生成的表名
    //                            .addInclude("news_detail")
                                .enableCapitalMode()
                                // Entity 策略配置
                                // 逻辑删除/乐观锁 字段
                                .entityBuilder()
                                .versionColumnName("version")
                                .versionPropertyName("version")
                                .logicDeleteColumnName("deleted")
                            	/.enableLombok() // 启动 lombok 模型
                                .mapperBuilder()
                                .enableBaseResultMap()
                                .enableMapperAnnotation()
                        ;
                    })
                    .templateEngine(new FreemarkerTemplateEngine())  // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                    .execute();
        }
    }
    

# SQL日志

日志打印通过 p6spy实现日志打印 , 通过数据源层级进行代理监听SQL , 代理驱动 com.mysql.cj.jdbc.Driver

maven依赖

<dependency>
    <groupId>p6spy</groupId>
    <artifactId>p6spy</artifactId>
    <version>3.9.1</version>
</dependency>

配置

数据源配置 spring.datasource.dynamic.p6spy 设置为 true (生产环境不建议启用该功能)

更多细节配置 spy.properties配置文件

# p6spy 性能分析插件配置文件
# mybatis-plus 也实现了支持p6spy的日志打印
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
# 日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
#deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# SQL语句打印时间格式
databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录 (超过2秒记录问题)
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
# 是否过滤 Log
filter=true
# 过滤 Log 时所排除的 sql 关键字,以逗号分隔 (排除检测数据库存活的SQL)
exclude=SELECT 1
#SQL#MyBatisPlus

← SpringBoot Redis 整合 SpringBoot JSON 整合→

最近更新
01
HTTPS自动续签
10-21
02
博客搭建-简化版(脚本)
10-20
03
ruoyi-vue-plus-部署篇
07-13
更多文章>
Theme by Vdoing | Copyright © 2019-2024 | 桂ICP备2022009417号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式