SpringBoot&Mybatis综合案例
SpringBoot&Mybatis综合案例
SmithSpringBootWeb案例
前面我们已经讲解了Web前端开发的基础知识,也讲解了Web后端开发的基础(HTTP协议、请求响应),并且也讲解了数据库MySQL,以及通过Mybatis框架如何来完成数据库的基本操作。 那接下来,我们就通过一个案例,来将前端开发、后端开发、数据库整合起来。
而这个案例呢,就是我们前面提到的Tlias智能学习辅助系统。

在这个案例中,前端开发人员已经将前端工程开发完毕了。 我们需要做的,就是参考接口文档完成后端功能的开发,然后结合前端工程进行联调测试即可。
那今天我们的主要内容如下:
- 准备工作
- 部门管理
- 员工管理
1. 准备工作
1.1 需求
1). 部门管理
部门管理功能开发,包括:
- 查询部门列表
- 删除部门
- 新增部门
- 修改部门
2). 员工管理
员工管理功能开发,包括:
- 查询员工列表(分页、条件)
- 删除员工
- 新增员工
- 修改员工
1.2 环境搭建
1). 创建一个SpringBoot工程,选择引入对应的起步依赖(web、mybatis、mysql驱动、lombok)

并在创建好的项目中,准备好包结构:

2). 准备数据库表,及对应的实体类
- SQL(导入MySQL数据库中)
1 | -- 部门管理 |
- 实体类 (放在项目的com.itxg.pojo包下)
1 | import lombok.AllArgsConstructor; |
1 | import lombok.AllArgsConstructor; |
3). 在application.properties中引入数据库连接信息(复制过来即可)
1 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver |
4). 准备对应的Mapper接口、Service、Controller的基础代码
①. DeptMapper
1 | import org.apache.ibatis.annotations.Mapper; |
②. EmpMapper
1 | import org.apache.ibatis.annotations.Mapper; |
③. DeptService / DeptServiceImpl
1 | public interface DeptService { |
1 | import lombok.extern.slf4j.Slf4j; |
④. EmpService / EmpServiceImpl
1 | public interface EmpService { |
1 | import lombok.extern.slf4j.Slf4j; |
⑤. DeptController
1 | import org.springframework.web.bind.annotation.*; |
⑥. EmpController
1 | import org.springframework.web.bind.annotation.*; |
最终的结构如下:
1.3 开发规范
1.3.1 REST风格
当前案例,我们基于当前最为主流的前后端分离模式进行开发。

在前后端分离的开发模式中,前后端开发人员都需要根据提前定义好的接口文档,来进行前后端功能的开发,而在前后端进行交互的时候,我们需要基于当前主流的REST风格的API接口进行交互。
那么什么是REST风格呢?
- REST(Representational State Transfer),表现形式状态转换,它是一种软件架构风格。
原来我们定义URL风格如下:

原始的传统URL呢,定义比较复杂,而且将资源的访问行为对外暴露出来了。
如果是基于REST风格:

在REST风格的URL中,我们通过四种请求方式,来操作数据的增删改查。
- GET : 查询
- POST :新增
- PUT :修改
- DELETE :删除
我们看到如果是基于REST风格,定义URL,URL将会更加简洁、更加规范、更加优雅。
注意事项:
- 上述行为是风格,是约定方式,约定不是规范,可以打破,所以称为 REST风格,而不是REST规范。 - 描述模块的功能通常使用复数,也就是加s的格式来描述,表示此类资源,而非单个资源。如:users、emps、books…
添加和新增不需要
1.3.2 统一响应结果
前后端工程在进行交互时,使用统一响应结果 Result。
1 |
|
1.3.3 开发流程
我们在进行功能开发时,都是根据如下流程进行:

查询页面原型明确需求
阅读接口文档(已提供)
思路分析
接口开发:就是开发后台的业务功能,一个业务功能,我们称为一个接口。
接口测试:功能开发完毕后,先通过Postman进行接口测试,测试通过后,和前端进行联调测试。
前后端联调测试:和前端开发人员开发好的前端工程一起测试。
2. 部门管理
2.1 查询部门
2.1.1 需求
通过页面原型以及需求描述,我们可以看到,部门查询,是不需要考虑分页操作的。
2.1.2 开发
然后我们就可以查看资料中提供的,查询部门列表的接口文档。
请求路径:/depts
请求方式:GET
接口描述:该接口用于部门列表数据查询
然后来开发对应的功能:

1). DeptMapper
1 |
|
2). DeptService / DeptServiceImpl
1 | public interface DeptService { |
1 |
|
3). DeptController
1 |
|
2.1.3 测试
功能开发完成后,我们就可以启动项目,然后打开postman。发起GET请求,访问 :http://localhost:8080/depts
2.2 删除部门
2.2.1 需求
点击部门列表后面操作栏的 “删除” 按钮,就可以删除该部门信息。 此时,前端只需要给服务端传递一个ID参数就可以了。 我们从接口文档中也可以看得出来。
2.2.2 开发
然后我们就可以查看资料中提供的,删除部门的接口文档。
请求路径:/depts/{id}
请求方式:DELETE
接口描述:该接口用于根据ID删除部门数据
然后来开发对应的功能:

