1: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 操作智能分析阻断,也可自定义拦截规则,预防误操作

2:快速开始

本模块来自官方文档,使用SpringBoot完成

2-1:创建表和添加数据

User表结构如下:

id name age email
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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');

2-2:初始化工程

SpringBoot版本:2.3.3.RELEASE
Mybatis-Plus:3.3.2
MySQL:8.21

2-2-1:依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!-- mp -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>

如上,mp只需要添加一个依赖,其余都是常规的依赖。

2-2-2:配置

配置数据库连接:

1
2
3
4
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/practice?userUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

日志查看sql语句(可以不加):

1
2
3
4
5
# 通过slf4j查看,设置mapper接口所在包loggging.level为debug
# logging.level.com.xqm.mybatisplus.mapper=debug

# 这种查看方式更详细
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹(可在mapper.java文件上使用@Mapper代替):

1
2
3
4
5
6
7
8
9
@MapperScan("com.xqm.mybatisplus.mapper")
@SpringBootApplication
public class MybatisPlusApplication {

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

}

2-2-3:编码

实例类User.java(此处使用lombok)

1
2
3
4
5
6
7
8
9
@Data
@Accessors(chain = true)
// 链式编程:setter方法返回一个对象
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}

接口文件mapper.java

1
2
3
4
5
@Repository
// 使Spring能扫描到,不加也可以,不加Idea最高等级警告会报错,强迫症可以加上
public interface UserMapper extends BaseMapper<User> {

}

2-2-4:开始使用

1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootTest
class MybatisPlusApplicationTests {
@Autowired
UserMapper userMapper;

@Test
void contextLoads() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}

}

UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件

控制台输出:

1
2
3
4
5
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)

3:CRUD扩展

3-1:插入操作

1
2
3
4
5
6
7
8
9
10
@Test
void testInsert() {
User user = new User();
user.setName("失铭").setAge(1).setEmail("123@qq.com");
int insert = userMapper.insert(user);
System.out.println(insert);
// 影响行数
System.out.println(user);
// id自动回填
}

3-2:主键策略

@TableId:主键注解,添加后默认:ASSIGN_UUID 分配UUID

属性 类型 必须指定 默认值 描述
value String “” 主键字段名
type Enum IdType.ASSIGN_UUID 主键类型

3-2-1:IdType

描述
AUTO 数据库ID自增
NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUT insert前自行set主键值
ASSIGN_ID 分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
ASSIGN_UUID 分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认default方法)
ID_WORKER 分布式全局唯一ID 长整型类型(please use ASSIGN_ID)
UUID 32位UUID字符串(please use ASSIGN_UUID)
ID_WORKER_STR 分布式全局唯一ID 字符串类型(please use ASSIGN_ID)

雪花算法:snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。

type设置为IdType.INPUT,需要手动输入,否则id为null

3-2-2:主键自增

  1. 实体类字段上``@TableId(type=IdType.AUTO)
  2. 数据库主键设置自增

3-3:更新操作

1
2
3
4
5
6
7
8
9
10
11
@Test
void testUpdate() {
User user = new User();
// 通过条件自动拼接动态sql
user.setId(1L).setAge(10).setEmail("123@gmail.com");

// 注意:传入参数为对象
// 源码:int updateById(@Param("et") T entity);
int i = userMapper.updateById(user);
System.out.println(i);
}

3-4:自动填充

创建时间(gmt_create),修改时间(gmt_modified)。自动化完成,不希望手动更新!
阿里巴巴java开发手册中规定如下:
20200824084406

3-4-1:方式一:数据库级别

  • 数据类型设为:datatime
  • 默认值:CURRENT_TIMESTAMP

注意:更新时间需要设置为根据时间戳更新

20200824084821
20200824084925

添加字段:

1
2
private Date gmtCreate;
private Date gmtModified;

3-4-2:方式二:代码级别

添加注解

1
2
3
4
5
@TableField(fill = FieldFill.INSERT)
private LocalDateTime gmtCreate;

@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime gmtModified;

注意:数据类型使用LocalDateTime,这里有一个小坑,等会说。

自定义实现类MyMetaObjectHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.strictInsertFill(metaObject, "gmtCreate", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "gmtModified", LocalDateTime.class, LocalDateTime.now());
}

@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.strictUpdateFill(metaObject, "gmtModified", LocalDateTime.class, LocalDateTime.now());
}
}

重新测试插入和更新,可以看到时间填充成功。

这里有两个问题:

  1. 时间差8个小时:这是因为数据库连接语句时区的设置的世界标准时间(UTC),而北京时间比标准时间快八个小时。所以需要将时间设置为:GMT%2B8。如:serverTimezone=GMT%2B8
  2. LocalDateTimeLocalDateTime是java8提供的新的日期和时间API,详细了解参考->廖雪峰的官方网站-LocalDateTime。实体类和实现类的时间类型要一致。例如:我的gmtCreate使用的LocalDateTime类型,那么填充语句中,也要写LocalDateTime.class。实体类定义的是Date类型,填充语句就要写Date.class

