获取依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 仓库地址 -->
<repositories>
<repository>
<id>github-maven-repo</id>
<url>https://raw.github.com/fanlychie/maven-repo/releases</url>
</repository>
</repositories>
<dependencies>
<!-- 声明依赖,版本信息参考:https://github.com/fanlychie/mybatis-template-generator/releases -->
<dependency>
<groupId>org.fanlychie</groupId>
<artifactId>mybatis-template-generator</artifactId>
<version>2.0</version>
<!-- 打包时可顺利排除此依赖 -->
<scope>test</scope>
</dependency>
</dependencies>

环境要求

JDK1.7 或以上版本

项目地址

https://github.com/fanlychie/mybatis-template-generator

配置

配置文件

在项目类路径下新建一个文件 mybatis-template-generator.xml (右键链接另存为下载), 内容如下:

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
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 自定义属性, 通过 ${} 占位符来引用 -->
<properties>
<!-- 引入属性配置文件 -->
<include location="jdbc.properties"/>
<!-- 自定义属性键值对 -->
<property name="basePackage" value="com.domain"/>
</properties>
<!-- 数据源配置 -->
<datasource>
<!-- 数据库连接地址 -->
<property name="url" value="${jdbc.url}"/>
<!-- 数据库账户名称 -->
<property name="username" value="${jdbc.username}"/>
<!-- 数据库账户密码 -->
<property name="password" value="${jdbc.password}"/>
<!-- 数据库连接驱动 -->
<property name="driverClass" value="${jdbc.driver}"/>
</datasource>
<!-- 表配置 -->
<table>
<!-- 表名分隔符 -->
<property name="separator" value="_"/>
<!-- 忽略表, 匹配的表将被忽略不处理 -->
<property name="ignores">
<value>temp*</value>
</property>
<!-- 逃逸表, 匹配的表总是会输出文件 -->
<property name="escapes">
<value>none</value>
</property>
<!-- 表前缀, 输出的类文件忽略此名称 -->
<property name="prefixs">
<value>tb_</value>
</property>
</table>
<!-- 列配置 -->
<column>
<!-- 列名分隔符 -->
<property name="separator" value="_"/>
<!-- 忽略列, 匹配的列将被忽略不处理 -->
<property name="ignores">
<value>temp*</value>
</property>
<!-- 逃逸列, 匹配的列总是会输出属性 -->
<property name="escapes">
<value>none</value>
</property>
<!-- 列前缀, 输出的属性忽略此前缀名 -->
<property name="prefixs">
<value>none</value>
</property>
</column>
<!-- 输出配置 -->
<output>
<!-- 实体类 -->
<property name="entity" folder="${basedir}/src/main/java" package="${basePackage}.entity"/>
<!-- Mybatis 实体类对应的 Xml 文件 -->
<property name="mapperXml" folder="${basedir}/src/main/resources" package="${basePackage}.mapper"/>
<!-- Dao 接口 -->
<property name="dao" folder="${basedir}/src/main/java" package="${basePackage}.dao"/>
<!-- Dao 实现类 -->
<property name="daoImpl" folder="${basedir}/src/main/java" package="${basePackage}.dao.impl"/>
<!-- Service 接口 -->
<property name="service" folder="${basedir}/src/main/java" package="${basePackage}.service"/>
<!-- Service 实现类 -->
<property name="serviceImpl" folder="${basedir}/src/main/java" package="${basePackage}.service.impl"/>
<!-- 每次生成时总是覆盖输出 -->
<property name="overwrite">
<value>none</value>
</property>
</output>
</configuration>

properties

配置模板文件上下文参数键值对, 上下文环境可以通过 ${} 语法来引用自定义的键值对

通过类路径下的属性文件引入:

1
<include location="jdbc.properties"/>

直接声明键值对:

1
<property name="basePackage" value="com.domain"/>

datasource

配置数据源信息:

1
2
3
4
5
6
7
8
9
10
<!-- 数据库连接地址 -->
<property name="url" value="${jdbc.url}"/>
<!-- 数据库账户名称 -->
<property name="username" value="${jdbc.username}"/>
<!-- 数据库账户密码 -->
<property name="password" value="${jdbc.password}"/>
<!-- 数据库连接驱动 -->
<property name="driverClass" value="${jdbc.driver}"/>
<!-- 元数据类, 默认配置 -->
<property name="metadataClass" value="org.fanlychie.mybatis.template.db.MySQLMetadata"/>

metadataClass 默认使用 MySQL 数据库实现

其它数据库生成模板代码需实现抽象类 org.fanlychie.mybatis.template.db.DatabaseMetadata

table

数据库表配置信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 表名分隔符 -->
<property name="separator" value="_"/>
<!-- 忽略表, 匹配的表将被忽略不处理 -->
<property name="ignores">
<value>temp*</value>
</property>
<!-- 逃逸表, 匹配的表总是会输出文件 -->
<property name="escapes">
<value>none</value>
</property>
<!-- 表前缀, 输出的类文件忽略此名称 -->
<property name="prefixs">
<value>tb_</value>
</property>
参数 描述
separator 表名分隔符, 用于驼峰拼写, 例: user_info -> UserInfo
ignores 忽略表, 匹配的表将被忽略不处理
escapes 逃逸表, 它无视 ignores 配置的规则, 匹配的表总是会输出文件
prefixs 表前缀, 输出的类文件忽略此名称, 例: tb_user_info -> UserInfo

column

数据库列配置信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 列名分隔符 -->
<property name="separator" value="_"/>
<!-- 忽略列, 匹配的列将被忽略不处理 -->
<property name="ignores">
<value>temp*</value>
</property>
<!-- 逃逸列, 匹配的列总是会输出属性 -->
<property name="escapes">
<value>none</value>
</property>
<!-- 列前缀, 输出的属性忽略此前缀名 -->
<property name="prefixs">
<value>none</value>
</property>
<!-- 数据库类型和 JAVA 数据类型的映射表 -->
<property name="typeMapping">
<value jdbcType="varchar" javaType="String" />
</property>
参数 描述
separator 列名分隔符, 用于驼峰拼写, 例: user_id -> userId
ignores 忽略列, 匹配的表将被忽略不处理
escapes 逃逸列, 它无视 ignores 配置的规则, 匹配的列总是输出到对象属性或文件
prefixs 列前缀, 输出的属性忽略此前缀名
typeMapping 数据库类型和 JAVA 数据类型的映射表

output

模板文件输出配置信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 实体类 -->
<property name="entity" folder="${basedir}/src/main/java" package="${basePackage}.entity"/>
<!-- Mybatis 实体类对应的 Xml 文件 -->
<property name="mapperXml" folder="${basedir}/src/main/resources" package="${basePackage}.mapper"/>
<!-- Dao 接口 -->
<property name="dao" folder="${basedir}/src/main/java" package="${basePackage}.dao"/>
<!-- Dao 实现类 -->
<property name="daoImpl" folder="${basedir}/src/main/java" package="${basePackage}.dao.impl"/>
<!-- Service 接口 -->
<property name="service" folder="${basedir}/src/main/java" package="${basePackage}.service"/>
<!-- Service 实现类 -->
<property name="serviceImpl" folder="${basedir}/src/main/java" package="${basePackage}.service.impl"/>
<!-- 每次生成时总是覆盖输出 -->
<property name="overwrite">
<value>none</value>
</property>

${basedir} 表示当前项目的路径

参数 描述
folder 模板文件输出到的目录路径
package 模板文件使用的包名
overwrite 可以指定哪些模板文件强制重新生成输出
例: 只重新生成 user_info 表相关的文件 UserInfo*
例: 只重新生成 user_info 表 XML 文件 UserInfo*.xml

生成模板文件

maven 命令