1). DeptMapper
1 | //删除部门 |
2). DeptService / DeptServiceImpl
DeptService
1 | /** |
DeptServiceImpl
1 |
|
3). DeptController
1 |
|
2.2.3 测试
功能开发完成后,我们就可以启动项目,然后打开postman。发起DELETE请求,访问 :http://localhost:8080/depts/5
2.3 新增部门
2.3.1 需求
点击 “新增部门” 按钮,弹出新增部门对话框,输入部门名称,点击 “保存” ,将部门信息保存到数据库。
2.3.2 开发
然后我们就可以查看资料中提供的,新增部门的接口文档。
请求路径:/depts
请求方式:POST
接口描述:该接口用于添加部门数据
然后来开发对应的功能:

1). DeptMapper
1 | //新增部门 |
2). DeptService / DeptServiceImpl
DeptService:
1 | /** |
DeptServiceImpl:
1 |
|
BeanUtils.copyProperties(deptDto, dept); 是 Spring 框架提供的一个工具方法,作用是把 源对象 的属性值复制到 目标对象 的对应属性上。
1 | Dept dept = new Dept(); // 1. 新建空的实体对象 |
1 | BeanUtils.copyProperties(source, target); |
source:数据来源对象,这里是deptDto(前端的参数 DTO)target:目标对象,这里是dept(即将插入数据库的实体)
需要注意的细节
- 属性名必须一致(区分大小写),否则不会拷贝。
- 类型要兼容(比如
String到String,Integer到int等),不匹配的属性会被跳过且不报错。 - 它是浅拷贝:如果属性是引用类型(如
List),只拷贝引用,两个对象会指向同一个集合,修改一个会相互影响。 - BeanUtils 来源:这里用的是
org.springframework.beans.BeanUtils(Spring 的),它比 Apache 的BeanUtils性能稍好(参数顺序也不同,Spring 是(source, target))。
3). DeptController
1 |
|
2.3.3 测试
功能开发完成后,我们就可以启动项目,然后打开postman。发起POST请求,访问 :http://localhost:8080/depts,然后在请求体中传递json格式的参数。

2.4 请求路径
前端我们开发的部门信息的列表查询、删除、新增功能接口,我们会看到,在方法上面加的注解中指定的请求路径中 ,都包含了 /depts ,重复了。我们可以考虑将其抽取到类上,可以在类上加一个注解@RequestMapping,然后声明属性 value,来指定请求路径 /depts。像下面这样:
那如果类上添加了@RequestMapping注解,在方法上也添加了@RequestMapping注解(或者其衍生注解 @GetMapping、@PostMapping、@DeleteMapping、@PutMapping),此时在进行请求访问时,完整的请求路径应该是 ==类上的@RequestMapping的value属性 + 方法上的@RequestMapping的value属性。==
3. 员工管理
3.1 分页查询
3.1.1 需求
我们之前做的 查询所有 功能中将数据库中所有的数据查询出来并展示到页面上,试想如果数据库中的数据有很多(假设有十几万条)的时候,将数据全部展示出来肯定不现实,那如何解决这个问题呢?几乎所有的网站都会使用分页解决这个问题。每次只展示一页的数据,比如一页展示10条数据,如果还想看其他的数据,可以通过点击页码进行查询。
意思是每次打开网页只显示第一页,其他的页面需要查询
通过提供的页面原型及需求可以看出,由于员工数据比较多,在展示的时候,需要进行分页展示。
3.1.2 分析
3.1.2.1 介绍
分页查询也是从数据库进行查询的,所以我们要分页对应的SQL语句应该怎么写。分页查询使用 LIMIT 关键字,格式为:==LIMIT 开始索引 每页显示的条数==。
以后前端页面在发送请求携带参数时,它并不明确开始索引是什么,但是它知道查询第几页。
所以 开始索引 需要在后端进行计算,计算的公式是 :==开始索引 = (当前页码 - 1)* 每页显示条数==
比如查询第1页的数据的 SQL 语句是:
1 | select * from emp limit 0,10; |
查询第2页的数据的 SQL 语句是:
1 | select * from emp limit 10,10; |
查询第3页的数据的 SQL 语句是:
1 | select * from emp limit 20,10; |
3.1.2.2 参数传递
分页查询功能时候比较复杂的,所以我们要先分析清楚以下两个问题:
前端在请求服务端时,传递的参数:
当前页码 page
每页展示记录数 pageSize
**后端需要响应什么数据给前端: **
上面的页面原型是分页查询页面展示的效果,从上面我们可以看出需要响应以下两份数据
- 当前页需要展示的数据。我们在后端一般会存储到 List 集合中
- 总共记录数。在上图页面中需要展示总的记录数,所以这部分数据也需要。总的页码 elementUI 的分页组件会自动计算,我们不需要关心。
而这两部分需要封装到 PageBean 对象中,并将该对象转换为 json 格式的数据响应回给浏览器

3.1.2.3 PageBean定义
1 |
|
3.1.3 开发
后端需要响应总记录数 和 当前页的数据 两部分数据给前端,所以在 EmpMapper 接口中需要定义两个方法:
- page() :查询当前页的数据的方法
- count() :查询总记录的方法
整体流程如下:

1). EmpMapper
1 |
|
2). EmpService / EmpServiceImpl
EmpService
1 | public interface EmpService { |
EmpServiceImpl
1 |
|
3). EmpController
1 |
|
@RequestParam :
可以通过该注解的defaultValue 属性来设置参数的默认值。
3.1.4 测试
功能开发完成后,我们就可以启动项目,然后打开postman。发起GET请求,访问 :http://localhost:8080/emps?page=1&pageSize=5

3.1.5 思考
我们通过上述方式已经实现了分页查询的需求,在数据库访问层 Mapper 接口中,我们编写两个方法:
- 获取总记录数
- 获取当前页的结果列表
如果我们通过这种方式来实现,也就意味着,我们所有的业务模块,只要涉及到分页,都需要指定上述的操作,步骤是固定的,而且代码比较繁琐。
由于步骤是固定的,所以在Mybatis框架中,已经有组织将其封装为了一个简单易用的插件。从而来大大简化分页的操作。
3.2 分页插件
3.2.1 介绍
PageHelper 是Mybatis的一款功能强大、方便易用的分页插件,支持任何形式的单标、多表的分页查询。

如果使用了PageHelper分页插件进行分页,那我们是无需再Mapper这层来手动分页的。 Mapper这一层,我们进行正常的列表查询即可。我们需要在Service层中,调用Mapper的方法之前设置分页参数,在调用Mapper方法执行查询之后,解析分页结果,并将结果封装到PageBean对象中,返回。
流程如下:

接下来呢,我们就可以将上面手动实现的分页代码注释掉。 通过PageHelper分页插件,来实现分页操作。
3.2.2 分页实现
1). pom.xml 引入依赖
1 | <dependency> |
2). EmpMapper
1 |
|
3). EmpServiceImpl
1 |
|
3.2.3 测试
功能开发完成后,我们就可以启动项目,然后打开postman。发起GET请求,访问 :http://localhost:8080/emps?page=1&pageSize=5

3.3 分页查询(条件)
3.3.1 需求
通过员工管理的页面原型我们可以看到,员工列表页面的查询,不仅仅需要考虑分页,还需要考虑查询条件。 分页查询我们已经实现了,接下来,我们需要考虑在分页查询的基础上,再加上查询条件。
我们看到页面原型及需求中描述,搜索栏的搜索条件有三个,分别是:
- 姓名:模糊匹配
- 性别:精确匹配
- 入职日期:范围匹配
而且上述的三个条件,都是可以传递,也可以不传递的,也就是动态的。 想到这儿,大家马上就想起来了,我们前面在Mybatis中讲解的动态SQL 。
3.3.2 开发
然后我们就可以查看资料中提供的,条件分页查询员工的接口文档。
请求路径:/emps
请求方式:GET
接口描述:该接口用于员工列表数据的条件分页查询
请求参数:
参数名称 是否必须 示例 备注 name 否 张 姓名 gender 否 1 性别 , 1 男 , 2 女 begin 否 2010-01-01 范围匹配的开始时间(入职日期) end 否 2020-01-01 范围匹配的结束时间(入职日期) page 是 1 分页查询的页码,如果未指定,默认为1 pageSize 是 10 分页查询的每页记录数,如果未指定,默认为10
然后来开发对应的功能:

需要在原来分页查询的代码基础上进行改造。
1). EmpMapper
EmpMapper接口
1 |
|
EmpMapper.xml
1 |
|
2). EmpService / EmpServiceImpl
EmpService
1 | public interface EmpService { |
EmpServiceImpl
1 |
|
3). EmpController
1 |
|
3.3.3 测试
功能开发完成后,我们就可以启动项目,然后打开postman。发起GET请求,访问 :http://localhost:8080/emps?page=1&pageSize=5

3.4 删除员工
3.4.1 需求

当我们勾选列表前面的复选框,然后点击 “批量删除” 按钮,就可以将这一批次的员工信息删除掉了。
3.4.2 开发
然后我们就可以查看资料中提供的,删除员工的接口文档。
请求路径:/emps/{ids}
请求方式:DELETE
接口描述:该接口用于批量删除员工的数据信息
请求样例:/depts/1,2,3
从接口文档中,我们可以看出在路径参数中,传递过来了多个id,在springboot中,我们可以将这组id值封装到一个集合中,然后在Mybatis中,通过动态SQL来完成批量删除操作。
对应的流程为:

1). EmpMapper
EmpMapper接口
1 | //批量删除 |
EmpMapper.xml
1 | <select id="delete"> |
2). EmpService / EmpServiceImpl
EmpService
1 | /** |
EmpServiceImpl
1 |
|
3). EmpController
通过接口文档我们可以看出,这一组id是通过路径参数传递过来的,接收路径参数,需要在集合前面加上 @PathVariable
1 | //批量删除 |
3.4.3 测试
功能开发完成后,我们就可以启动项目,然后打开postman。发起DELETE请求,访问 :http://localhost:8080/emps/15,16,17

3.4 新增员工
3.4.1 需求
在新增用户时,我们需要保存用户的基本信息,并且还需要上传的员工的图片,目前我们先完成第一步操作,保存用户的基本信息。
我们可以看一下接口文档,参照接口文档,进行功能的开发。
3.4.2 开发
新增员工,最终呢,我们就是需要往数据库表结构中插入数据。具体的流程为:

1). EmpMapper
1 | //保存员工信息 |
2). EmpService / EmpServiceImpl
EmpService
1 | /** |
EmpServiceImpl
1 |
|
3). EmpController
1 | //新增 |
3.4.3 测试
代码编写完毕后,启动服务器,打开Postman发送 POST 请求,请求连接:http://localhost:8080/emps

新增员工基本信息,我们已经保存到数据库了。那接下来,我们要来完成的是员工图像的上传。
3.5 修改员工
3.5.1 需求

在进行修改员工信息的时候,我们首先先要根据员工的ID查询员工的信息用于页面回显展示,然后用户修改员工数据之后,点击保存按钮,就可以将修改的数据提交到服务端,保存到数据库。 所以呢,分为两部操作:
- 根据ID查询员工信息
- 保存修改
3.5.2 查询回显
查询回显,就是根据ID查询员工的信息,用于页面回显展示。接下来,我们就需要参考接口文档进行开发:

1). EmpMapper
1 | //根据ID查询员工信息 |
2). EmpService / EmpServiceImpl
EmpService
1 | /** |
EmpServiceImpl
1 |
|
3). EmpController
1 | //根据id查询 |
4). 测试
代码编写完毕后,启动服务器,打开Postman发送 GET 请求,请求连接:http://localhost:8080/emps/1

3.5.3 保存修改
assets/image-20220904221256025.png
当用户修改完数据之后,点击保存按钮,就需要将数据提交到服务端,然后服务端需要将数据保存到数据库中。 具体的执行流程为:

接下来,我们就可以根据接口文档进行功能开发了。
1). EmpMapper
EmpMapper接口
1 | //修改员工信息 |
EmpMapper.xml
1 | <update id="update"> |
2). EmpService / EmpServiceImpl
EmpService
1 | /** |
EmpServiceImpl
1 |
|
3). EmpController
1 | //修改 |
4). 测试











