springboot2集成mybatis-plus

一. MyBatis-Plus简介

简介:

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
另最新的3.x版本支持lambda()语法糖, 方便以代码方式组织SQL语句.
在这里插入图片描述

核心特性

卖点 说明
无侵入 只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小 启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
强大的 CRUD 操作 内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
支持 Lambda 形式调用 通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
支持主键自动生成 支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
支持 ActiveRecord 模式 支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
支持自定义全局通用操作 支持全局通用方法注入( Write once, use anywhere )
内置代码生成器 采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
内置分页插件 基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
分页插件支持多种数据库 支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
内置性能分析插件 可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
内置全局拦截插件 提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

支持数据库

mysql 、 mariadb 、 oracle 、 db2 、 h2 、 hsql 、 sqlite 、 postgresql 、 sqlserver
达梦数据库 、 虚谷数据库 、 人大金仓数据库

MP框架结构

在这里插入图片描述

代码托管

Gitee | Github

学习教程

官方教程:

非官方视频教程:

  1. MyBatis-Plus 入门 - 视频教程 - 慕课网
  2. MyBatis-Plus 进阶 - 视频教程 - 慕课网

二. springboot2集成mybatis-plus

2.1 项目构建

传送门: -IDEA创建SpringBoot项目

2.2 项目环境

软件 版本
JDK 1.8
SpringBoot 2.2.6.RELEASE
MyBatis-Plus 3.1.0

2.3 项目结构

在这里插入图片描述

2.4 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>mybatisplus</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springboot_mybatisplus</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<!--<version>5.1.47</version>-->
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- mybatisPlus 核心库 -->
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.1.0</version>
		</dependency>
		<!-- 引入阿里数据库连接池 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.1.6</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!--swagger start-->
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.9.2</version>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.9.2</version>
		</dependency>
		<!--swagger  end-->
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

2.5 springboot2 配置文件

# 配置端口
server:
  port: 8080 
spring:
  # 配置数据源
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://{IP}:{PORT}/user?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull
    username: xxxx
    password: xxxx
    type: com.alibaba.druid.pool.DruidDataSource
# mybatis 相关 configurations
mybatis-plus:
  # xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
  mapper-locations: classpath:mapper/*.xml
  # 以下配置均有默认值,可以不设置
  global-config:
    db-config:
      # 主键类型,大小写不敏感 AUTO:"数据库ID自增", INPUT:"用户输入ID", ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID"
      id-type: auto
      # 字段策略 IGNORED:"忽略判断"  NOT_NULL:"非 NULL 判断")  NOT_EMPTY:"非空判断"
      field-strategy: not_empty
      #数据库类型, 大小写不敏感
      db-type: mysql
  configuration:
    # 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
    map-underscore-to-camel-case: true
    # 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
    call-setters-on-nulls: true
    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2.6 构建测试data

-- 建表
CREATE TABLE `user_info` (
  `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 `user_info` VALUES (1, '小明', 20, '画画', '该学生在画画方面有一定天赋', 89);
INSERT INTO `user_info` VALUES (2, '小兰', 19, '游戏', '近期该学生由于游戏的原因导致分数降低了', 64);
INSERT INTO `user_info` VALUES (3, '张张', 18, '英语', '近期该学生参加英语比赛获得二等奖', 90);
INSERT INTO `user_info` VALUES (4, '大黄', 20, '体育', '该学生近期由于参加篮球比赛,导致脚伤', 76);
INSERT INTO `user_info` VALUES (5, '大白', 17, '绘画', '该学生参加美术大赛获得三等奖', 77);
INSERT INTO `user_info` VALUES (7, '小龙', 18, 'JAVA', '该学生是一个在改BUG的码农', 59);
INSERT INTO `user_info` VALUES (9, 'Sans', 18, '睡觉', 'Sans是一个爱睡觉,并且身材较矮骨骼巨大的骷髅小胖子', 60);
INSERT INTO `user_info` VALUES (10, 'papyrus', 18, 'JAVA', 'Papyrus是一个讲话大声、个性张扬的骷髅,给人自信、有魅力的骷髅小瘦子', 58);
INSERT INTO `user_info` VALUES (11, '删除数据1', 3, '画肖像', NULL, 61);
INSERT INTO `user_info` VALUES (12, '删除数据2', 3, NULL, NULL, 61);
INSERT INTO `user_info` VALUES (13, '删除数据3', 3, NULL, NULL, 61);
INSERT INTO `user_info` VALUES (14, '删除数据4', 5, '删除', NULL, 10);
INSERT INTO `user_info` VALUES (15, '删除数据5', 6, '删除', NULL, 10);

2.7 编写类

①. SpringBoot2 启动类

Usage:
加载Spring容器上下文, 解析配置文件, 解析注解, 反射进行Object生成, DI依赖注入等.

注意:
spring boot 可以管理同级目录下的注解, 也可以管理下级目录的注解, 如果位置不对,可以用@ComponentScan(basePackages = {"","",""})去定义包的位置,但是如果使用该方法,spring boot 就不能再去访问同级目录,或者未定义包位置的下级目录.

具体到开发中, 需要注意:

  1. 启动类不能放置在main/java下.
  2. 启动类不能放置在下级目录中. 如dao/service等package中.
package com.example;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan(basePackages = {"com.example.dao"})
@EnableSwagger2
public class MybatisPlusDemoApplication {

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

}

②. MyBatis-Plus 配置类

Usage:
MyBatis-Plus 配置增强选项, 实现以下功能:
- 1.debug等开发环境下,提供SQL执行效率的输出信息, 帮助检查优化sql, 揪出slow query问题.
- 2.简易的代码, 提供强大的分页Page查询功能.

package com.example.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * User: Administrator
 * Date: 2020/4/7
 * Time: 16:00
 * Desc: 
 */
