20201122 MyBatis-Plus - 拉勾教育
MyBatis-Plus
MyBatis-Plus 概念
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
对于 MyBatis 整合 MP 有常常有三种用法,分别是 MyBatis + MP、Spring + MyBatis + MP、Spring
Boot + MyBatis + MP。
SpringBoot 整合 MP
-
准备数据
-- 创建测试表 DROP TABLE IF EXISTS tb_user; CREATE TABLE user ( id BIGINT(20) NOT NULL COMMENT '主键ID', name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名', age INT(11) NULL DEFAULT NULL COMMENT '年龄', email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱', PRIMARY KEY (id) ); -- 插入测试数据 INSERT INTO user (id, name, age, email) VALUES (1, 'Jone', 18, 'test1@baomidou.com'), (2, 'Jack', 20, 'test2@baomidou.com'), (3, 'Tom', 28, 'test3@baomidou.com'), (4, 'Sandy', 21, 'test4@baomidou.com'), (5, 'Billie', 24, 'test5@baomidou.com');
-
增加依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.0</version> </dependency>
-
application.properties
spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://192.168.181.130:3306/mp?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false spring.datasource.username=root spring.datasource.password=123456
-
实体类
@Data @NoArgsConstructor @AllArgsConstructor public class User { private Long id; private String name; private Integer age; private String email; }
-
Mapper 接口
package com.lagou.mybatisplus.dao; public interface UserMapper extends BaseMapper<User> { }
-
SpringBoot 启动类
@MapperScan("com.lagou.mybatisplus.dao") //设置mapper接口的扫描包 @SpringBootApplication public class MybatisplusApplication { public static void main(String[] args) { SpringApplication.run(MybatisplusApplication.class, args); } }
-
测试类
@SpringBootTest class MybatisplusApplicationTests { @Autowired private UserMapper userMapper; @Test public void testSelectList() { List<User> userList = userMapper.selectList(null); for (User user : userList) { System.out.println(user); } } @Test public void testSelectById() { //根据id查询数据 User user = this.userMapper.selectById(2L); System.out.println("result = " + user); } @Test public void testSelectBatchIds() { //根据id集合批量查询 List<User> users = this.userMapper.selectBatchIds(Arrays.asList(2L, 3L, 10L)); for (User user : users) { System.out.println(user); } } @Test public void testSelectOne() { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("name", "jack"); //根据条件查询一条数据,如果结果超过一条会报错 User user = this.userMapper.selectOne(wrapper); System.out.println(user); } @Test public void testSelectCount() { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.gt("age", 23); //年龄大于23岁 //根据条件查询数据条数 Integer count = this.userMapper.selectCount(wrapper); System.out.println("count = " + count); } @Test public void testSelectPage() { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.gt("age", 20); //年龄大于20岁 Page<User> page = new Page<>(1, 2); //根据条件查询数据 IPage<User> iPage = this.userMapper.selectPage(page, wrapper); System.out.println("数据总条数:" + iPage.getTotal()); System.out.println("总页数:" + iPage.getPages()); List<User> users = iPage.getRecords(); for (User user : users) { System.out.println("user = " + user); } } @Test public void testInsert() { User user = new User(); user.setAge(18); user.setMail("test@lagou.cn"); user.setName("子慕"); //返回的result是受影响的行数,并不是自增后的id int result = userMapper.insert(user); System.out.println(result); System.out.println(user.getId()); } /** * 根据id更新 */ @Test public void testUpdateById() { User user = new User(); user.setId(6L); //主键 user.setAge(21); //更新的字段 //根据id更新,更新不为null的字段 this.userMapper.updateById(user); } /** * 根据条件更新 */ @Test public void testUpdateByQueryWrapper() { User user = new User(); user.setAge(22); //更新的字段 //更新的条件 QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("id", 6); //执行更新操作 int result = this.userMapper.update(user, wrapper); System.out.println("result = " + result); } @Test public void testUpdateByUpdateWrapper() { //更新的条件以及字段 UpdateWrapper<User> wrapper = new UpdateWrapper<>(); wrapper.eq("id", 6).set("age", 23); //执行更新操作 int result = this.userMapper.update(null, wrapper); System.out.println("result = " + result); } @Test public void testDeleteById() { //执行删除操作 int result = this.userMapper.deleteById(6L); System.out.println("result = " + result); } @Test public void testDeleteByMap() { Map<String, Object> columnMap = new HashMap<>(); columnMap.put("age", 21); columnMap.put("name", "子慕"); //将columnMap中的元素设置为删除的条件,多个之间为and关系 int result = this.userMapper.deleteByMap(columnMap); System.out.println("result = " + result); } @Test public void testDeleteByQueryWrapper() { User user = new User(); user.setAge(20); user.setName("子慕"); //将实体对象进行包装,包装为操作条件 QueryWrapper<User> wrapper = new QueryWrapper<>(user); int result = this.userMapper.delete(wrapper); System.out.println("result = " + result); } @Test public void testDeleteByBatchIds() { //根据id集合批量删除 int result = this.userMapper.deleteBatchIds(Arrays.asList(1L, 10L, 20L)); System.out.println("result = " + result); } }
设置 id 的生成策略
- 参考
com.baomidou.mybatisplus.annotation.IdType
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user") // 指定实体类对应的表名
public class User {
@TableId(type = IdType.AUTO) //指定id类型为自增长,需要表设置主键自增
private Long id;
private String name;
private Integer age;
private String email;
}
@TableField
在MP中通过 @TableField 注解可以指定字段的一些属性,常常解决的问题有2个:
- 对象中的属性名和字段名不一致的问题(非驼峰)
- 对象中的属性字段在表中不存在的问题
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user") // 指定实体类对应的表名
public class User {
@TableId(type = IdType.AUTO) //指定id类型为自增长
private Long id;
@TableField(select = false) // 查询时不返回
private String name;
private Integer age;
@TableField("email") // 解决字段名称不一致
private String mail;
@TableField(exist = false) // 解决字段在表中不存在
private String address;
}
分页功能
增加配置:
@Configuration
@MapperScan("com.lagou.mybatisplus.dao") //设置mapper接口的扫描包
public class MyBatisPlusConfig {
/**
* 分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
测试功能:
@Test
public void testSelectPage() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("age", 20); //年龄大于20岁
Page<User> page = new Page<>(1, 2);
//根据条件查询数据
IPage<User> iPage = this.userMapper.selectPage(page, wrapper);
System.out.println("数据总条数:" + iPage.getTotal());
System.out.println("总页数:" + iPage.getPages());
List<User> users = iPage.getRecords();
for (User user : users) {
System.out.println("user = " + user);
}
}
SQL注入的原理
- MP 在启动后会将
BaseMapper
中的一系列的方法注册到mappedStatements
中 - 在 MP 中,
ISqlInjector
负责 SQL 的注入工作,它是一个接口,AbstractSqlInjector
是它的实现类
配置
## MyBatis 配置文件位置,如果有单独的 MyBatis 配置,请将其路径配置到 configLocation 中
mybatis-plus.config-location = classpath:mybatis-config.xml
## MyBatis Mapper 所对应的 XML 文件位置,如果您在 Mapper 中有自定义方法(XML 中有自定义实现),需要进行该配置,告诉 Mapper 所对应的 XML 文件位置
mybatis-plus.mapper-locations = classpath*:mybatis/*.xml
## MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在 Mapper 对应的 XML 文件中可以直接使用类名,而不用使用全限定的类名(即 XML 中调用的时候不用包含包名)
mybatis-plus.type-aliases-package = com.lagou.mp.pojo
## 关闭自动驼峰映射,该参数不能和mybatis-plus.config-location同时存在
mybatis-plus.configuration.map-underscore-to-camel-case=false
## 全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为 true。
mybatis-plus.configuration.cache-enabled=false
## 全局默认主键类型,设置后,即可省略实体对象中的@TableId(type = IdType.AUTO)配置。
mybatis-plus.global-config.db-config.id-type=auto
## 表名前缀,全局配置后可省略@TableName()配置。
mybatis-plus.global-config.db-config.table-prefix=tb_
条件构造器
com.baomidou.mybatisplus.core.conditions.Wrapper
QueryWrapper(LambdaQueryWrapper)
和UpdateWrapper(LambdaUpdateWrapper)
的父类用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件,注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为
@SpringBootTest
public class MPWrapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testWrapperllEq() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
//设置条件
Map<String, Object> params = new HashMap<>();
params.put("name", "jack");
params.put("age", "20");
// wrapper.allEq(params);// SELECT id,age,email AS mail FROM tb_user WHERE (name = ? AND age = ?)
wrapper.allEq(params, false); // SELECT id,age,email AS mail FROM tb_user WHERE (name = ? AND age = ?)
wrapper.allEq((k, v) -> (k.equals("name") || k.equals("email")), params);// SELECT id,age,email AS mail FROM tb_user WHERE (name = ? AND age = ? AND name = ? AND age = ?)
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
@Test
public void testWrapperCompare() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
// (email = ? AND age >= ? AND name IN (?,?,?))
wrapper.eq("email", "test2@baomidou.com").ge("age", 20).in("name", "jack", "jone", "tom");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
@Test
public void testWrapperLike() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
// (name LIKE ?)
// Parameters: %子%(String)
wrapper.like("name", "子");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
@Test
public void testWrapperOrderBy() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
// ORDER BY age DESC
wrapper.orderByDesc("age");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
@Test
public void testWrapperLogic() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
// (name = ? OR age = ?)
wrapper.eq("name","jack").or().eq("age", 24);
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
@Test
public void testWrapperSelect() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
// SELECT id,name,age FROM tb_user WHERE (name = ? OR age = ?)
wrapper.eq("name", "jack")
.or()
.eq("age", 24)
.select("id", "name", "age");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
}
ActiveRecord
ActiveRecord也属于ORM(对象关系映射)层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,记录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的快速实现模型的操作,而且简洁易懂。
ActiveRecord的主要思想是:
- 每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录;通常表的每个字段在类中都有相应的Field;
- ActiveRecord同时负责把自己持久化,在ActiveRecord中封装了对数据库的访问,即 CURD;
- ActiveRecord是一种领域模型(Domain Model),封装了部分业务逻辑;
使用步骤
-
实体类,继承
com.baomidou.mybatisplus.extension.activerecord.Model
@Data @NoArgsConstructor @AllArgsConstructor @TableName("tb_user") public class ARUser extends Model<ARUser> { private Long id; private String name; private Integer age; private String email; }
-
Mapper 接口实现
com.baomidou.mybatisplus.core.mapper.BaseMapper
public interface ARUserMapper extends BaseMapper<ARUser> { }
-
测试功能
@SpringBootTest public class MPARTest { @Test public void testAR() { ARUser user = new ARUser(); user.setId(2L); // SELECT id,name,age,email FROM tb_user WHERE id=? ARUser user2 = user.selectById(); System.out.println(user2); } }
插件
MP 执行分析插件
- 攻击 SQL 阻断解析器,防止全表更新与删除
- 在MP中提供了对SQL执行的分析的插件,可用作阻断全表更新、删除的操作
- 注意:该插件仅适用于开发环境,不适用于生产环境
配置插件:
@Configuration
@MapperScan("com.lagou.mybatisplus.dao") //设置mapper接口的扫描包
public class MyBatisPlusConfig {
/**
* 分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// 分页拦截器
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
// 攻击 SQL 阻断解析器,防止全表更新与删除
mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return mybatisPlusInterceptor;
}
}
测试功能:
@Test
public void testBlockAttackInnerInterceptor() {
userMapper.delete(null);
// org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
// ### Error updating database. Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Prohibition of full table deletion
}
性能分析插件
- 性能分析拦截器,用于输出每条 SQL 语句及其执行时间,可以设置最大执行时间,超过时间会抛出异常。
- 该插件只用于开发环境,不建议生产环境使用。
- MP 在 3.2 的版本已经移除了这个性能分析插件并推荐使用第三方插件。
使用步骤
-
添加依赖
<dependency> <groupId>p6spy</groupId> <artifactId>p6spy</artifactId> <version>3.9.1</version> </dependency>
-
修改配置,数据库连接信息
spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver spring.datasource.url=jdbc:p6spy:mysql://192.168.181.130:3306/mp?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false
-
增加 p6spy 配置,
spy.properties
#3.2.1以上使用 modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory #3.2.1以下使用或者不配置 #modulelist=com.p6spy.engine.logging.P6LogFactory,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 # 实际驱动可多个 #driverlist=org.h2.Driver # 是否开启慢SQL记录 outagedetection=true # 慢SQL记录标准 2 秒 outagedetectioninterval=2
-
测试使用,打印日志如下
Consume Time:2 ms 2020-11-22 20:40:54 Execute SQL:SELECT id,age,email AS mail FROM tb_user
乐观锁插件
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时,
set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
- 表中增加字段 version
ALTER TABLE `tb_user` ADD COLUMN `version` int(10) NULL AFTER `email`;
UPDATE `tb_user` SET `version`='1';
- 实体类增加属性 version,注解
@Version
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user") // 指定实体类对应的表名
public class User {
@TableId(type = IdType.AUTO) //指定id类型为自增长
private Long id;
@TableField(select = false) // 查询时不返回
private String name;
private Integer age;
@TableField("email") // 解决字段名称不一致
private String mail;
@TableField(exist = false) // 解决字段在表中不存在
private String address;
@Version
private Integer version;
}
- 测试功能
/**
* 测试乐观锁
*/
@Test
public void testUpdateByIdVersion() {
User user = new User();
user.setId(7L); //主键
user.setAge(21); //更新的字段
user.setVersion(1);
// UPDATE tb_user SET age=21, version=2 WHERE id=7 AND version=1
int rowCount = this.userMapper.updateById(user);
System.out.println(rowCount);
}
Sql 注入器
- 在 MP 中,通过
AbstractSqlInjector
将BaseMapper
中的方法注入到了 MyBatis 容器 - 扩充
BaseMapper
中的方法,以扩展findAll
方法为例
使用步骤
-
MyBaseMapper ,扩展 BaseMapper
public interface MyBaseMapper<T> extends BaseMapper<T> { List<T> findAll(); }
-
Mapper 继承 MyBaseMapper
public interface UserMapper extends MyBaseMapper<User> { }
-
自定义 MySqlInjector ,扩展 DefaultSqlInjector,并注册到 Spring 容器
public class MySqlInjector extends DefaultSqlInjector { @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass) { List<AbstractMethod> methodList = super.getMethodList(mapperClass); // 扩充自定义的方法 methodList.add(new FindAll()); return methodList; } }
/** * 自定义SQL注入器 */ @Bean public MySqlInjector mySqlInjector() { return new MySqlInjector(); }
-
FindAll,自定义 AbstractMethod
public class FindAll extends AbstractMethod { @Override public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) { String sqlMethod = "findAll"; String sql = "select * from " + tableInfo.getTableName(); // SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); SqlSource sqlSource = new RawSqlSource(configuration, String.format(sql, sqlSelectColumns(tableInfo, false), tableInfo.getTableName(), tableInfo.getKeyColumn(), tableInfo.getKeyProperty(), tableInfo.getLogicDeleteSql(true, true)), Object.class); return this.addSelectMappedStatementForTable(mapperClass, sqlMethod, sqlSource, tableInfo); } }
-
功能测试
/** * 测试 SQL 注入器,findAll */ @Test public void testFindAll() { List<User> userList = userMapper.findAll(); for (User user : userList) { System.out.println(user); } }
自动填充功能
- 有些时候我们可能会有这样的需求,插入或者更新数据时,希望有些字段可以自动填充数据,比如密码、version 等。在MP中提供了这样的功能,可以实现自动填充。
-
实体类添加注解,
@TableField(fill = FieldFill.INSERT)
@Data @NoArgsConstructor @AllArgsConstructor @TableName("tb_user") // 指定实体类对应的表名 public class User { @TableId(type = IdType.AUTO) //指定id类型为自增长 private Long id; @TableField(select = false) // 查询时不返回 private String name; @TableField(fill = FieldFill.INSERT) // 插入时自动填充 private Integer age; @TableField(value = "email") // 解决字段名称不一致 private String mail; @TableField(exist = false) // 解决字段在表中不存在 private String address; @Version private Integer version; }
-
MyMetaObjectHandler
,实现MetaObjectHandler
,并注册到 Spring 容器中public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { Object password = getFieldValByName("age", metaObject); if (null == password) { //字段为空,可以进行填充 setFieldValByName("age", 18, metaObject); } } @Override public void updateFill(MetaObject metaObject) { } }
/** * 元对象字段填充控制器抽象类,实现公共字段自动写入 * @return */ @Bean public MyMetaObjectHandler myMetaObjectHandler() { return new MyMetaObjectHandler(); }
-
测试功能
/**
* 测试自动填充功能
*/
@Test
public void testInsertAuto() {
User user = new User();
user.setMail("test@lagou.cn");
user.setName("子慕xx");
// INSERT INTO tb_user ( name, age, email ) VALUES ( '子慕xx', 18, 'test@lagou.cn' )
int result = userMapper.insert(user);
System.out.println(result);
System.out.println(user.getId());
}
逻辑删除
- 修改表结构,增加字段 deleted
ALTER TABLE `tb_user`
ADD COLUMN `deleted` int(1) NULL DEFAULT 0 COMMENT '1代表删除,0代表未删除' AFTER `version`;
-
增加配置
# 逻辑已删除值(默认为 1) mybatis-plus.global-config.db-config.logic-delete-value=1 # 逻辑未删除值(默认为 0) mybatis-plus.global-config.db-config.logic-not-delete-value=0
-
测试功能,打印日志如下
删除日志:
UPDATE tb_user SET deleted=1 WHERE id=2 AND deleted=0
查询日志:
SELECT id,age,email AS mail,version,deleted FROM tb_user WHERE deleted=0
代码生成器
-
添加依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
-
执行主类,生成文件
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.io.File; 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 + "!"); } /** * RUN THIS */ public static void main(String[] args) { // 代码生成器 AutoGenerator mpg = new AutoGenerator(); // 全局配置 GlobalConfig gc = new GlobalConfig(); String moduleName = "mybatisplus"; String projectPath = System.getProperty("user.dir") + File.separator + moduleName; gc.setOutputDir(projectPath + "/src/main/java"); gc.setAuthor("lagou"); gc.setOpen(false); mpg.setGlobalConfig(gc); // 数据源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://192.168.181.130:3306/mp?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false"); // dsc.setSchemaName("public"); dsc.setDriverName("com.mysql.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("123456"); mpg.setDataSource(dsc); // 包配置 PackageConfig pc = new PackageConfig(); pc.setModuleName(scanner("模块名")); pc.setParent("com.lagou.mp.generator"); mpg.setPackageInfo(pc); // 自定义配置 InjectionConfig cfg = new InjectionConfig() { @Override public void initMap() { // to do nothing } }; List<FileOutConfig> focList = new ArrayList<>(); focList.add(new FileOutConfig("/templates/mapper.xml.ftl") { @Override public String outputFile(TableInfo tableInfo) { // 自定义输入文件名称 return projectPath + "/src/main/resources/mapper/" + pc.getModuleName() + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; } }); cfg.setFileOutConfigList(focList); mpg.setCfg(cfg); mpg.setTemplate(new TemplateConfig().setXml(null)); // 策略配置 StrategyConfig strategy = new StrategyConfig(); strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); // 设置实体类的超类 // strategy.setSuperEntityClass("com.baomidou.mybatisplus.samples.generator.common.BaseEntity"); strategy.setEntityLombokModel(true); // 设置 Controller 的超类 // strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.com mon.BaseController"); strategy.setInclude(scanner("表名")); strategy.setSuperEntityColumns("id"); strategy.setControllerMappingHyphenStyle(true); strategy.setTablePrefix(pc.getModuleName() + "_"); mpg.setStrategy(strategy); // 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有! mpg.setTemplateEngine(new FreemarkerTemplateEngine()); mpg.execute(); } }
-
确认文件生成
请输入模块名: user 请输入表名: tb_user 21:56:37.907 [main] DEBUG com.baomidou.mybatisplus.generator.AutoGenerator - ==========================准备生成文件...========================== 创建目录: [E:\Develop\workspace\IDEA_2020\studyInLaGou\mybatisplus/src/main/java\com\lagou\mp\generator\user\entity] 创建目录: [E:\Develop\workspace\IDEA_2020\studyInLaGou\mybatisplus/src/main/java\com\lagou\mp\generator\user\controller] 创建目录: [E:\Develop\workspace\IDEA_2020\studyInLaGou\mybatisplus/src/main/java\com\lagou\mp\generator\user\mapper] 创建目录: [E:\Develop\workspace\IDEA_2020\studyInLaGou\mybatisplus/src/main/java\com\lagou\mp\generator\user\service\impl] 模板:/templates/entity.java.ftl; 文件:E:\Develop\workspace\IDEA_2020\studyInLaGou\mybatisplus/src/main/java\com\lagou\mp\generator\user\entity\TbUser.java 模板:/templates/mapper.java.ftl; 文件:E:\Develop\workspace\IDEA_2020\studyInLaGou\mybatisplus/src/main/java\com\lagou\mp\generator\user\mapper\TbUserMapper.java 模板:/templates/service.java.ftl; 文件:E:\Develop\workspace\IDEA_2020\studyInLaGou\mybatisplus/src/main/java\com\lagou\mp\generator\user\service\ITbUserService.java 模板:/templates/serviceImpl.java.ftl; 文件:E:\Develop\workspace\IDEA_2020\studyInLaGou\mybatisplus/src/main/java\com\lagou\mp\generator\user\service\impl\TbUserServiceImpl.java 模板:/templates/controller.java.ftl; 文件:E:\Develop\workspace\IDEA_2020\studyInLaGou\mybatisplus/src/main/java\com\lagou\mp\generator\user\controller\TbUserController.java 21:56:38.532 [main] DEBUG com.baomidou.mybatisplus.generator.AutoGenerator - ==========================文件生成完成!!!==========================