1
mvn exec:java -Dexec.mainClass=MyBatisTemplateGenerator -Dexec.classpathScope=test

Java 方法调用

1
2
3
public static void main(String[] args) {
org.fanlychie.mybatis.template.Generator.generate();
}

使用

引入测试依赖包:

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>

以 user 用户表为例:

用户表

模板文件

除常规文件生成外代码生成器还会为每一个表生成对应的 Criteria 类用于 SQL 条件操作例: user 表 -> UserCriteria

Criteria 类拥有和实体类一致的 set 方法不同的是 Criteria 类的 set 方法的参数接收的是 Criterion 对象Criterion 对象通过 Value 静态方法来构建见下文

日志

设置输出 SQL 语句 ( com.domain 替换成你自己的包名 ) :

1
log4j.logger.com.domain.dao = DEBUG

保存数据

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
import com.domain.entity.User;
import com.domain.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Date;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/spring-context.xml")
public class UserTest {
@Autowired
private UserService userService;
@Test
public void testSave() {
User user = new User();
user.setName("张三");
user.setAge(23);
user.setSalary(8600F);
user.setProvince("广东");
user.setCity("广州");
user.setArea("天河区");
user.setCreateTime(new Date());
// 保存数据
Integer id = userService.save(user);
}
}

单元测试:

1
2
3
DEBUG [save:145] - ==> Preparing: INSERT INTO USER ( ID, NAME, AGE, SALARY, PROVINCE, CITY, AREA, CREATE_TIME ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )
DEBUG [save:145] - ==> Parameters: null, 张三(String), 23(Integer), 8600.0(Float), 广东(String), 广州(String), 天河区(String), 2017-02-04 17:33:09.373(Timestamp)
DEBUG [save:145] - <== Updates: 1

更新数据

根据主键更新

1
2
3
4
5
6
7
8
@Test
public void testUpdate() {
User user = new User();
user.setId(21);
user.setName("张三丰");
// 根据主键更新数据
boolean result = userService.update(user);
}

单元测试:

1
2
3
DEBUG [update:145] - ==> Preparing: UPDATE USER SET NAME = ? WHERE id = ?
DEBUG [update:145] - ==> Parameters: 张三丰(String), 21(Integer)
DEBUG [update:145] - <== Updates: 1

根据条件更新

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void testUpdate() {
User user = new User();
// 期望更新用户的薪资
user.setSalary(9000F);
// 条件对象
UserCriteria criteria = new UserCriteria();
// 姓名等于张三丰的用户
criteria.setName(Value.eq("张三丰"));
// 根据条件更新数据
int result = userService.update(user, criteria);
}

单元测试:

1
2
3
DEBUG [update:145] - ==> Preparing: UPDATE USER SET SALARY = ? WHERE name = ?
DEBUG [update:145] - ==> Parameters: 9000.0(Float), 张三丰(String)
DEBUG [update:145] - <== Updates: 1

删除数据

根据主键删除

1
2
3
4
5
@Test
public void testDelete() {
// 根据主键删除数据
boolean result = userService.delete(21);
}

单元测试:

1
2
3
DEBUG [delete:145] - ==> Preparing: DELETE FROM USER WHERE id = ?
DEBUG [delete:145] - ==> Parameters: 21(Integer)
DEBUG [delete:145] - <== Updates: 1

根据条件删除

1
2
3
4
5
6
7
8
9
@Test
public void testDelete() {
// 条件对象
UserCriteria criteria = new UserCriteria();
// 年龄大于 30 的用户
criteria.setAge(Value.gt(30));
// 根据条件删除数据
int result = userService.delete(criteria);
}

单元测试:

1
2
3
DEBUG [delete:145] - ==> Preparing: DELETE FROM USER WHERE age > ?
DEBUG [delete:145] - ==> Parameters: 30(Integer)
DEBUG [delete:145] - <== Updates: 2

查询数据

查询全部