@Configuration
public class MybatisPlusConfig {

    /**
     * mybatis-plus SQL执行效率插件【生产环境可以关闭】
     */
    @Bean
    public PerformanceInterceptor performanceInterceptor() {
        return new PerformanceInterceptor();
    }

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

}

③. Entity实例类

Usage: 实体Pojo类构建, 对象封装, 数据承载

package com.example.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

/**
 * User: Administrator
 * Date: 2020/4/7
 * Time: 16:03
 * Desc:
 */
@Data //lombok提供简单的实体Pojo类构建
@TableName("user_info") // @TableName中的值, 对应着数据库中的表名
public class UserInfoEntity {

     /**
     * 主键
     * @TableId中可以决定主键的类型,不写会采取默认值,默认值可以在yml中配置
     * AUTO: 数据库ID自增
     * INPUT: 用户输入ID
     * ID_WORKER: 全局唯一ID,Long类型的主键
     * ID_WORKER_STR: 字符串全局唯一ID
     * UUID: 全局唯一ID,UUID类型的主键
     * NONE: 该类型为未设置主键类型
     */
    @TableId(type = IdType.AUTO)
    private Long id;

    /**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private Integer age;
    /**
     * 技能
     */
    private String skill;
    /**
     * 评价
     */
    private String evaluate;
    /**
     * 分数
     */
    private Long fraction;

}

④. Dao层接口

Usage:
该接口继承了BaseMapper<EntityObject>, 集成了基础的CURD功能.

说明:

  • 1.如上所述, 无须做复杂配置或写DbUtils工具, 即可进行基础的CURD操作(如果仅实现CURD功能, 此接口甚至无法定义任何方法, 即可开箱即用; 本接口中定义的方法为所谓的"复杂业务"服务, 无须添加此方法,简单CURD操作即可完成操作);
  • 2.复杂的sql逻辑, 提供传统的xxxMapper.xml映射文件支持;
  • 3.注意:接口方法第二个参数fraction前, 需加上注解@Param("fraction"), 将入参与xxxMapper.xml中的如下红色部分的parameterType入参类型相匹配, 否则将会报错:"nested exception is org.apache.ibatis.binding.BindingException: Parameter 'fraction' not found. Available parameters are [arg1, arg0, param1, param2]".

<select id=“selectUserInfoByGtFraction” resultType=“com.example.entity.UserInfoEntity” parameterType="long">

注意:
很多开发者dao层习惯于命名为mapper层, 道理是一样的, 相应的, 接口名UserInfoDao 需要 同步调整为 UserInfoMapper.

package com.example.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.entity.UserInfoEntity;

/**
 * User: Administrator
 * Date: 2020/4/7
 * Time: 16:06
 * Desc: 用户信息DAO
 */
public interface UserInfoDao extends BaseMapper<UserInfoEntity> {


    /**
     * 查询大于该分数的学生
     * @Param  page  分页参数
     * @Param  fraction  分数
     * @Return IPage<UserInfoEntity> 分页数据
     */
    IPage<UserInfoEntity> selectUserInfoByGtFraction(IPage<UserInfoEntity> page, @Param("fraction") Long fraction);

}

