springboot2.3整合mybatis-plus3.3.2较为详细的教程

springboot2.3整合mybatis-plus3.3.2较为详细的教程

  • 前言
  • 项目环境
    • maven依赖如下
    • 项目配置如下
    • 建表语句如下
    • 使用mybatis-plus代码生成插件生成代码
    • 配置分页插件
    • 启动类加扫描dao注解
  • mabatis-plus 基础演示
  • mybatis-plus的条件构造器
  • 自定义sql语句

前言

mybatis官网
Mybatis-Plus是一个Mybatis框架的增强插件,核心理念
是为简化开发而生
根据官方描述,MP只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑.并且只需简单配置,即可快速进行 CRUD 操作,从而节省大量时间.代码生成,分页,性能分析等功能一应俱全。

项目环境

ide工具:idea
springboot版本:2.3.0
mybatis-plus:3.3.2
jdk:12
数据库:MySQL(版本8.0+)

maven依赖如下

  

        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        

        
            org.springframework.boot
            spring-boot-starter-web
        

        
            mysql
            mysql-connector-java
            runtime
        

        
        
            com.alibaba
            druid-spring-boot-starter
            1.1.21
        

        
            org.projectlombok
            lombok
            true
        

        
            com.baomidou
            mybatis-plus-boot-starter
            3.3.2
        

        
        
            com.baomidou
            mybatis-plus-generator
            3.3.2
        

        
        
            org.freemarker
            freemarker
            2.3.30
        

        
        
        
        
            com.github.xiaoymin
            knife4j-spring
            1.9.6
        
        
            com.github.xiaoymin
            knife4j-spring-ui
            1.9.6
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        
    

项目配置如下

# 配置端口号
server:
  port: 8080

# 数据源配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mp_test?useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 自己的数据库连接密码
    type: com.alibaba.druid.pool.DruidDataSource
    #模板引擎设置
  thymeleaf:
    mode: HTML
    encoding: UTF-8
    servlet:
      content-type: text/html
     # 开发时关闭缓存,页面实时刷新
    cache: false

# mybatis- plus配置
mybatis-plus:
  # xml扫描,多个目录用逗号或者分号隔开隔开
  mapper-locations: classpath:mapper/*.xml
    # 以下配置均有默认值,可以不设置
  global-config:
    db-config:
        #主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
      id-type: auto
  configuration:
      # 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
      map-underscore-to-camel-case: true
      # 返回map时true:当查询数据为空时字段返回为null,false:不加这个查询数据为空时,字段将被隐藏
      call-setters-on-nulls: true
      # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

建表语句如下

create schema mp_test;
use mp_test;
CREATE TABLE `mp_user` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `name` varchar(32) DEFAULT NULL COMMENT '姓名',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `skill` varchar(32) DEFAULT NULL COMMENT '技能',
  `evaluate` varchar(64) DEFAULT NULL COMMENT '评价',
  `fraction` bigint(11) DEFAULT NULL COMMENT '分数',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表';

INSERT INTO `mp_user` VALUES (1, '小明', 20, '画画', '该学生在画画方面有一定天赋', 89);
INSERT INTO `mp_user` VALUES (2, '小兰', 19, '游戏', '近期该学生由于游戏的原因导致分数降低了', 64);
INSERT INTO `mp_user` VALUES (3, '张张', 18, '英语', '近期该学生参加英语比赛获得二等奖', 90);
INSERT INTO `mp_user` VALUES (4, '大黄', 20, '体育', '该学生近期由于参加篮球比赛,导致脚伤', 76);
INSERT INTO `mp_user` VALUES (5, '大白', 17, '绘画', '该学生参加美术大赛获得三等奖', 77);
INSERT INTO `mp_user` VALUES (7, '小龙', 18, 'JAVA', '该学生是一个在改BUG的码农', 59);
INSERT INTO `mp_user` VALUES (9, 'Sans', 18, '睡觉', 'Sans是一个爱睡觉,并且身材较矮骨骼巨大的骷髅小胖子', 60);
INSERT INTO `mp_user` VALUES (10, 'papyrus', 18, 'JAVA', '个性张扬的骷髅,给人自信、有魅力的骷髅小瘦子', 58);
INSERT INTO `mp_user` VALUES (11, '小红', 12, '画肖像', '小红是一个很红的女孩', 61);
INSERT INTO `mp_user` VALUES (12, 'Tom', 7, '理发', '全世界的理发师统称为tom老师', 61);
INSERT INTO `mp_user` VALUES (13, '小黑', 3, NULL, NULL, 61);
INSERT INTO `mp_user` VALUES (14, '楚子航', 24, '君焰', '杀胚一个', 99);
INSERT INTO `mp_user` VALUES (15, '路明非', 6, '自爆', '废材一个', 60);

使用mybatis-plus代码生成插件生成代码

在测试包新建CodeGenerator.java类
代码如下

package com.wlf.demo;

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.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;
/**
 * @author wan [email protected]
 * @version 1.0
 * @className CodeGenerator
 * @date 2020/6/5 9:35
 **/

