mybatis-plus
mybatis-plus 介绍
1.简介
MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
2.特性
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
3.支持数据库
任何能使用 MyBatis 进行 CRUD, 并且支持标准 SQL 的数据库,具体支持情况如下,如果不在下列表查看分页部分教程 PR 您的支持。
MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb
达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库
官网地址:https://baomidou.com/
mybatis-plus ->springboot环境搭建
1.引jar包
<!-- hutool-all 工具类包-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.1</version>
</dependency>
<!--mybatis-plus 的依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!--Velocity模板生成引擎-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
2.编辑application.yml配置文件
#数据库连接池
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
password: 123456
username: root
url: jdbc:mysql:///test2?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
mybatis-plus:
global-config:
db-config:
#id的类型
id-type: auto
#逻辑删除的属性
logic-delete-field: isDelete
#逻辑未删除的值
logic-not-delete-value: 0
#逻辑删除的值
logic-delete-value: 1
#枚举类扫描包
type-enums-package: com.zhuoyue.**
configuration:
#是否开启驼峰命名
map-underscore-to-camel-case: true
#MyBatis 自动映射策略 NONE:不启用自动映射 PARTIAL:只对非嵌套的 resultMap 进行自动映射 FULL:对所有的 resultMap 都进行自动映射
auto-mapping-behavior: partial
#输入日志打印SQL语句
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3.在resources文件夹下增加generator.properties配置数据库信息,mybatis-puls自动生成工具类要用
dataSource.url=jdbc:mysql:///test2?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
dataSource.driverName=com.mysql.jdbc.Driver
dataSource.username=root
dataSource.password=123456
package.base=com.zhuoyue
4.创建自动生成工具类MyBatisPlusGenerator
import cn.hutool.setting.dialect.Props;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
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.LikeTable;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import java.util.ArrayList;
import java.util.List;
/**
* @author o_wanglisheng
* @description MyBatisPlus代码生成器
* @created 2022/1/20 17:10
*/
public class MyBatisPlusGenerator {
public static void main(String[] args) {
String projectPath = System.getProperty("user.dir") + "";
//模块名
String moduleName = "";
//表名,多个英文逗号分割;当表名中带*号时可以启用通配符模式
String[] tableNames = new String[]{
"wc_fi_account_payment",
"wc_fi_account_payment_detail",
"wc_fi_account_receipt",
"wc_fi_account_receipt_detail"
};
// 代码生成器
AutoGenerator autoGenerator = new AutoGenerator();
autoGenerator.setGlobalConfig(initGlobalConfig(projectPath));
autoGenerator.setDataSource(initDataSourceConfig());
autoGenerator.setPackageInfo(initPackageConfig(moduleName));
autoGenerator.setCfg(initInjectionConfig(projectPath, moduleName));
autoGenerator.setTemplate(initTemplateConfig());
autoGenerator.setStrategy(initStrategyConfig(tableNames));
autoGenerator.setTemplateEngine(new VelocityTemplateEngine());
autoGenerator.execute();
}
/**
* 初始化全局配置
*/
private static GlobalConfig initGlobalConfig(String projectPath) {
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(projectPath + "/src/main/java");
//创建人
globalConfig.setAuthor("myl");
globalConfig.setOpen(false);
globalConfig.setSwagger2(true);
globalConfig.setBaseResultMap(true);
globalConfig.setFileOverride(true);
globalConfig.setDateType(DateType.ONLY_DATE);
globalConfig.setEntityName("%s");
globalConfig.setMapperName("%sMapper");
globalConfig.setXmlName("%sMapper");
globalConfig.setServiceName("%sService");
globalConfig.setServiceImplName("%sServiceImpl");
globalConfig.setControllerName("%sController");
return globalConfig;
}
/**
* 初始化数据源配置
*/
private static DataSourceConfig initDataSourceConfig() {
Props props = new Props("generator.properties");
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setUrl(props.getStr("dataSource.url"));
dataSourceConfig.setDriverName(props.getStr("dataSource.driverName"));
dataSourceConfig.setUsername(props.getStr("dataSource.username"));
dataSourceConfig.setPassword(props.getStr("dataSource.password"));
return dataSourceConfig;
}
/**
* 初始化包配置
*/
private static PackageConfig initPackageConfig(String moduleName) {
Props props = new Props("generator.properties");
PackageConfig packageConfig = new PackageConfig();
packageConfig.setModuleName(moduleName);
packageConfig.setParent(props.getStr("package.base"));
packageConfig.setEntity("model");
return packageConfig;
}
/**
* 初始化模板配置
*/
private static TemplateConfig initTemplateConfig() {
TemplateConfig templateConfig = new TemplateConfig();
//可以对controller、service、entity模板进行配置
//mapper.xml模板需单独配置
templateConfig.setXml(null);
return templateConfig;
}
/**
* 初始化策略配置
*/
private static StrategyConfig initStrategyConfig(String[] tableNames) {
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setNaming(NamingStrategy.underline_to_camel);
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
strategyConfig.setEntityLombokModel(true);
strategyConfig.setRestControllerStyle(true);
//当表名中带*号时可以启用通配符模式
if (tableNames.length == 1 && tableNames[0].contains("*")) {
String[] likeStr = tableNames[0].split("_");
String likePrefix = likeStr[0] + "_";
strategyConfig.setLikeTable(new LikeTable(likePrefix));
} else {
strategyConfig.setInclude(tableNames);
}
return strategyConfig;
}
/**
* 初始化自定义配置
*/
private static InjectionConfig initInjectionConfig(String projectPath, String moduleName) {
// 自定义配置
InjectionConfig injectionConfig = new InjectionConfig() {
@Override
public void initMap() {
// 可用于自定义属性
}
};
// 模板引擎是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/" + moduleName
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
injectionConfig.setFileOutConfigList(focList);
return injectionConfig;
}
}
5.书写IsDeleteEnum
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.Getter;
/**
* @author wjj
*/
@Getter
public enum IsDeleteEnum {
/**
* 1.已删除
* 0,未删除
*/
YES(1,"已删除"),
NO(0,"未删除");
@EnumValue
private final Integer value;
@JsonValue
private final String name;
IsDeleteEnum(Integer value, String name) {
this.value = value;
this.name = name;
}
}
6.在启动类上添加@MapperScan注解
7.配置分页插件MybatisPlusPageConfig
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusPageConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题
*
* mp 与 pagehelper 存在依赖 jsqlparser 冲突,不建议混用
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
//乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// 攻击 SQL 阻断解析器,防止全表更新与删除
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
}
8.配置自动填充策略
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
* mybatis全局通用属性填充
*
* @author wjj
*/
@Slf4j
@Component
public class MybatisMetaHandler implements MetaObjectHandler {
/**
* CREATE_USER_ID 创建人
* CREATE_TIME 创建时间
* UPDATE_USER_ID 修改人
* UPDATE_TIME 修改时间
* IS_DELETE 是否删除(0:否,1是)
*/
private static final String CREATE_USER_ID = "createUserId";
private static final String CREATE_TIME = "createTime";
private static final String UPDATE_USER_ID = "updateUserId";
private static final String UPDATE_TIME = "updateTime";
private static final String IS_DELETE = "isDelete";
/**
* 添加拦截
*
* @param metaObject 实例对象
*/
@Override
public void insertFill(MetaObject metaObject) {
// 获取创建时间
Object createTime = this.getFieldValByName(CREATE_TIME, metaObject);
if (createTime == null) {
this.strictInsertFill(metaObject, CREATE_TIME, LocalDateTime.class, LocalDateTime.now());
}
// 是否删除
Object isDelete = this.getFieldValByName(IS_DELETE, metaObject);
if (isDelete == null) {
this.strictInsertFill(metaObject, IS_DELETE, IsDeleteEnum.class, IsDeleteEnum.NO);
}
// 只有制定了创建人,而且没有指定修改人时,才会默认添加修改人信息
Object createUserId = this.getFieldValByName(CREATE_USER_ID, metaObject);
Object updateUserId = this.getFieldValByName(UPDATE_USER_ID, metaObject);
if (updateUserId == null && createUserId != null) {
this.strictInsertFill(metaObject, UPDATE_USER_ID, Long.class, Long.parseLong(createUserId + ""));
}
// 添加时指定初始修改人和修改时间
this.updateFill(metaObject);
}
/**
* 修改拦截
*
* @param metaObject 实例对象
*/
@Override
public void updateFill(MetaObject metaObject) {
// 获取修改时间
Object updateTime = this.getFieldValByName(UPDATE_TIME, metaObject);
if (updateTime == null) {
this.strictInsertFill(metaObject, UPDATE_TIME, LocalDateTime.class, LocalDateTime.now());
}
}
}
9.配置显示时间格式
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* jackson序列化时间格式调整
*
* @author myl
*/
@Configuration
public class JacksonConfig {
/**
* 指定日期输出格式
*/
private static final String DATA_FORMAT = "yyyy-MM-dd HH:mm:ss";
/**
* 定义时间序列化格式
*
* @return Jackson2ObjectMapperBuilderCustomizer
*/
@Bean
public Jackson2ObjectMapperBuilderCustomizer customJackson() {
return jacksonObjectMapperBuilder -> {
// 针对于JDK新时间类。序列化时带有T的问题,自定义格式化字符串
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATA_FORMAT)));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATA_FORMAT)));
jacksonObjectMapperBuilder.modules(javaTimeModule);
};
}
}
10.运行工具类
补充
实体类 时间格式为LocaDateTime
添加自动填充策略、逻辑删除策略、乐观锁注解
import com.baomidou.mybatisplus.annotation.*;
import java.time.LocalDateTime;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* <p>
*
* </p>
*
* @author myl
* @since 2022-06-20
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
@TableName("dept")
public class Dept implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.AUTO)
private Long deptno;
private String dname;
private String loc;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUserId;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUserId;
@Version
private Integer version;
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer isDelete;
}