⑤. service接口

Usage:
用户业务接口类的接口定义, 用于定义非基础CURD的"复杂业务逻辑"方法定义.

5.1 service: 接口定义

类定义模板:
interface BIZService extends IService<BIZEntity>
其中:
IService<BIZEntity> 为 框架中类.

package com.example.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.entity.UserInfoEntity;

/**
 * User: Administrator
 * Date: 2020/4/7
 * Time: 16:06
 * Desc: 用户业务接口
 */
public interface UserInfoService extends IService<UserInfoEntity> {

    /**
     * 查询大于该分数的学生
     * @Param  page  分页参数
     * @Param  fraction  分数
     * @Return IPage<UserInfoEntity> 分页数据
     */
    IPage<UserInfoEntity> selectUserInfoByGtFraction(IPage<UserInfoEntity> page, Long fraction);
}

5.2 serviceImpl: 接口实现类

类定义模板:
BIZSerivceImpl extends ServiceImpl<BIZDao, BIZEntity> implements BIZService
其中:
ServiceImpl<BIZDao, BIZEntity> 为 框架中类.

package com.example.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.dao.UserInfoDao;
import com.example.service.UserInfoService;
import com.example.entity.UserInfoEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * User: Administrator
 * Date: 2020/4/7
 * Time: 16:20
 * Desc: 用户业务实现
 */
@Service
@Transactional
public class UserInfoSerivceImpl extends ServiceImpl<UserInfoDao, UserInfoEntity> implements UserInfoService{

    /**
     * 查询大于该分数的学生
     * @Param  page  分页参数
     * @Param  fraction  分数
     * @Return IPage<UserInfoEntity> 分页数据
     */
    @Override
    public IPage<UserInfoEntity> selectUserInfoByGtFraction(IPage<UserInfoEntity> page, Long fraction) {
        return this.baseMapper.selectUserInfoByGtFraction(page, fraction);
    }
}

⑥. controller 类

Usage:
控制层的作用:接收客户端的请求,然后调用Service层业务逻辑,获取到数据,传递数据给视图层(客户端)用于视觉呈现.

6.1 MyBatis-Plus 基础CURD功能Demo

Usage:
这里我们看到,service中我们没有写任何方法,MyBatis-Plus官方封装了许多基本CRUD的方法,可以直接使用大量节约时间,MyBatis-Plus共通方法详见IService,ServiceImpl,BaseMapper源码,写入操作在ServiceImpl中已有事务绑定,这里我们举一些常用的方法演示.

package com.example.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.service.UserInfoService;
import com.example.entity.UserInfoEntity;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

/**
 * User: Administrator
 * Date: 2020/4/7
 * Time: 16:23
 * Desc: MP基础CURD功能DEMO
 */
@RestController
@RequestMapping("/userInfo")
public class UserInfoController {

    @Autowired
    private UserInfoService userInfoService;
     
    /**
     * 根据ID获取用户信息
     * TODO
     * /
    @ApiOperation("根据用户ID获取用户信息")
    @PostMapping("/getInfo")
    public UserInfoEntity getInfo(@RequestBody String userId){
        UserInfoEntity userInfoEntity = userInfoService.getById(userId);
        return userInfoEntity;
    }

    /**
     * 根据ID获取用户信息
     * /
    @ApiOperation("查询全部信息")
    @PostMapping("/getList")
    public List<UserInfoEntity> getList(){
        List<UserInfoEntity> list = userInfoService.list();
        return list;
    }

    /**
     * 分页查询全部数据
     * @Return IPage<UserInfoEntity> 分页数据
     */
    @ApiOperation("分页查询全部数据")
    @PostMapping("/getInfoListPage")
    public IPage<UserInfoEntity> getInfoListPage(){
        //需要在Config配置类中配置分页插件
        IPage<UserInfoEntity> page = new Page<>();
        page.setCurrent(1); //当前页
        page.setSize(5);    //每页条数
        page = userInfoService.page(page);
        return page;
    }
    
    /**
     * 根据指定字段查询用户信息集合
     * @Return Collection<UserInfoEntity> 用户实体集合
     */
    @ApiOperation("根据指定字段查询用户信息集合")
    @PostMapping("/getListMap")
    public Collection<UserInfoEntity> getListMap(){
        Map<String,Object> map = new HashMap<>();
        //kay是字段名 value是字段值
        map.put("age",20);
        Collection<UserInfoEntity> userInfoEntityList = userInfoService.listByMap(map);
        return userInfoEntityList;
    }
    
