10-后端Web实战(员工管理)

10-后端Web实战(员工管理)
Smith我们已经完成了员工管理中的列表查询、新增员工的功能,那关于员工管理还有两个功能分别是:修改员工、删除员工。
除了员工管理的功能以外,我们还要完成员工信息统计的功能,包括:员工职位统计、员工性别统计。
所以,今天课程内容包含如下几个部分:
- 删除员工
- 修改员工
- 异常处理
- 员工信息统计
1. 删除员工
1.1 需求
当我们勾选列表前面的复选框,然后点击 “批量删除” 按钮,就可以将这一批次的员工信息删除掉了。也可以只勾选一个复选框,仅删除一个员工信息。
问题:我们需要开发两个功能接口吗?一个删除单个员工,一个删除多个员工
答案:不需要。 只需要开发一个功能接口即可(删除多个员工包含只删除一个员工)
1.2 接口文档
参照资料中提供的接口文档,查看 员工管理 -> 删除员工 接口的描述。
1.3 思路分析
1.4 功能开发
1.4.1 Controller接收参数
在 EmpController 中增加如下方法 delete ,来执行批量删除员工的操作。
方式一:在Controller方法中通过数组来接收
多个参数,默认可以将其封装到一个数组中,需要保证前端传递的参数名 与 方法形参名称保持一致。
1 | /** |
方式二:在Controller方法中通过集合来接收
也可以将其封装到一个List<Integer> 集合中,如果要将其封装到一个集合中,需要在集合前面加上 @RequestParam 注解。
1 | /** |
两种方式,选择其中一种就可以,我们一般推荐选择集合,因为基于集合操作其中的元素会更加方便。
1.4.2 Service
1). 在接口中 EmpService 中定义接口方法 deleteByIds
1 | /** |
2). 在实现类 EmpServiceImpl 中实现接口方法 deleteByIds
在删除员工信息时,既需要删除 emp 表中的员工基本信息,还需要删除 emp_expr 表中员工的工作经历信息
1 |
|
由于删除员工信息,既要删除员工基本信息,又要删除工作经历信息,操作多次数据库的删除,所以需要进行事务控制。
1.4.3 Mapper
1). 在 EmpMapper 接口中增加 deleteByIds 方法实现批量删除员工基本信息
1 | /** |
2). 在 EmpMapper.xml 配置文件中, 配置对应的SQL语句
1 | <!--批量删除员工信息--> |
3). 在 EmpExprMapper 接口中增加 deleteByEmpIds 方法实现根据员工ID批量删除员工的工作经历信息
1 | /** |
4). 在 EmpExprMapper.xml 配置文件中, 配置对应的SQL语句
1 | <!--根据员工的ID批量删除工作经历信息--> |
1.5 功能测试
功能开发完成后,重启项目工程,打开 Apifox,发起DELETE请求:
控制台SQL语句:
1.6 前后端联调
打开浏览器,测试后端功能接口:
2. 修改员工
在进行修改员工信息的时候,我们首先先要根据员工的ID查询员工的详细信息用于页面回显展示,然后用户修改员工数据之后,点击保存按钮,就可以将修改的数据提交到服务端,保存到数据库。 具体操作为:
1. 根据ID查询员工信息
2.保存修改的员工信息
2.1 查询回显
2.1.1 接口描述
参照资料中提供的接口文档,查看 员工管理 -> 根据ID查询 接口的描述。
2.1.2 思路
在查询回显时,既需要查询出员工的基本信息,又需要查询出该员工的工作经历信息。
我们可以先通过一条SQL语句,查询出指定员工的基本信息,及其员工的工作经历信息。SQL如下:
1 | select e.*, |
具体的实现思路如下:
2.1.3 代码实现
1). EmpController 添加 getInfo 用来根据ID查询员工数据,用于页面回显
1 | /** |
2). EmpService 接口中增加 getInfo 方法
1 | /** |
3). EmpServiceImpl 实现类中实现 `getInfo` 方法
1 |
|
4). EmpMapper 接口中增加 getById 方法
1 | /** |
5). EmpMapper.xml 配置文件中定义对应的SQL
1 | <!--自定义结果集ResultMap--> |
在这种一对多的查询中,我们要想成功的封装的结果,需要手动的基于 <resultMap> 来进行封装结果。
Mybatis中封装查询结果,什么时候用 resultType,什么时候用resultMap ?
如果查询返回的字段名与实体的属性名可以直接对应上,用resultType 。
如果查询返回的字段名与实体的属性名对应不上,或实体属性比较复杂,可以通过resultMap手动封装 。
2.1.4 Apifox测试
重新启动服务,基于Apifox进行接口测试。
2.1.5 前后端联调测试
打开浏览器,进行前后端联调测试。
2.2 修改员工
查询回显之后,就可以在页面上修改员工的信息了。
当用户修改完数据之后,点击保存按钮,就需要将数据提交到服务端,然后服务端需要将修改后的数据更新到数据库中 。
而此次更新的时候,既需要更新员工的基本信息; 又需要更新员工的工作经历信息 。
2.2.1 接口文档
参照资料中提供的接口文档,查看 员工管理 -> 修改员工接口的描述。
2.2.2 实现思路
2.2.3 代码实现
1). EmpController 增加 update 方法接收请求参数,响应数据
1 | /** |
2). EmpService 接口增加 update 方法
1 | /** |
3). EmpServiceImpl实现类实现 update 方法
1 |
|
4). EmpMapper 接口中增加 updateById 方法
1 | /** |
5). EmpMapper.xml 配置文件中定义对应的SQL语句,基于动态SQL更新员工信息
1 | <!--根据ID更新员工信息--> |
2.2.4 Apifox测试
重新启动服务,打开 Apifox 进行接口测试。
2.2.5 前后端联调
点击保存之后,查看更新后的数据。
3. 异常处理
3.1 问题分析
当我们在修改部门数据的时候,如果输入一个在数据库表中已经存在的手机号,点击保存按钮之后,前端提示了错误信息,但是返回的结果并不是统一的响应结果,而是框架默认返回的错误结果 。
状态码为500,表示服务器端异常,我们打开idea,来看一下,服务器端出了什么问题。
上述错误信息的含义是,emp员工表的phone手机号字段的值重复了,因为在数据库表emp中已经有了13309090027这个手机号了,我们之前设计这张表时,为phone字段建议了唯一约束,所以该字段的值是不能重复的。
而当我们再将该员工的手机号也设置为 13309090027,就违反了唯一约束,此时就会报错。
我们来看一下出现异常之后,最终服务端给前端响应回来的数据长什么样。
响应回来的数据是一个JSON格式的数据。但这种JSON格式的数据还是我们开发规范当中所提到的统一响应结果Result吗?显然并不是。由于返回的数据不符合开发规范,所以前端并不能解析出响应的JSON数据 。
接下来我们需要思考的是出现异常之后,当前案例项目的异常是怎么处理的? 答案:没有做任何的异常处理
当我们没有做任何的异常处理时,我们三层架构处理异常的方案:
- Mapper接口在操作数据库的时候出错了,此时异常会往上抛(谁调用Mapper就抛给谁),会抛给service。
- service 中也存在异常了,会抛给controller。
- 而在controller当中,我们也没有做任何的异常处理,所以最终异常会再往上抛。最终抛给框架之后,框架就会返回一个JSON格式的数据,里面封装的就是错误的信息,但是框架返回的JSON格式的数据并不符合我们的开发规范。
3.2 解决方案
那么在三层构架项目中,出现了异常,该如何处理?
- 方案一:在所有Controller的所有方法中进行try…catch处理
缺点:代码臃肿(不推荐)
- 方案二:全局异常处理器
好处:简单、优雅(推荐)
3.3 全局异常处理器
我们该怎么样定义全局异常处理器?
定义全局异常处理器非常简单,就是定义一个类,在类上加上一个注解@RestControllerAdvice,加上这个注解就代表我们定义了一个全局异常处理器。
在全局异常处理器当中,需要定义一个方法来捕获异常,在这个方法上需要加上注解@ExceptionHandler。通过@ExceptionHandler注解当中的value属性来指定我们要捕获的是哪一类型的异常。
1 |
|
@RestControllerAdvice = @ControllerAdvice + @ResponseBody
处理异常的方法返回值会转换为json后再响应给前端
重新启动SpringBoot服务,打开浏览器,再来测试一下 修改员工 这个操作,我们依然设置已存在的 13309090027这个手机号:
此时,我们可以看到,出现异常之后,异常已经被全局异常处理器捕获了。然后返回的错误信息,被前端程序正常解析,然后提示出了对应的错误提示信息。
以上就是全局异常处理器的使用,主要涉及到两个注解:
@RestControllerAdvice //表示当前类为全局异常处理器
@ExceptionHandler //指定可以捕获哪种类型的异常进行处理
4. 员工信息统计
员工管理的增删改查功能我们已开发完成,接下来,我们再来完成员工信息统计的接口开发。 对于这些图形报表的开发,其实呢,都是基于现成的一些图形报表的组件开发的,比如:Echarts、HighCharts等。
而报表的制作,主要是前端人员开发,引入对应的组件(比如:ECharts)即可。 服务端开发人员仅为其提供数据即可。
官网: https://echarts.apache.org/zh/index.html
4.1 职位统计
4.1.1 需求
对于这类的图形报表,服务端要做的,就是为其提供数据即可。 我们可以通过官方的示例,看到提供的数据其实就是X轴展示的信息,和对应的数据。
4.1.2 接口描述
参照资料中提供的接口文档,查看 数据统计 -> 员工职位统计 接口的描述。
4.1.3 代码实现
1). 定义封装结果对象JobOption
在 com.itheima.pojo 包中定义实体类 JobOption
1 | package com.itheima.pojo; |
1). 定义ReportController,并添加方法。
1 |
|
2). 定义ReportService接口,并添加接口方法。
1 | public interface ReportService { |
3). 定义ReportServiceImpl实现类,并实现方法
1 |
|
4). 定义EmpMapper 接口
统计的是员工的信息,所以需要操作的是员工表。 所以代码我们就写在 EmpMapper 接口中即可。
1 | /** |
如果查询的记录往Map中封装,可以通过@MapKey注解指定返回的map中的唯一标识是那个字段。【也可以不指定】
5). 定义EmpMapper.xml
1 | <!-- 统计各个职位的员工人数 --> |
case流程控制函数:
语法一:case when cond1 then res1 [ when cond2 then res2 ] else res end ;
含义:如果 cond1 成立, 取 res1。 如果 cond2 成立,取 res2。 如果前面的条件都不成立,则取 res。
语法二(仅适用于等值匹配):case expr when val1 then res1 [ when val2 then res2 ] else res end ;
含义:如果 expr 的值为 val1 , 取 res1。 如果 expr 的值为 val2 ,取 res2。 如果前面的条件都不成立,则取 res。
4.1.4 Apifox测试
重新启动服务,打开Apifox进行测试。
4.1.5 联调测试
4.2 性别统计
4.2.1 需求
对于这类的图形报表,服务端要做的,就是为其提供数据即可。 我们可以通过官方的示例,看到提供的数据就是一个json格式的数据。
4.2.2 接口描述
参照资料中提供的接口文档,查看 数据统计 -> 员工性别统计接口的描述。
4.2.3 代码实现
1). 在ReportController,添加方法。
1 | /** |
2). 在ReportService接口,添加接口方法。
1 | /** |
3). 在ReportServiceImpl实现类,实现方法
1 |
|
4). 定义EmpMapper 接口
统计的是员工的信息,所以需要操作的是员工表。 所以代码我们就写在 EmpMapper 接口中即可。
1 | /** |
5). 定义EmpMapper.xml
1 | <!-- 统计员工的性别信息 --> |
if函数语法:
if(条件, 条件为true取值, 条件为false取值)ifnull函数语法:
ifnull(expr, val1)如果expr不为null,取自身,否则取val1









