public class CodeGenerator {
    /**
     * 

* 读取控制台内容 *

*/ 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.isNotEmpty(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 + "/src/main/java"); //这里你填上自己想自己的用户,也可以不填 gc.setAuthor("无良芳"); gc.setOpen(false); //这里可以设置为false,是一个api工具类 gc.setSwagger2(true); //实体属性 Swagger2 注解 mpg.setGlobalConfig(gc); // 数据源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://localhost:3306/mp_test?serverTimezone=GMT%2B8"); // dsc.setSchemaName("public"); dsc.setDriverName("com.mysql.cj.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("你的数据库密码"); mpg.setDataSource(dsc); // 包配置 PackageConfig pc = new PackageConfig(); pc.setModuleName(scanner("模块名")); //这里需要填上自己的项目包路径。 pc.setParent("com.wlf.demo"); mpg.setPackageInfo(pc); // 自定义配置 InjectionConfig cfg = new InjectionConfig() { @Override public void initMap() { // to do nothing } }; // 如果模板引擎是 freemarker String templatePath = "/templates/mapper.xml.ftl"; // 如果模板引擎是 velocity // String templatePath = "/templates/mapper.xml.vm"; // 自定义输出配置 List 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; return projectPath + "/src/main/resources/mapper/" + 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.setInclude(scanner("表名,多个英文逗号分割").split(",")); strategy.setControllerMappingHyphenStyle(true); // strategy.setTablePrefix(pc.getModuleName() + "_"); //去除表名的前缀 strategy.setTablePrefix("mp_"); mpg.setStrategy(strategy); mpg.setTemplateEngine(new FreemarkerTemplateEngine()); mpg.execute(); } }

直接运行此类,提示输入模块名就是新的包名,作者在这里输入的是
mp,然后提示你输入表名,按规定输入表名回车,即可生成代码。
项目结构图
springboot2.3整合mybatis-plus3.3.2较为详细的教程_第1张图片这里我说一下项目结构,和以前的ssm项目结构差不多,
config 一些配置类。
controller 控制层,接受处理请求
entity 实体类,没啥好说的。
mapper dao层,数据库连接层
service 服务层 处理一些复杂的服务,一般来说,不建议在控制层里写过多的代码。控制层只用来发送和接受数据,对数据的处理业务统统放在service层。

配置分页插件

项目下新建config包,在此包下新建MybatisPlusConfig.java类
详细代码如下

@Configuration
public class MybatisPlusConfig {
    /**
     * 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }
}

启动类加扫描dao注解

@SpringBootApplication
@MapperScan("com.wlf.demo.mp.mapper") //扫描dao
public class SpringbootMybatisPlusApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootMybatisPlusApplication.class, args);
    }

}

到这里环境搭建已经完成。

mabatis-plus 基础演示

到这里我们可以看一看生成的代码service的实现类里面没有任何代码,MyBatis-Plus官方封装了许多基本CRUD的方法,可以直接使用大量节约时间,MP共通方法详见IService,ServiceImpl,BaseMapper源码,写入操作在ServiceImpl中已有事务绑定,这里我们列举一下常用的方法演示。
原本是打算写一个前端页面更直观的进行测试,算了算了,用插件测试测试得了

@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private IUserService iUserService;

    /**
     * 根据用户id获取用户信息
     * @param id 用户id
     * @return User 用户实体
     */
    @GetMapping("/getUser")
    public User getUser(@RequestParam("id") Integer id){
        return iUserService.getById(id);
    }