3-4-3:@TableField注解(了解)

@TableField:字段注解(非主键)

属性 类型 必须指定 默认值 描述
value String “” 数据库字段名
el String “” 映射为原生 #{ ... } 逻辑,相当于写在 xml 里的 #{ ... } 部分
exist boolean true 是否为数据库表字段
condition String “” 字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考
update String “” 字段 update set 部分注入, 例如:update="%s+1":表示更新时会set version=version+1(该属性优先级高于 el 属性)
insertStrategy Enum N DEFAULT 举例:NOT_NULL: insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
updateStrategy Enum N DEFAULT 举例:IGNORED: update table_a set column=#{columnProperty}
whereStrategy Enum N DEFAULT 举例:NOT_EMPTY: where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
fill Enum FieldFill.DEFAULT 字段自动填充策略
select boolean true 是否进行 select 查询
keepGlobalFormat boolean false 是否保持使用全局的 format 进行处理
jdbcType JdbcType JdbcType.UNDEFINED JDBC类型 (该默认值不代表会按照该值生效)
typeHandler Class<? extends TypeHandler> UnknownTypeHandler.class 类型处理器 (该默认值不代表会按照该值生效)
numericScale String “” 指定小数点后保留的位数

关于jdbcTypetypeHandler以及numericScale的说明:
numericScale只生效于 update 的sql. jdbcType和typeHandler如果不配合@TableName#autoResultMap = true一起使用,也只生效于 update 的sql.
对于typeHandler如果你的字段类型和set进去的类型为equals关系,则只需要让你的typeHandler让Mybatis加载到即可,不需要使用注解

FieldStrategy:

描述
IGNORED 忽略判断
NOT_NULL 非NULL判断
NOT_EMPTY 非空判断(只对字符串类型字段,其他类型字段依然为非NULL判断)
DEFAULT 追随全局配置

FieldFill:

描述
DEFAULT 默认不处理
INSERT 插入时填充字段
UPDATE 更新时填充字段
INSERT_UPDATE 插入和更新时填充字段

4:乐观锁

  • 悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
  • 乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。乐观锁适用于读多写少的应用场景,这样可以提高吞吐量。

意图:

当要更新一条记录的时候,希望这条记录没有被别人更新

乐观锁实现方式:

  1. 取出记录时,获取当前version
  2. 更新时,带上这个version
  3. 执行更新时, set version = newVersion where version = oldVersion
  4. 如果version不对,就更新失败

乐观锁实现只需两步

4-1. 注册组件OptimisticLockerInterceptor

1
2
3
4
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}

4-2.:version字段添加@Version注解

1
2
@Version
private Integer version;

特别说明:

  • 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
  • 整数类型下 newVersion = oldVersion + 1
  • newVersion 会回写到 entity 中
  • 仅支持 updateById(id) 与 update(entity, wrapper) 方法
  • 在 update(entity, wrapper) 方法下, wrapper 不能复用!!!

4-3:乐观锁示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 乐观锁成功
@Test
void testOptimisticLocker() {
// 查询用户信息
User user = userMapper.selectById(5L);
// 修改用户信息
user.setEmail("456@gmail.com").setAge(100);

// 更新信息
userMapper.updateById(user);
}

// 乐观锁失败
@Test
void testOptimisticLocker2() {
// 查询用户信息
User user = userMapper.selectById(5L);
// 修改用户信息
user.setEmail("456@gmail.com").setAge(100);

// 模拟多线程插队
User user2 = userMapper.selectById(5L);
user2.setEmail("123456@gmail.com").setAge(50);
userMapper.updateById(user2);

// 自旋锁多次提交
// 如果没有乐观锁会覆盖插队线程的值
userMapper.updateById(user);
}

观察控制台日志,可以发现:

1
UPDATE user SET name=?, age=?, email=?, version=?, gmt_create=?, gmt_modified=? WHERE id=? AND version=?

如上,id和version都相同时才更新,很简单的就实现了乐观锁

5:查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 查询
// 单个查询
@Test
void testSelect() {
User user = userMapper.selectById(1L);
System.out.println(user);
}

// 批量查询
@Test
void testSelectBatchIds() {
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
System.out.println(users);
}

// 条件查询之一:map
@Test
void testSelectByMap() {
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("name", "Jone");
List<User> users = userMapper.selectByMap(hashMap);
System.out.println(users);
}

5-1:分页查询

5-1-1:添加插件

1
2
3
4
5
6
7
8
9
10
11
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}

也可以简单一点:

1
2
3
4
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}

5-2-2:分页查询示例

1
2
3
4
5
6
7
8
9
10
11
// 分页
@Test
void testPage() {
// 参数一:页码
// 参数二:页面大小
// 原理:拦截器分页,系统添加limit
Page<User> page = new Page<>(1, 5);
userMapper.selectPage(page, null);

page.getRecords().forEach(System.out::println);
}

6:删除操作

