文章目录
1.简介
Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。这是官方给的定义,关于mybatis-plus的更多介绍及特性,可以参考mybatis-plus官网。那么它是怎么增强的呢?其实就是它已经封装好了一些crud方法,我们不需要再写xml了,直接调用这些方法就行,就类似于JPA。
官网地址: https://mybatis.plus/guide/
使用版本
- springboot版本是: 2.3.0.RELEASE
- mybatis-plus-boot-starter的使用的 3.5.2
2添加入依赖
<properties>
<java.version>1.8</java.version>
<mybatis-plus.version>3.5.2</mybatis-plus.version>
<mysql.version>8.0.11</mysql.version>
</properties>
<dependencies>
<!--MyBatis-Plus 核心依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!--如果不需要自动生成代码,下面两个包不需要引入-->
<!-- 代码生成器 MyBatis-Plus 从 3.0.3 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!--模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!--生成的模板实体类用到了lombok注解-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
3.使用代码生成器生成模板代码
3.1.生成代码需要用的测试数据
drop database if exists boot_master;
create database boot_master;
use boot_master;
drop table if exists sys_users;
CREATE TABLE sys_users (
id int AUTO_INCREMENT,
username varchar(20) COMMENT '用户名',
password varchar(20) COMMENT '密码',
create_time datetime COMMENT '创建时间',
update_time datetime COMMENT '修改时间',
grade int COMMENT '年纪',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into sys_users(username, password, create_time,update_time,grade) values ('test1','123456','2020-7-1 0:02','2020-7-1 0:02',7),('test2','123456','2020-7-1 0:02','2020-7-1 0:02',7),
('test3','123456','2020-7-1 0:02','2020-7-1 0:02',7),('test4','123456','2020-7-1 0:02','2020-7-1 0:02',8),('test5','123456','2020-7-1 0:02','2020-7-1 0:02',8),
('test6','123456','2020-7-1 0:02','2020-7-1 0:02',8),('test7','123456','2020-7-1 0:02','2020-7-1 0:02',9),('test8','123456','2020-7-1 0:02','2020-7-1 0:02',9),
('test9','123456','2020-7-1 0:02','2020-7-1 0:02',9),('test10','123456','2020-7-1 0:02','2020-7-1 0:02',9),('test11','123456','2020-7-1 0:02','2020-7-1 0:02',9),
('test12','123456','2020-7-1 0:02','2020-7-1 0:02',9);
3.2.创建模板实体类继承通用父类
通常会把一些通用的字段放入到超类中
- 使用TableField的FieldFill.INSERT指列在插入数据的时候设置默认值
- 使用TableField的FieldFill.INSERT_UPDATE指列在插入数据的时候设置默认值并在修改的时候自动修改
@Data
@Data
public class BaseEntity implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;
@TableField(fill = FieldFill.INSERT)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
3.3.模板生成器代码
public class GeneratorMybatisCode {
//生成类的作者描述
private final static String AUTHOR = "Dominick Li";
//数据库连接信息
private final static String DATASOURCE_URL = "jdbc:mysql://localhost:3306/boot_master?useSSL=false&serverTimezone=GMT%2b8&characterEncoding=utf8&connectTimeout=10000&socketTimeout=3000&autoReconnect=true";
//数据库用户名
private final static String DATASOURCE_USERNAME = "root";
//数据库密码
private final static String DATASOURCE_PASSWORD = "123456";
//项目包名全路径
private final static String BASE_PACKAGE = "com.ljm.boot.mybatisplus";
//通用父类的字段,该字段不会出现在生成的类中
private final static String[] SUERP_COLUMN = new String[]{"id", "create_time", "update_time"};
//需要指定生成模板的表名称
private final static String[] GENERATOR_TABLES = new String[]{"sys_users"};
public static void main(String[] args) {
//项目根路径
String rootPath = System.getProperty("user.dir");
//聚合工程需要写工程的名字,普通工程写 "" 就行
String parantPath = "/14_mybatis_plus";
FastAutoGenerator.create(DATASOURCE_URL, DATASOURCE_USERNAME, DATASOURCE_PASSWORD)
//全局配置
.globalConfig(builder -> {
builder.author(AUTHOR) // 设置作者 baomidou 默认值:作者
//.enableSwagger() // 开启 swagger 模式 默认值:false
.fileOverride() // 覆盖已生成文件 默认值:false
.disableOpenDir()//禁止打开输出目录 默认值:true
.commentDate("yyyy-MM-dd")// 注释日期
.dateType(DateType.ONLY_DATE)//定义生成的实体类中日期类型 DateType.ONLY_DATE 默认值: DateType.TIME_PACK
.outputDir(rootPath + parantPath + "/src/main/java");
})
//包命名配置
.packageConfig(builder -> {
builder.parent(BASE_PACKAGE)// 父包模块名 默认值:com.baomidou
// .controller("controller")//Controller 包名 默认值:controller
// .entity("entity")//Entity 包名 默认值:entity
// .service("service")//Service 包名 默认值:service
// .mapper("mapper")//Mapper 包名 默认值:mapper
.pathInfo(Collections.singletonMap(OutputFile.xml, rootPath + parantPath + "/src/main/resources/mapper")); // 设置mapper.xml存放路径
})
//生成策略配置
.strategyConfig(builder -> {
builder.addInclude(GENERATOR_TABLES) // 设置需要生成的表名 可边长参数“user”, “user1”
//.addTablePrefix("sys_") // 设置生成的累名称过滤表前缀
.serviceBuilder()//service策略配置
.formatServiceFileName("%sService")
.formatServiceImplFileName("%sServiceImpl")
.entityBuilder()// 实体类策略配置
.idType(IdType.AUTO)//主键策略 根据表是否有自增自动分配
.superClass(BaseEntity.class)
.addSuperEntityColumns(SUERP_COLUMN) //设置父类的通用字段
.enableLombok() //开启lombok
//.logicDeleteColumnName("deleted")// 说明逻辑删除是哪个字段
.enableTableFieldAnnotation()// 属性加上注解说明
.controllerBuilder() //controller 策略配置
.formatFileName("%sController")
.enableRestStyle() // 开启RestController注解
.mapperBuilder()// mapper策略配置
.formatMapperFileName("%sMapper")
.enableMapperAnnotation()//@mapper注解开启
.formatXmlFileName("%sMapper");
})
//生成的模板配置 如果用默认的模板则下面的不需要配置
.templateConfig(
builder -> {
builder.controller("/template/controller.java");
builder.entity("/template/entity.java");
builder.mapper("/template/mapper.java");
builder.xml("/template/mapper.xml");
builder.service("/template/service.java");
builder.serviceImpl("/template/serviceImpl.java");
}
)
// 使用Freemarker引擎模板,默认的是Velocity引擎模板
.templateEngine(new FreemarkerTemplateEngine())
.execute();
}
3.4.自定义生成的代码模板
在上面2.3示例中通过使用templateConfig指定了自定义模板路径,
从依赖的代码生成器中的templates目录下找到了.ftl后缀需要自定义修改的模板文件然后复制项目resources目录的template目录下
默认的controller.java.ftl模板中没有定义接口信息,我们可以自定义一些CRUD接口
添加后的
package ${package.Controller};
import org.springframework.web.bind.annotation.RequestMapping;
<#if restControllerStyle>
import org.springframework.web.bind.annotation.RestController;
<#else>
import org.springframework.stereotype.Controller;
</#if>
<#if superControllerClassPackage??>
import ${superControllerClassPackage};
</#if>
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @description
* @author ${author}
* @createTime ${date}
**/
<#if restControllerStyle>
@RestController
<#else>
@Controller
</#if>
@RequestMapping("<#if package.ModuleName?? && package.ModuleName != "">/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle>${controllerMappingHyphen}<#else>${table.entityPath}</#if>")
<#if kotlin>
class ${table.controllerName}<#if superControllerClass??> : ${superControllerClass}()</#if>
<#else>
<#if superControllerClass??>
public class ${table.controllerName} extends ${superControllerClass} {
<#else>
public class ${table.controllerName} {
</#if>
@Autowired
private ${table.serviceName} ${(table.serviceName)?uncap_first};
/**
* 根据id查询
*/
@GetMapping("/{id}")
public ${table.entityName} getById(@PathVariable Integer id) {
return ${(table.serviceName)?uncap_first}.getById(id);
}
/**
* 查询所有
*/
@GetMapping
public List<${table.entityName}> list() {
return ${(table.serviceName)?uncap_first}.list();
}
/**
* 添加
*/
@PostMapping
public boolean add(${table.entityName} ${(table.entityName)?uncap_first}) {
return ${(table.serviceName)?uncap_first}.save(${(table.entityName)?uncap_first});
}
/**
* 修改
*/
@PutMapping
public boolean modify(${table.entityName} ${(table.entityName)?uncap_first}) {
return ${(table.serviceName)?uncap_first}.updateById(${(table.entityName)?uncap_first});
}
/**
* 根据Id删除
*/
@DeleteMapping("/{id}")
public boolean deleteId(@PathVariable Integer id) {
return ${(table.serviceName)?uncap_first}.removeById(id);
}
}
</#if>
3.5.运行main函数生成代码
看到下面的日志就代表模板文件生成成功了.
每个表对应会生成一个controller->service->mapper>xml>entity
生成的结构如下
可以查看到控制器层已根据自定义模板配置生成了一些CRUD接口
4.2.mybatis-plus配置类
4.2.1.设置分页插件
在xml中使用分页查询的时候需要用到
@Configuration
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
4.2.2.元数据填充
在上文3.2.创建模板实体类继承通用父类中在父类里使用到的 @TableField(fill = FieldFill.INSERT)和 @TableField(fill = FieldFill.INSERT_UPDATE),这个需要通过配置需要生成默认值
- FieldFill.INSERT和FieldFill.INSERT_UPDATE属性会在插入数据的时候会调用insertFill函数
- FieldFill.UPDATE和FieldFill.INSERT_UPDATE属性会在修改的时候调用updateFill函数
@Component
public class MybatisMetaObjectHandlerConfig implements MetaObjectHandler {
/**
* 插入数据添加默认值
*/
@Override
public void insertFill(MetaObject metaObject) {
// 该属性为空,可以进行填充
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
/**
* 修改数据添加默认值
*/
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
5.使用mybatis-plus实现基本的CRUD功能
5.1.通用代码层详解
下面的代码会在模板生成器生成模板的时候会自动添加上
service代码详解
此处继承了ServiceImpl通用代码实现类
@Service
public class SysUsersServiceImpl extends ServiceImpl<SysUsersMapper, SysUsers> implements SysUsersService {
}
查看ServiceImpl 源码能看到已经定义了一些通用的代码
//新增 这个有点迷,我以为会和Jpa一样自动判断添加和修改,这个save只能添加
boolean save(T entity);
//根据id获取
T getById(Serializable id)
//根据条件查询
List<T> list(Wrapper<T> queryWrapper)
//分页查询
<E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper);
//批量新增 (默认是1000条,可以调用saveBatch(Collection<T> entityList, int batchSize)指定批量操作数量)
boolean saveBatch(Collection<T> entityList)
//添加或者修改
boolean saveOrUpdate(T entity);
//批量添加或者修改
boolean saveOrUpdateBatch(Collection<T> entityList)
//根据ID删除
removeById(Serializable id)
//根据Id批量删除
boolean removeByIds(Collection<? extends Serializable> idList)
mapper接口
此处继承框架内的BaseMappe 接口,里面也定义了一些通用的接口
public interface SysUserMapper extends BaseMapper<SysUser> {
}
5.2.自定义xml分页查询
- 在查询的时候通过指定Page参数自动分页
- 在查询的时候通过@Param注解指定查询条件别名为condition
@Mapper
public interface SysUsersMapper extends BaseMapper<SysUsers> {
IPage<SysUsers> page(Page page,@Param("condition") SysUsers condition);
}
在SysUsersMapper.xml中添加下面的代码
<select id="page" resultType="com.ljm.boot.mybatisplus.entity.SysUsers">
SELECT *
FROM sys_users
where
1=1
<if test="condition.username!=null and condition.username!=''">
AND username LIKE CONCAT('%',#{condition.username},'%')
</if>
<if test="condition.password!=null and condition.password!=''">
AND password=#{condition.password}
</if>
</select>
5.3.配置application.yml
server:
port: 8014
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/boot_master?createDatabaseIfNotExist=true&useSSL=false&serverTimezone=GMT%2b8&characterEncoding=utf8&connectTimeout=10000&socketTimeout=3000&autoReconnect=true
username: root
password: 123456
#项目启动执行sql脚本
schema: classpath:sql/init.sql
sql-script-encoding: utf-8
platform: mysql
initialization-mode: always
freemarker:
#关闭模板缓存,方便测试
cache: false
# mybatis-plus相关配置
mybatis-plus:
# xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.ljm.boot.mybatisplus.model
# 以下配置均有默认值,可以不设置
global-config:
db-config:
#主键类型 auto:"数据库ID自增" 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一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
5.4.在SpringBoot测试中使用CRUD方法
@SpringBootTest
class MybatisPlusApplicationTests {
@Autowired
private SysUsersService sysUsersService;
@Resource
private SysUsersMapper sysUsersMapper;
@Test
void contextLoads() {
//查询
{
//指定查询列和查询条件
LambdaQueryWrapper<SysUsers> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper
//只查询id,姓名,年纪三个字段的数据
.select(SysUsers::getId, SysUsers::getUsername, SysUsers::getGrade)
//根据年级等值查询
.eq(SysUsers::getGrade, 7)
//模糊查询
.like(SysUsers::getUsername, "%test%")
//根据Id范围查询
.in(SysUsers::getId, Arrays.asList(1));
//根据Id查询
SysUsers sysUsers = sysUsersService.getById(1);
//根据查询条件获取一条数据
sysUsers = sysUsersService.getOne(lambdaQueryWrapper);
System.out.println(sysUsers == null);
//根据条件查询数据列表数据
List<SysUsers> userList = sysUsersService.list(lambdaQueryWrapper);
System.out.println(userList.size());
//页码,每页显示的记录数
Integer currentPage = 1, pageSize = 10;
Page page = new Page<>(currentPage, pageSize);
//分页查询
IPage<SysUsers> iPage = sysUsersService.page(page);
System.out.printf("总页数:{%d},总记录数:{%d}", iPage.getPages(), iPage.getTotal());
System.out.println();
//分页指定查询条件
//IPage<SysUser> iPage = sysUserService.page(page, lambdaQueryWrapper);
//封装查询条件用于xml的自定义查询
SysUsers condition = new SysUsers();
condition.setUsername("test");
condition.setPassword("123456");
//自定义xml分页查询 会写sql就行
IPage<SysUsers> iPage2 = sysUsersMapper.page(page, condition);
System.out.printf("自定义xml分页查询 总页数:{%d},总记录数:{%d}", iPage2.getPages(), iPage2.getTotal());
}
//增删改
{
SysUsers user = new SysUsers();
user.setUsername("test99");
//增加
boolean flag = sysUsersService.save(user);
System.out.println("save flag=" + flag);
//批量增加
//flag = sysUsersService.saveBatch(Arrays.asList(user));
System.out.println("save flag=" + flag);
//修改
SysUsers updateUser = new SysUsers();
updateUser.setPassword("1234567");
updateUser.setId(1);
//根据id修改
flag = sysUsersService.updateById(updateUser);
System.out.println("updateById flag=" + flag);
UpdateWrapper<SysUsers> sysUsersUpdateWrapper = Wrappers.update();
sysUsersUpdateWrapper.lambda()
.set(SysUsers::getUsername, "admin")
.eq(SysUsers::getId, 1);
flag = sysUsersService.update(sysUsersUpdateWrapper);
System.out.println("update flag=" + flag);
//删除
//根据Id删除
flag = sysUsersService.removeById(2);
System.out.println("removeById flag=" + flag);
//根据Id批量删除
flag = sysUsersService.removeBatchByIds(Arrays.asList(3, 4, 5));
System.out.println("removeBatchByIds flag=" + flag);
//根据自定义条件删除
LambdaQueryWrapper<SysUsers> condition = new LambdaQueryWrapper<>();
condition.eq(SysUsers::getGrade, 9);
flag = sysUsersService.remove(condition);
System.out.println("removeBatchByIds flag=" + flag);
}
}
}
6.项目配套代码
创作不易,要是觉得我写的对你有点帮助的话,麻烦在gitee上帮我点下 Star
【SpringBoot框架篇】其它文章如下,后续会继续更新。
- 1.搭建第一个springboot项目
- 2.Thymeleaf模板引擎实战
- 3.优化代码,让代码更简洁高效
- 4.集成jta-atomikos实现分布式事务
- 5.分布式锁的实现方式
- 6.docker部署,并挂载配置文件到宿主机上面
- 7.项目发布到生产环境
- 8.搭建自己的spring-boot-starter
- 9.dubbo入门实战
- 10.API接口限流实战
- 11.Spring Data Jpa实战
- 12.使用druid的monitor工具查看sql执行性能
- 13.使用springboot admin对springboot应用进行监控
- 14.mybatis-plus实战
- 15.使用shiro对web应用进行权限认证
- 16.security整合jwt实现对前后端分离的项目进行权限认证
- 17.使用swagger2生成RESTful风格的接口文档
- 18.使用Netty加websocket实现在线聊天功能
- 19.使用spring-session加redis来实现session共享
- 20.自定义@Configuration配置类启用开关
- 21.对springboot框架编译后的jar文件瘦身
- 22.集成RocketMQ实现消息发布和订阅
- 23.集成smart-doc插件零侵入自动生成RESTful格式API文档
- 24.集成FastDFS实现文件的分布式存储
- 25.集成Minio实现文件的私有化对象存储
- 26.集成spring-boot-starter-validation对接口参数校验
- 27.集成mail实现邮件推送带网页样式的消息
- 28.使用JdbcTemplate操作数据库
- 29.Jpa+vue实现单模型的低代码平台
- 30.使用sharding-jdbc实现读写分离和分库分表
- 31.基于分布式锁或xxx-job实现分布式任务调度
- 32.基于注解+redis实现表单防重复提交
- 33.优雅集成i18n实现国际化信息返回
- 34.使用Spring Retry完成任务的重试