    /**
     * 新增用户信息
     */
    @ApiOperation("新增用户信息")
    @PostMapping("/saveInfo")
    public void saveInfo(){
        UserInfoEntity userInfoEntity = new UserInfoEntity();
        userInfoEntity.setName("小龙");
        userInfoEntity.setSkill("JAVA");
        userInfoEntity.setAge(18);
        userInfoEntity.setFraction(59L);
        userInfoEntity.setEvaluate("该学生是一个在改BUG的码农");
        userInfoService.save(userInfoEntity);
    }
    
    /**
     * 批量新增用户信息
     */
    @ApiOperation("批量新增用户信息")
    @PostMapping("/saveInfoList")
    public void saveInfoList(){
        //创建对象
        UserInfoEntity sans = new UserInfoEntity();
        sans.setName("Sans");
        sans.setSkill("睡觉");
        sans.setAge(18);
        sans.setFraction(60L);
        sans.setEvaluate("Sans是一个爱睡觉,并且身材较矮骨骼巨大的骷髅小胖子");
        UserInfoEntity papyrus = new UserInfoEntity();
        papyrus.setName("papyrus");
        papyrus.setSkill("JAVA");
        papyrus.setAge(18);
        papyrus.setFraction(58L);
        papyrus.setEvaluate("Papyrus是一个讲话大声、个性张扬的骷髅,给人自信、有魅力的骷髅小瘦子");
        //批量保存
        List<UserInfoEntity> list =new ArrayList<>();
        list.add(sans);
        list.add(papyrus);
        userInfoService.saveBatch(list);
    }
    
    /**
     * 更新用户信息
     */
    @ApiOperation("更新用户信息")
    @PostMapping("/updateInfo")
    public void updateInfo(){
        //根据实体中的ID去更新,其他字段如果值为null则不会更新该字段,参考yml配置文件
        UserInfoEntity userInfoEntity = new UserInfoEntity();
        userInfoEntity.setId(1L);
        userInfoEntity.setAge(19);
        userInfoService.updateById(userInfoEntity);
    }
    
    /**
     * 新增或者更新用户信息
     */
    @ApiOperation("新增或者更新用户信息")
    @PostMapping("/saveOrUpdateInfo")
    public void saveOrUpdate(){
        //传入的实体类userInfoEntity中ID为null就会新增(ID自增)
        //实体类ID值存在,如果数据库存在ID就会更新,如果不存在就会新增
        UserInfoEntity userInfoEntity = new UserInfoEntity();
        userInfoEntity.setId(1L);
        userInfoEntity.setAge(20);
        userInfoService.saveOrUpdate(userInfoEntity);
    }
    
    /**
     * 根据ID删除用户信息
     */
    @ApiOperation("根据ID删除用户信息")
    @PostMapping("/deleteInfo")
    public void deleteInfo(String userId){
        userInfoService.removeById(userId);
    }
    
    /**
     * 根据ID批量删除用户信息
     */
    @ApiOperation("根据ID批量删除用户信息")
    @PostMapping("/deleteInfoList")
    public void deleteInfoList(){
        List<String> userIdlist = new ArrayList<>();
        userIdlist.add("12");
        userIdlist.add("13");
        userInfoService.removeByIds(userIdlist);
    }
    
    /**
     * 根据指定字段删除用户信息
     */
    @ApiOperation("根据指定字段删除用户信息")
    @PostMapping("/deleteInfoMap")
    public void deleteInfoMap(){
        //kay是字段名 value是字段值
        Map<String,Object> map = new HashMap<>();
        map.put("skill","删除");
        map.put("fraction",10L);
        userInfoService.removeByMap(map);
    }
    
}

6.2 MyBatis-Plus 中 QueryWrapper条件构造器功能Demo

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

package com.example.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.entity.UserInfoEntity;
import com.example.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * User: Administrator
 * Date: 2020/4/7
 * Time: 19:14
 * Desc:  MP 提供的QueryWrapper条件选择器功能DEMO
 */
@RestController
@RequestMapping("/userInfoPlus")
public class UserInfoPlusController {

    @Autowired
    private UserInfoService userInfoService;