1
2
3
4
5
6
7
8
9
10
11
@Test
void testDelete() {
// 单个删除
userMapper.deleteById(1297730862471913474L);
// 批量删除
userMapper.deleteBatchIds(Arrays.asList(1297730992902164482L, 1297731359643713538L));
// 条件删除
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("id",1297731433178230785L);
userMapper.deleteByMap(hashMap);
}

6-1:逻辑删除

  • 物理删除:从数据库中直接移除
  • 逻辑删除:未从数据库中移除,而是通过一个变量让他失效,例:deleted = 0 -> deleted =1

准备工作:

数据库添加字段:

20200824111900

默认值为0

修改实体类:

1
private int deleted;

实际使用:

修改配置文件:

1
2
3
4
5
6
7
# 逻辑删除
mybatis-plus.global-config.db-config.logic-delete-field=deleted
# 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-not-delete-value=0
# 逻辑未删除值(默认为 0)

实体类添加@TableLogic注解:

如果设置了mybatis-plus.global-config.db-config.logic-delete-field = deleted,那么只需要有deleted这个属性即可,不需要添加注解。

1
2
@TableLogic
private Integer deleted;

修改配置后原来的删除语句就会变为更新语句,例:

1
2
3
4
5
6
@Test
void testDelete() {
// 单个删除
userMapper.deleteById(2L);
// sql语句为:UPDATE user SET deleted=1 WHERE id=2 AND deleted=0
}

注:添加逻辑删除后查询自动添加deleted = 0条件

官方说明如下:

20200824112551

7:条件构造器

十分重要:Wrapper
我们写一些复杂的sql就可以使用它来替代!

官方文档

1、测试一

1
2
3
4
5
6
7
8
9
10
11
@Test
void contextLoads() {
 // 查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于12
 QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.isNotNull("name")
.isNotNull("email")
.ge("age",12);
userMapper.selectList(wrapper).forEach(System.out::println);
// 和我们刚才学习的map对比一下
}

2、测试二

1
2
3
4
5
6
7
8
@Test
void test2(){
 // 查询名字狂神说
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","狂神说");
User user = userMapper.selectOne(wrapper); // 查询一个数据,出现多个结果使用List 或者 Map
System.out.println(user);
}

3、测试三

1
2
3
4
5
6
@Test
void test3(){
// 查询年龄在 20 ~ 30 岁之间的用户
QueryWrapper<User> wrapper = new QueryWrapper<>();  wrapper.between("age",20,30); // 区间
Integer count = userMapper.selectCount(wrapper);// 查询结果数 System.out.println(count);
}

4、测试四

1
2
3
4
5
6
7
8
9
10
// 模糊查询
@Test
void test4(){
// 查询年龄在 20 ~ 30 岁之间的用户
QueryWrapper<User> wrapper = new QueryWrapper<>();  // 左和右 t%
wrapper
.notLike("name","e")
.likeRight("email","t");
List<Map<String, Object>> maps = userMapper.selectMaps(wrapper); maps.forEach(System.out::println);
}

5、测试五

1
2
3
4
5
6
7
8
// 模糊查询
@Test
void test5(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
// id 在子查询中查出来
wrapper.inSql("id","select id from user where id<3");
List<Object> objects = userMapper.selectObjs(wrapper); objects.forEach(System.out::println);
}

6、测试六

1
2
3
4
5
6
7
//测试六
@Test
void test6(){
QueryWrapper<User> wrapper = new QueryWrapper<>();  // 通过id进行排序
wrapper.orderByAsc("id");
List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println);
}

8:自动生成代码

依赖:

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.ArrayList;

public class MybatisGenerator {

public static void Generator(String moduleName, String include) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();

// 全局配置
GlobalConfig gc = new GlobalConfig();
// 当前目录的/src/main/java目录下
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
// 开发人员
gc.setAuthor("ShiMing");
// 输出目录
gc.setOpen(false);
// 是否覆盖
gc.setFileOverride(true);
// 去掉ServiceI前缀
gc.setServiceName("%sService");
// 主键策略
gc.setIdType(IdType.ASSIGN_ID);
// 时间类型
gc.setDateType(DateType.ONLY_DATE);
// Swagger2
gc.setSwagger2(true);

mpg.setGlobalConfig(gc);

// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/practice?userUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);

// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(moduleName);
pc.setParent("com.xqm");
pc.setEntity("pojo");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);

// 策略配置
StrategyConfig strategy = new StrategyConfig();
// 表名
strategy.setInclude(include.split(","));
// 下划线转驼峰
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// 自动lombok
strategy.setEntityLombokModel(true);
// 链式编程
strategy.setChainModel(true);
// 自动填充-创建时间,更新时间
TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
// 逻辑删除
strategy.setLogicDeleteFieldName("deleted");
// 乐观锁
strategy.setVersionFieldName("version");

strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);
mpg.setStrategy(strategy);

mpg.execute();
}

public static void main(String[] args) {
// 模块名
String moduleName = "mybatis";
// 表名,多个表名用","分开
String include = "user,student";
// 生成文件
Generator(moduleName, include);
}
}

使用效果如下:

20200824132645

9:参考