    /**
     * 查询全部信息
     * @return 返回用户实体类集合
     */
    @GetMapping("/getList")
    public List getList(){
        return iUserService.list();
    }

    /**
     * 分页查询全部数据
     * 这里只做演示,不写前端
     * @return IPage 分页数据
     */
    @GetMapping("/getUserListPage")
    public IPage getUserListPage(){
        IPage page = new Page<>();
        //当前页
        page.setCurrent(4);
        //每页条数
        page.setSize(2);
        return iUserService.page(page);
    }

    /**
     * 根据指定字段查询用户信息集合
     * @Return Collection 用户实体集合
     */
    @GetMapping("/getListMap")
    public Collection getListMap(){
        Map map = new HashMap<>();
        //kay是字段名 value是字段值
        map.put("age",20);
        return iUserService.listByMap(map);
    }
    /**
     * 新增用户信息
     */
    @GetMapping("/saveUser")
    public void saveUser(){
        User userInfoEntity = new User();
        userInfoEntity.setName("陈墨瞳");
        userInfoEntity.setSkill("侧写");
        userInfoEntity.setAge(18);
        userInfoEntity.setFraction(99L);
        userInfoEntity.setEvaluate("无言灵,长得漂亮");
        iUserService.save(userInfoEntity);
    }
    /**
     * 批量新增用户信息
     */
    @RequestMapping("/saveUserList")
    public void saveUserList(){
        //创建对象
        User sans = new User();
        sans.setName("芬格尔");
        sans.setSkill("睡觉");
        sans.setAge(18);
        sans.setFraction(60L);
        sans.setEvaluate("芬格尔是一个爱睡觉,并且身手十分了的");
        User papyrus = new User();
        papyrus.setName("零");
        papyrus.setSkill("镜瞳");
        papyrus.setAge(18);
        papyrus.setFraction(99L);
        papyrus.setEvaluate("高冷女王");
        //批量保存
        List list =new ArrayList<>();
        list.add(sans);
        list.add(papyrus);
        iUserService.saveBatch(list);
    }
    /**
     * 更新用户信息
     */
    @RequestMapping("/updateUser")
    public void updateUser(){
        //根据实体中的ID去更新,其他字段如果值为null则不会更新该字段,参考yml配置文件
        User userInfoEntity = new User();
        userInfoEntity.setId(1L);
        userInfoEntity.setAge(19);
        iUserService.updateById(userInfoEntity);
    }
    /**
     * 新增或者更新用户信息
     */
    @RequestMapping("/saveOrUpdateUser")
    public void saveOrUpdate(){
        //传入的实体类userInfoEntity中ID为null就会新增(ID自增)
        //实体类ID值存在,如果数据库存在ID就会更新,如果不存在就会新增
        User userInfoEntity = new User();
        userInfoEntity.setId(1L);
        userInfoEntity.setAge(20);
        iUserService.saveOrUpdate(userInfoEntity);
    }
    /**
     * 根据ID删除用户信息
     */
    @RequestMapping("/deleteUser")
    public void deleteInfo(String id){
        iUserService.removeById(id);
    }
    /**
     * 根据ID批量删除用户信息
     */
    @RequestMapping("/deleteUserList")
    public void deleteInfoList(){
        List userIdlist = new ArrayList<>();
        userIdlist.add("12");
        userIdlist.add("13");
        iUserService.removeByIds(userIdlist);
    }
    /**
     * 根据指定字段删除用户信息
     */
    @RequestMapping("/deleteUserMap")
    public void deleteInfoMap(){
        //kay是字段名 value是字段值
        Map map = new HashMap<>();
        map.put("skill","删除");
        map.put("fraction",10L);
        iUserService.removeByMap(map);
    }
    
}

这里推荐一个idea的插件,用来调试api十分方便
安装好后springboot2.3整合mybatis-plus3.3.2较为详细的教程_第2张图片就可以愉快的测试api接口了。

mybatis-plus的条件构造器

当查询条件复杂的时候,我们可以使用MP的条件构造器,请参考下面的QueryWrapper条件参数说明。

查询方式 方法说明 实例
eq 等价于等于 eq(“name”, “老王”)—>name = ‘老王’
allEq 全部eq(或个别isNull) allEq({id:1,name:“老王”,age:null}, false)—>id = 1 and name = ‘老王’
ne 不等于<> ne(“name”, “老王”)—>name <> ‘老王’
gt 大于 > gt(“age”, 18)—>age > 18
ge 大于等于 >= ge(“age”, 18)—>age >= 18
lt 小于 < lt(“age”, 18)—>age < 18
le 小于等于 <= le(“age”, 18)—>age <= 18
between BETWEEN 值1 AND 值2 between(“age”, 18, 30)—>age between 18 and 30
notBetween NOT BETWEEN 值1 AND 值2 notBetween(“age”, 18, 30)—>age not between 18 and 30
like LIKE ‘%值%’ like(“name”, “王”)—>name like ‘%王%’
notLike NOT LIKE ‘%值%’ notLike(“name”, “王”)—>name not like ‘%王%’
likeLeft LIKE ‘%值’ likeLeft(“name”, “王”)—>name like ‘%王’
likeRight LIKE ‘值%’ likeRight(“name”, “王”)—>name like ‘王%’
isNull 字段 IS NULL isNull(“name”)—>name is null
isNotNull 字段 IS NOT NULL isNotNull(“name”)—>name is not null
in 字段 IN (value.get(0), value.get(1), …)
字段 IN (v0, v1, …)
in(“age”,{1,2,3})—>age in (1,2,3)
in(“age”, 1, 2, 3)—>age in (1,2,3)
notIn 字段 NOT IN (value.get(0), value.get(1), …)
字段 NOT IN (v0, v1, …)
notIn(“age”,{1,2,3})—>age not in (1,2,3)
notIn(“age”, 1, 2, 3)—>age not in (1,2,3)
inSql 字段 IN ( sql语句 ) inSql(“age”, “1,2,3,4,5,6”)—>age in (1,2,3,4,5,6)
inSql(“id”, “select id from table where id < 3”)—>id in (select id from table where id < 3)
notInSql 字段 NOT IN ( sql语句 ) notInSql(“age”, “1,2,3,4,5,6”)—>age not in (1,2,3,4,5,6)
notInSql(“id”, “select id from table where id < 3”)—>id not in (select id from table where id < 3)
groupBy 分组:GROUP BY 字段, … groupBy(“id”, “name”)—>group by id,name
orderByAsc 排序:ORDER BY 字段, … ASC orderByAsc(“id”, “name”)—>order by id ASC,name ASC
orderByDesc 排序:ORDER BY 字段, … DESC orderByDesc(“id”, “name”)—>order by id DESC,name DESC
orderBy 排序:ORDER BY 字段, … orderBy(true, true, “id”, “name”)—>order by id ASC,name ASC
having HAVING ( sql语句 ) having(“sum(age) > 10”)—>having sum(age) > 10

having(“sum(age) > {0}”, 11)—>having sum(age) > 11
or 拼接 OR eq(“id”,1).or().eq(“name”,“老王”)—>id = 1 or name = ‘老王’
or OR 嵌套 or(i -> i.eq(“name”, “李白”).ne(“status”, “活着”))—>or (name = ‘李白’ and status <> ‘活着’)
and AND 嵌套 and(i -> i.eq(“name”, “李白”).ne(“status”, “活着”))—>and (name = ‘李白’ and status <> ‘活着’)
nested 正常嵌套 不带 AND 或者 OR nested(i -> i.eq(“name”, “李白”).ne(“status”, “活着”))—>(name = ‘李白’ and status <> ‘活着’)

下面演示了一些常见的实例,有一说一,就是一个字,香!!!
在controller包下新建一个UserPlusController类,代码如下,

@RestController
@RequestMapping("/userPlus")
public class UserPlusController {
    @Resource
    private IUserService iUserService;