    @RequestMapping("/getInfoListPlus")
    public Map<String, Object> getInfoListPage() {
        //初始化返回类
        Map<String, Object> result = new HashMap<>(100);

        //查询年龄等于18的学生
        //等价sql: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE age=18;
        QueryWrapper<UserInfoEntity> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.lambda().eq(UserInfoEntity::getAge, 18);
        List<UserInfoEntity> userInfoEntityList1 = userInfoService.list(queryWrapper1);
        result.put("studentAge18", userInfoEntityList1);

        //查询年龄大于5岁的学生且小于等于18岁的学生
        //等价SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE age > 5 AND age <= 18
        QueryWrapper<UserInfoEntity> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.lambda().ge(UserInfoEntity::getAge, 5);
        queryWrapper2.lambda().le(UserInfoEntity::getAge, 18);
        List<UserInfoEntity> userInfoEntityList2 = userInfoService.list(queryWrapper2);
        result.put("studentAge5", userInfoEntityList2);

        //模糊查询技能字段带有"画"的数据,并按照年龄降序
        //等价SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE skill LIKE '%画%' ORDER BY age DESC
        QueryWrapper<UserInfoEntity> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.lambda().like(UserInfoEntity::getSkill, "画");
        queryWrapper3.lambda().orderByDesc(UserInfoEntity::getAge);
        List<UserInfoEntity> userInfoEntityList3 = userInfoService.list(queryWrapper3);
        result.put("studentAgeSkill", userInfoEntityList3);

        //模糊查询名字带有"小"或者年龄大于18的学生
        //等价SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE name LIKE '%小%' OR age > 18
        QueryWrapper<UserInfoEntity> queryWrapper4 = new QueryWrapper<>();
        queryWrapper4.lambda().like(UserInfoEntity::getName, "小");
        queryWrapper4.lambda().or().gt(UserInfoEntity::getAge, 18);
        List<UserInfoEntity> userInfoEntityList4 = userInfoService.list(queryWrapper4);
        result.put("studentOr", userInfoEntityList4);

        //查询评价不为null的学生,并且分页
        //等价SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE evaluate IS NOT NULL LIMIT 0,5
        IPage<UserInfoEntity> page = new Page<>();
        page.setCurrent(1);
        page.setSize(5);
        QueryWrapper<UserInfoEntity> queryWrapper5 = new QueryWrapper<>();
        queryWrapper5.lambda().isNotNull(UserInfoEntity::getEvaluate);
        page = userInfoService.page(page, queryWrapper5);
        result.put("studentPage", page);

        return result;

    }

    public IPage<UserInfoEntity> getInfoListSQL() {
        //查询大于60分以上的学生,并且分页。
        IPage<UserInfoEntity> page = new Page<>();
        page.setCurrent(1);
        page.setPages(5);
        page = userInfoService.selectUserInfoByGtFraction(page, 60L);
        return page;
    }

}

6.3 MyBatis-Plus 中 自定义SQL Demo

Usage:
项目中引入Mybatis-Plus组件, 将不会对项目现有的 Mybatis 构架产生任何影响,而且Mybatis-Plus支持所有 Mybatis 原生的特性.
由于某些业务逻辑复杂, 我们可能要自己去写一些比较复杂的SQL语句.

我们举一个简单的例子来演示自定义SQL.
示例:查询大于设置分数的学生(分数为动态输入,且有分页)

6.3.1 构建 xxxMapper.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.example.dao.UserInfoDao">
    <!-- 通用查询映射结果 -->
    <!--<resultMap id="BaseResultMap" type="com.example.entity.UserInfoEntity">
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="age" property="age"/>
        <result column="skill" property="skill"/>
        <result column="evaluate" property="evaluate"/>
        <result column="fraction" property="fraction"/>
    </resultMap>-->

    <select id="selectUserInfoByGtFraction" resultType="com.example.entity.UserInfoEntity"
            parameterType="long">
        SELECT 
             * 
        FROM user_info 
        WHERE fraction > #{fraction}
    </select>

</mapper>
6.3.2 dao 层中加入方法

详见:

    /**
     * 查询大于该分数的学生
     * @Param  page  分页参数
     * @Param  fraction  分数
     * @Return IPage<UserInfoEntity> 分页数据
     */
    IPage<UserInfoEntity> selectUserInfoByGtFraction(IPage<UserInfoEntity> page, @Param("fraction") Long fraction);
6.3.3 service 层中加入方法

详见:

     /**
     * 查询大于该分数的学生
     * @Param  page  分页参数
     * @Param  fraction  分数
     * @Return IPage<UserInfoEntity> 分页数据
     */
    IPage<UserInfoEntity> selectUserInfoByGtFraction(IPage<UserInfoEntity> page, Long fraction);