1
2
3
4
5
6
7
@Test
public void testSelect() {
List<User> user = userService.selectAll();
for (User u : user) {
System.out.println(u.getName());
}
}

单元测试:

1
2
3
DEBUG [selectList:145] - ==> Preparing: SELECT * FROM USER
DEBUG [selectList:145] - ==> Parameters:
DEBUG [selectList:145] - <== Total: 18

主键查询

1
2
3
4
@Test
public void testSelect() {
User user = userService.selectOne(8);
}

单元测试:

1
2
3
DEBUG [selectList:145] - ==> Preparing: SELECT * FROM USER WHERE id = ?
DEBUG [selectList:145] - ==> Parameters: 8(Integer)
DEBUG [selectList:145] - <== Total: 1

条件查询唯一记录

1
2
3
4
5
6
7
8
9
10
@Test
public void testSelect() {
UserCriteria criteria = new UserCriteria();
// 年龄大于 20
criteria.setAge(Value.gt(20));
// 用户名为 "用户08"
criteria.setName(Value.eq("用户08"));
// 条件查询, 需确保数据是唯一的
User user = userService.selectOne(criteria);
}

单元测试:

1
2
3
DEBUG [selectList:145] - ==> Preparing: SELECT * FROM USER WHERE age > ? AND name = ?
DEBUG [selectList:145] - ==> Parameters: 20(Integer), 用户08(String)
DEBUG [selectList:145] - <== Total: 1

列表查询

1
2
3
4
5
6
7
8
9
@Test
public void testSelect() {
// 条件对象
UserCriteria criteria = new UserCriteria();
// 年龄小于 25
criteria.setAge(Value.lt(25));
// 查询列表
List<User> users = userService.selectList(criteria);
}

单元测试:

1
2
3
DEBUG [selectList:145] - ==> Preparing: SELECT * FROM USER WHERE age < ?
DEBUG [selectList:145] - ==> Parameters: 25(Integer)
DEBUG [selectList:145] - <== Total: 7

查询条数

1
2
3
4
5
6
7
8
9
@Test
public void testSelect() {
// 条件对象
UserCriteria criteria = new UserCriteria();
// 年龄小于 25
criteria.setAge(Value.lt(25));
// 查询总条数
long counts = userService.selectCount(criteria);
}

单元测试:

1
2
3
DEBUG [selectCount:145] - ==> Preparing: SELECT COUNT(1) FROM USER WHERE age < ?
DEBUG [selectCount:145] - ==> Parameters: 25(Integer)
DEBUG [selectCount:145] - <== Total: 1

分页查询

bootstrap 插件分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
public void testSelect() {
// 分页对象
Pagination pagination = new Pagination();
// 条件对象, 根据情况设置 SQL 条件, 此处不设
UserCriteria criteria = new UserCriteria();
// 分页查询, 无需提供任何参数, 极简分页
pagination = userService.selectPage(criteria, pagination);
// 查询结果总条数
System.out.println(pagination.getTotal());
// 查询的结果集
for (Object row : pagination.getRows()) {
User user = (User) row;
System.out.println(user.getName() + " - ¥" + user.getSalary());
}
}

单元测试:

1
2
3
4
5
6
7
DEBUG [selectCount:145] - ==> Preparing: SELECT COUNT(1) FROM USER
DEBUG [selectCount:145] - ==> Parameters:
DEBUG [selectCount:145] - <== Total: 1
DEBUG [selectList:145] - ==> Preparing: SELECT * FROM USER LIMIT ?, ?
DEBUG [selectList:145] - ==> Parameters: 0(Integer), 10(Integer)
DEBUG [selectList:145] - <== Total: 10

bootstrap 插件分页 Pagination 参数说明表:

