(五)SpringBoot整合Mybatis通用Mapper

SpringBoot整合Thymeleaf、Mybatis

:tada: :tada: :tada: 这里有丰富的 Spring 框架学习案例

仓库地址:spring-learn
欢迎star、fork,给作者一些鼓励

项目介绍

前面我们学习了 SpringBoot整合Mybatis 基础CRUD,这里我们结合上一篇文章实战CRUD业务。

其实之前我已经写过一个SpringBoot整合Mybatis的案例:传送门

技术选型

后端

  • 基础框架:Spring Boot 2.1.3.RELEASE

  • 持久层框架:Mybatis 1.3.1

  • 模板引擎:Thymeleaf 3.0.11.RELEASE

  • 其他:Druid、PageHelper、通用Mapper

前端

  • 基础框架:ElementUI

  • JavaScript框架:Vue.js

开发环境

  • 语言: JDK1.8

  • IDE: IDEA 2018.3

  • 依赖管理: Maven

  • 数据库: Mysql 5.7.24

写在前面

如上,前端完全依赖Vue.js,这和传统依赖Jquery的前端区别还是蛮大的,使用Vue即要用基于Node.js的前后端分离的开发模式,而本项目中仅仅是在HTML中引入了vue.js,虽然不是完全的前后端分离开发,但项目中我尽量使用Vue.js渲染数据,涉及后端的也仅是用到Thymeleaf的th:replace拼接页面。看下图:

截图

通用Mapper

开源地址:https://github.com/abel533/MyBatis-Spring-Boot

之前学习了 SpringBoot整合MybatisSpringBoot整合JPA 发现两者各有优缺点,个人而言还是喜欢用Mybatis。

那么虽然Mybatis目前提供了一些注解来简化XML的编写,但是仍需要手动写SQL,相比JPA仍麻烦很多,有没有可以像JPA那样调用Java方法自动生成SQL的办法呢?于是就有了框架:通用Mapper

通用Mapper内置了很多API供开发者调用,目的是简化SQL编写。

mapper generator代码生成器

官方文档:传送门

使用该插件可以方便的生成Entity、Mapper interface、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
-- create database springboot_thymeleaf_mybatis charset utf8;

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(255) DEFAULT NULL COMMENT '用户名',
`password` varchar(255) DEFAULT NULL COMMENT '密码',
`age` int(11) DEFAULT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `role`;

CREATE TABLE `role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(255) DEFAULT NULL COMMENT '名称',
`description` varchar(255) DEFAULT NULL COMMENT '描述',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `user_role`;

CREATE TABLE `user_role` (
`user_id` bigint(20) DEFAULT NULL,
`role_id` bigint(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

按照官方文档首先引入依赖:

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
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<!--mapper-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>1.2.4</version>
</dependency>
<!--pagehelper-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
<!-- mapper生成依赖 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>

创建MyMapper.java用于继承tk.mapper(通用Mapper)

1
2
public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {
}

创建配置文件: /resources/generator/generatorConfig.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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>

<context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>

<plugin type="tk.mybatis.mapper.generator.MapperPlugin">
<property name="mappers" value="cn.tycoding.utils.MyMapper"/>
</plugin>

<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/springboot_thymeleaf_mybatis"
userId="root"
password="root">
<property name="nullCatalogMeansCurrent" value="true"/>
</jdbcConnection>

<!-- 生成的entity -->
<javaModelGenerator targetPackage="cn.tycoding.entity" targetProject="spring-boot-thymeleaf-mybatis/src/main/java"/>

<!-- 生成的Mapper XML-->
<sqlMapGenerator targetPackage="mapper" targetProject="spring-boot-thymeleaf-mybatis/src/main/resources"/>

<!-- 生成的Mapper映射类 -->
<javaClientGenerator targetPackage="cn.tycoding.mapper" targetProject="spring-boot-thymeleaf-mybatis/src/main/java"
type="XMLMAPPER"/>

<table tableName="user"></table>
</context>
</generatorConfiguration>

注意

  • 按照官方文档会遇到:Table Configuration scheme.table matched more than one table的错误,因此需要配置<property name="nullCatalogMeansCurrent" value="true"/>博文

  • 按照官方文档配置遇到:The specified target project directory src/main/resources does not exist,要修改所有的targetProject地址加上项目名即可。

生成代码,创建GeneratorDisplay.java

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
public class GeneratorDisplay {

public void generator() throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
ConfigurationParser cp = new ConfigurationParser(warnings);
File configFile = ResourceUtils.getFile("classpath:generator/generatorConfig.xml");
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
for (String warning : warnings) {
System.out.println(warning);
}
}

public static void main(String[] args) throws Exception {
try {
GeneratorDisplay display = new GeneratorDisplay();
display.generator();
} catch (Exception e) {
e.printStackTrace();
}
}
}

注意

使用new File("/path")获取到的仅是项目的根路径地址,用其获取new File("generator/generatorConfig")是not found的,要使用Spring提供的ResourceUtils工具类获取项目静态文件路径。

修改generatorConfig.xml<table>的名称,执行GeneratorDisplay.java就能生成不同的文件:

测试

首先需要配置Spring扫描Mapper接口

方式一: 在Mapper接口上添加@Mapper注解

方式二: 在Application.java启动类上添加@MapperScan()注解扫描所有Mapper接口。注意这里的@MapperScan注解来自tk.mybatis.spring.annotation.MapperScan,用spring的会报错。

user表中新增一条记录:

1
insert into user values (1, 'tycoding', '123', '19');

创建UserMapper.java的测试类UserMapperTest.java:

可以看到,因为UserMapper继承了MyMapper<User>,而MyMapper又继承了Mapper<T>, MySqlMapper<T>。类似Jap中继承JpaRepositoryMapper接口中提供了很多API用于生成SQL,简化SQL编写。

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
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserMapperTest {
private Logger logger = LoggerFactory.getLogger(this.getClass());

@Autowired
private UserMapper userMapper;

@Test
public void findAll() {
List<User> list = userMapper.selectAll();
list.forEach(user -> {
logger.info("user={}", user);
});
}

@Test
public void findById() {
User user = userMapper.selectByPrimaryKey(1L);
logger.info("user={}", user);
}

@Test
public void save() {
User user = new User();
user.setUsername("涂陌");
user.setPassword("123");
user.setAge(20);
userMapper.insert(user);
findAll();
}

@Test
public void update() {
User user = new User();
user.setId(2L);
user.setUsername("小涂陌");
userMapper.updateByPrimaryKey(user);
findAll();
}

@Test
public void delete() {
userMapper.deleteByPrimaryKey(2L);
findAll();
}
}

如上,看到这里,感觉和JPA调用接口的方式很像吧,tk.Mapper能帮我们简化很多SQL的编写,但是复杂的SQL还是需要手动写,这点和JPA一样的。

这里我也只是测试了几个常用的CRUD操作,tk.Mapper提供了很多方法,我们通过方法名就能大概猜到,所以这里不再做更多的测试。


交流

以上仅是个人的见解,可能有些地方是错误的,深知自己的菜鸡技术,欢迎大佬指出。

个人建了一个Java交流群:671017003。 欢迎大佬或是新人入驻一起交流学习Java技术。


联系

If you have some questions after you see this article, you can contact me or you can find some info by clicking these links.

如果你觉得这篇文章帮助到了你,你可以帮作者买一杯果汁表示鼓励