6.3.4 serviceImpl 层中加入方法

详见:

    /**
     * 查询大于该分数的学生
     * @Param  page  分页参数
     * @Param  fraction  分数
     * @Return IPage<UserInfoEntity> 分页数据
     */
    @Override
    public IPage<UserInfoEntity> selectUserInfoByGtFraction(IPage<UserInfoEntity> page, Long fraction) {
        return this.baseMapper.selectUserInfoByGtFraction(page, fraction);
    }
6.3.5 Controller中进行测试

详见:

package com.example.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.entity.UserInfoEntity;
import com.example.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * User: Administrator
 * Date: 2020/4/7
 * Time: 19:14
 * Desc:
 */
@RestController
@RequestMapping("/userInfoPlus")
public class UserInfoPlusController {

    @Autowired
    private UserInfoService userInfoService;

    /**
     * MyBatis-Plus自定义SQL
     * @Return IPage<UserInfoEntity> 分页数据
     */
    @RequestMapping("/getInfoListSQL")
    public IPage<UserInfoEntity> getInfoListSQL() {
        //查询大于60分以上的学生,并且分页。
        IPage<UserInfoEntity> page = new Page<>();
        page.setCurrent(1);
        page.setPages(5);
        page = userInfoService.selectUserInfoByGtFraction(page, 60L);
        return page;
    }

}

三. Postman测试

Postman调用接口效果如下:
在这里插入图片描述

四. Swagger2 在线文档

地址 : http://localhost:8080/swagger-ui.html
在这里插入图片描述

五 代码生成器(AutoGenerator)

5.1 说明

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

特别说明:

自定义模板有哪些可用参数?Github Gitee AbstractTemplateEngine 类中方法 getObjectMap 返回 objectMap 的所有值都可用。

5.2 pom.xml 改造

1. 为避免generator包冲突, 需把mybatis-plus-boot-starter 包中关联的generator包给移除掉, 再重新在mybatis-plus-boot-starter 平级包中重新导入;
2. 代码生成器, 底层使用了 Freemarker 或 Velocity 等模板自动化生成引擎, 故需将其包添加进来;

<!-- mybatisPlus 核心库 -->
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.1.0</version>
			<exclusions>
				<exclusion>
					<groupId>com.baomidou</groupId>
					<artifactId>mybatis-plus-generator</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-generator</artifactId>
			<version>3.1.0</version>
		</dependency>
		
		<!-- mybatisPlus 关联的模板引擎&文本生成输出框架(如生成XML,JSP,JAVA等) freemarker-->
		<dependency>
			<groupId>org.freemarker</groupId>
			<artifactId>freemarker</artifactId>
			<version>2.3.30</version>
		</dependency>
		
		<!-- mybatisPlus 关联的模板引擎&文本生成输出框架(如生成XML,JSP,JAVA等) velocity-->
		<dependency>
			<groupId>org.apache.velocity</groupId>
			<artifactId>velocity-engine-core</artifactId>
			<version>2.0</version>
		</dependency>

5.3 代码生成器演示例子

执行 main 方法控制台输入模块表名回车自动生成对应项目目录中

package com.example.util.generator;


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;

/**
 * User: Administrator
 * Date: 2020/4/9
 * Time: 18:39
 * Desc: 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
 */
public class CodeGenerator {


    private static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + ": ");
        System.out.println(help.toString());
        while (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("jobob");
        gc.setOpen(false);
        gc.setSwagger2(true); //实体属性 Swagger2 注解
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://{DBMS_IP}:{DBMS_PORT}/user?useUnicode=true&useSSL=false&characterEncoding=utf8");
//         dsc.setSchemaName("user");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("XXXX");
        dsc.setPassword("XXXX");
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(scanner("模块名"));
        pc.setParent("com.baomidou.generatorPKG");
        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<FileOutConfig> focList = new ArrayList<>();
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {

                System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML);
                // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>D:\IdeaProjects-6\springboot_mybatisplus/src/main/resources/mapper/user/InfoMapper.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("调用默认方法创建的目录");
                return false;
            }
        });
        */

        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() + "_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();

    }

}

演示效果图:
在这里插入图片描述

参考列表:
-SpringBoot 整合MyBatis-Plus3.1详细教程
-MyBatis-Plus 官方文档
-代码生成器
-解决org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)问题
-springMVC中的controller层
-FreeMarker使用 & 与spring4集成

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章