参数 是否必须 描述
rows 分页结果集合, 返回字段, 无需设值
total 查询结果总条数, 返回字段, 无需设值
limit 每页显示的条数, 默认 10
offset 查询的起始索引值, 默认 0
sort 排序字段的名称
order 排序的关键字
search 搜索的关键字
field 搜索字段名称, bootstrap 分页插件不发送此参数, 如果有需要, 需手工设置, 建议不使用此参数

普通分页

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
@Test
public void testSelect() {
// 分页对象
Pagination pagination = new Pagination();
// 设置第一页, 普通分页必设
pagination.setPage(1);
// 条件对象
UserCriteria criteria = new UserCriteria();
// 薪资升序排序
criteria.setSalary(Value.orderBy(OrderBy.ASC));
// 薪资相同则按年龄升序排序
criteria.setAge(Value.orderBy(OrderBy.ASC));
// 分页查询, 无需提供任何参数, 极简分页
pagination = userService.selectPage(criteria, pagination);
// 查询结果总条数
System.out.println("查询结果总条数: " + pagination.getTotal());
// 查询结果总页数
System.out.println("查询结果总页数: " + pagination.getPages());
// 上一页的页码
System.out.println("上一页的页码: " + pagination.getPrev());
// 下一页的页码
System.out.println("下一页的页码: " + pagination.getNext());
// 查询的结果集
for (Object row : pagination.getRows()) {
User user = (User) row;
System.out.println(user.getName() + " " + user.getAge() + " - ¥" + user.getSalary());
}
}

单元测试:

1
2
3
4
5
6
7
DEBUG [selectCount:145] - ==> Preparing: SELECT COUNT(1) FROM USER
DEBUG [selectCount:145] - ==> Parameters:
DEBUG [selectCount:145] - <== Total: 1
DEBUG [selectList:145] - ==> Preparing: SELECT * FROM USER ORDER BY salary ASC , age ASC LIMIT ?, ?
DEBUG [selectList:145] - ==> Parameters: 0(Integer), 10(Integer)
DEBUG [selectList:145] - <== Total: 10

bootstrap 插件分页 Pagination 参数说明表:

参数 是否必须 描述
rows 分页结果集合, 返回字段, 无需设值
total 查询结果总条数, 返回字段, 无需设值
limit 每页显示的条数, 默认 10
offset 查询的起始索引值, 默认 0
sort 排序字段的名称
order 排序的关键字
search 搜索的关键字
field 搜索字段名称
page 当前请求的页码, 页码从 1 开始
prev 上一页的页码, 返回字段, 无需设值
next 下一页的页码, 返回字段, 无需设值
pages 查询结果总页数, 返回字段, 无需设值

逻辑操作

多个 Criterion 条件默认是 AND 逻辑:

1
2
3
4
5
6
7
8
9
10
11
@Test
public void testSelect() {
// 条件对象
UserCriteria criteria = new UserCriteria();
// 年龄小于 28
criteria.setAge(Value.lt(28));
// 薪资高于 8000
criteria.setSalary(Value.gt(8000));
// 查询结果
List<User> users = userService.selectList(criteria);
}

单元测试:

1
2
3
DEBUG [selectList:145] - ==> Preparing: SELECT * FROM USER WHERE age < ? AND salary > ?
DEBUG [selectList:145] - ==> Parameters: 28(Integer), 8000(Integer)
DEBUG [selectList:145] - <== Total: 4

支持简单的 OR 逻辑:

1
2
3
4
5
6
7
8
9
@Test
public void testSelect() {
// 条件对象
UserCriteria criteria = new UserCriteria();
// 年龄小于 28 或 薪资高于 12000
criteria.setAge(Value.lt(28)).or(criteria.setSalary(Value.gt(12000)));
// 查询结果
List<User> users = userService.selectList(criteria);
}

单元测试:

1
2
3
DEBUG [selectList:145] - ==> Preparing: SELECT * FROM USER WHERE age < ? OR salary > ?
DEBUG [selectList:145] - ==> Parameters: 28(Integer), 12000(Integer)
DEBUG [selectList:145] - <== Total: 15