    @GetMapping("/getUserListPage")
    public Map getUserListPage(){
        Map map = new HashMap<>();
        //查询成绩高于80的用户
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.lambda().gt(User::getFraction,80);
        List list = iUserService.list(wrapper);
        map.put("userfraction",list);

        //查询年龄大于5岁,小于等于15岁的同学
        QueryWrapper wrapper1 = new QueryWrapper<>();
        wrapper1.lambda().gt(User::getAge,5);
        wrapper1.lambda().le(User::getAge,15);
        List list1 = iUserService.list(wrapper1);
        map.put("userAge5~15",list1);

        //模糊查询技能字段带有画的数据,并且按照年龄降序
        QueryWrapper wrapper2 = new QueryWrapper<>();
        wrapper2.lambda().like(User::getSkill,"画");
        wrapper2.lambda().orderByDesc(User::getAge);
        List list2 = iUserService.list(wrapper2);
        map.put("UserAgeSkill", list2);

        //模糊查询名字带有"小"或者年龄大于18的学生
        QueryWrapper wrapper3 = new QueryWrapper<>();
        wrapper3.lambda().like(User::getName,"小");
        wrapper3.lambda().or().gt(User::getAge,18);
        List list3 = iUserService.list(wrapper3);
        map.put("userOr",list3);

        //查询评价不为null的学生,并分页
        IPage page = new Page<>();
        page.setCurrent(1);
        page.setSize(5);
        QueryWrapper wrapper4 = new QueryWrapper<>();
        wrapper4.lambda().isNotNull(User::getEvaluate);
        page =  iUserService.page(page,wrapper4);
        map.put("userPage",page);

        return map;
    }
}

自定义sql语句

你认为mp的条件构造器这么香了还需要自己写sql语句嘛,好吧,有些时候确实需要。介绍一下自定义sql语句,没啥难的,和以前没有mp一样,自己添加dao层接口,在mapper.xml里面写sql语句,就这还没完,mp对于自定义sql语句还有优化。香就完事了。没啥好说的看一张图吧。
在这里插入图片描述
回归正题。需求查询分数大于80的学生信息,并分页。
第一步,编写mapper.xml语句,看看这简洁分页查询语句,直接看语句你甚至都感觉不到这个语句竟然可以做到分页查询。这和普通的查询没什么区别嘛。


第二步,编写dao层代码,我直接贴代码

/**
     * 查询大于该分数的学生,并分页
     * @param page 分页参数
     * @param fraction 分数
     * @return 分页数据
     */
    IPage selectUserByFraction(IPage page,Long fraction);

这里再给大家推荐一个插件。
springboot2.3整合mybatis-plus3.3.2较为详细的教程_第3张图片装上之后dao层代码会有提示点击直接跳转到mapper文件中,也可以直接生成mapper标签。香!!!
springboot2.3整合mybatis-plus3.3.2较为详细的教程_第4张图片如图点击那个小鸟会有神奇的事情发生。
第三步,给service接口添加方法

 /**
     * 查询大于该分数的学生,并分页
     * @param page 分页参数
     * @param fraction 分数
     * @return 分页数据
     */
    IPage selectUserByFraction(IPage page, Long fraction);

再实现方法。

 @Override
    public IPage selectUserByFraction(IPage page, Long fraction) {
        return this.baseMapper.selectUserByFraction(page,fraction);
    }

最后我们controller测试一下,新建UserCustomController类

@RestController
@RequestMapping("/userCustom")
public class UserCustomController {
    @Resource
    private IUserService iUserService;

    /**
     * 查询分数大于80
     * @return 分页数据
     */
    @GetMapping("/getUserListSql")
    public IPage getUserListSql() {
        IPage page = new Page<>();
        page.setCurrent(1);
        page.setSize(2);
        return iUserService.selectUserByFraction(page, 80L);
    }

}

到这里文章也基本结束了。好的。
原本想弄个前端界面的,嗨,谁说前端简单我锤谁。
有什么问题可以评论区告诉我呦
项目源码点击这里

你可能感兴趣的:(springboot,spring,boot,mybatis)