瑞吉外卖项目学习笔记(一)准备工作、员工登录功能实现
瑞吉外卖项目学习笔记(二)Swagger、logback、表单校验和参数打印功能的实现
瑞吉外卖项目学习笔记(三)过滤器实现登录校验、添加员工、分页查询员工信息
文章目录
- [7 修改员工信息](#7 修改员工信息)
-
- [7.1 启用/禁用员工账号](#7.1 启用/禁用员工账号)
-
- [7.1.1 需求梳理](#7.1.1 需求梳理)
- [7.1.2 具体实现](#7.1.2 具体实现)
- [7.2 修改员工基本信息](#7.2 修改员工基本信息)
-
- [7.2.1 需求梳理](#7.2.1 需求梳理)
- [7.2.2 具体实现](#7.2.2 具体实现)
- [7.2.3 公共字段自动填充](#7.2.3 公共字段自动填充)
7 修改员工信息
- 启用/禁用员工账号
- 修改员工基本信息
7.1 启用/禁用员工账号
7.1.1 需求梳理
在"员工管理"页面,在每一行员工信息的"操作"栏,都支持"启用/禁用"员工的操作:
从业务角度来说,禁用员工就是把员工的状态改为"禁用",启用员工就是改为"正常"。只有状态为"正常"的员工可以登录系统。
API文档如下:
接口功能 | 请求方法 | 请求路径 | 请求参数 |
---|---|---|---|
启用/禁用员工 | PUT | /employee/staus | {id: 1, status: 1} |
7.1.2 具体实现
- 1)在
EmployeeController
类中创建修改员工信息方法status
:
java
@ApiOperation("启用/禁用员工")
@PutMapping("/staus")
public BaseResult staus(@RequestBody @Validated(EditStatus.class) EmployeeQuery employeeQuery) {
return employeeService.editEmployee(employeeQuery);
}
- 2)在Service层具体实现业务逻辑:
java
@Override
public BaseResult editEmployee(EmployeeQuery employeeQuery) {
// 1 根据ID查询员工信息
Employee exEmployee = getById(employeeQuery.getId());
if(exEmployee == null) {
return BaseResult.error(ErrorCode.EMPLOYEE_NOT_EXIST);
}
Employee newEmployee = new Employee();
newEmployee.setId(exEmployee.getId());
newEmployee.setUpdateTime(LocalDateTime.now());
newEmployee.setUpdateUser((Long)session.getAttribute("login_employee"));
// 2 判断员工状态是否修改
if(!exEmployee.getStatus().equals(employeeQuery.getStatus())) {
newEmployee.setStatus(employeeQuery.getStatus());
}
// 3 修改员工信息
updateById(newEmployee);
return BaseResult.success();
}
- 3)重启服务,测试启用/禁用员工功能:
7.2 修改员工基本信息
7.2.1 需求梳理
在"员工管理"页面,在每一行员工信息的"操作"栏,都支持"编辑"员工的操作:
点击"编辑"按钮,页面跳转到修改信息页面,首先需要根据员工ID查询员工信息进行数据回显;用户修改完员工信息后,点击"保存"按钮确认修改。
API文档如下:
接口功能 | 请求方法 | 请求路径 | 请求参数 |
---|---|---|---|
根据ID查询员工信息 | GET | /employee/{id} | |
根据ID修改员工信息 | PUT | /employee/edit | {id: 1, username: "xxx", name: "xxx", phone: "xxx", sex: "xxx", idNumber: "xxx"} |
7.2.2 具体实现
- 1)在
EmployeeController
类中创建根据ID查询员工信息的方法get
:
java
@ApiOperation("根据ID查询员工信息")
@GetMapping("/{id}")
public BaseResult<Employee> get(@NotNull(message = "员工ID不能为空") @PathVariable Long id) {
return employeeService.getEmployeeById(id);
}
- 2)在Service层具体实现业务逻辑:
java
@Override
public BaseResult<Employee> getEmployeeById(Long id) {
Employee employee = getById(id);
if(employee == null) {
return BaseResult.error(ErrorCode.EMPLOYEE_NOT_EXIST);
}
return BaseResult.success(employee);
}
- 3)重启服务,测试数据回显功能:
- 4)在
EmployeeController
类中创建根据ID修改员工信息的方法edit
:
java
@ApiOperation("修改员工信息")
@PutMapping("/edit")
public BaseResult edit(@RequestBody @Validated(Edit.class) EmployeeQuery employeeQuery) {
return employeeService.editEmployee(employeeQuery);
}
- 5)和启用/禁用员工一样,调用Service层的
editEmployee
方法,对该方法进行改造:
java
@Override
public BaseResult editEmployee(EmployeeQuery employeeQuery) {
// 1 根据ID查询员工信息
Employee exEmployee = getById(employeeQuery.getId());
if(exEmployee == null) {
return BaseResult.error(ErrorCode.EMPLOYEE_NOT_EXIST);
}
Employee newEmployee = new Employee();
newEmployee.setId(exEmployee.getId());
newEmployee.setUpdateTime(LocalDateTime.now());
newEmployee.setUpdateUser((Long)session.getAttribute("login_employee"));
// 2 判断员工状态是否修改
if(!exEmployee.getStatus().equals(employeeQuery.getStatus())) {
newEmployee.setStatus(employeeQuery.getStatus());
}
// 3 判断用户名是否修改
if(!exEmployee.getUsername().equals(employeeQuery.getUsername())) {
newEmployee.setUsername(employeeQuery.getUsername());
}
// 4 判断姓名是否修改
if(!exEmployee.getName().equals(employeeQuery.getName())) {
newEmployee.setName(employeeQuery.getName());
}
// 5 判断手机号是否修改
if(!exEmployee.getPhone().equals(employeeQuery.getPhone())) {
newEmployee.setPhone(employeeQuery.getPhone());
}
// 6 判断性别是否修改
if(!exEmployee.getSex().equals(employeeQuery.getSex())) {
newEmployee.setSex(employeeQuery.getSex());
}
// 7 判断身份证号码是否修改
if(!exEmployee.getIdNumber().equals(employeeQuery.getIdNumber())) {
newEmployee.setIdNumber(employeeQuery.getIdNumber());
}
// 8 修改员工信息
updateById(newEmployee);
return BaseResult.success();
}
- 6)重启服务,测试修改员工信息功能:
7.2.3 公共字段自动填充
前面我们已经完成了对员工信息的添加与修改,在添加/修改员工信息时,都需要设置创建人、创建时间、修改人、修改时间等字段,这些字段不仅员工表有,在未来的菜品表、分类表等其他表中也拥有这些字段。
所以这些字段属于公共字段。那有没有办法让这些公共字段在一个地方统一管理从而简化开发呢?答案就是使用MybatisPlus提供的公共字段自动填充功能。
- 1)在实体类
Employee
的属性上方加入@TableFiled
注解,指定自动填充的策略:
java
// com.itweid.takeout.entity.Employee
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@ApiModelProperty(value = "创建人")
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@ApiModelProperty(value = "修改人")
@TableField(fill = FieldFill.INSERT)
private Long updateUser;
- 2)编写元数据对象处理器,在该处理器中统一对公共字段进行赋值。该处理需要实现
MetaObjectHandler
接口,并重写insertFill
、updateFill
方法:
java
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
LocalDateTime now = LocalDateTime.now();
metaObject.setValue("createTime", now);
metaObject.setValue("updateTime", now);
log.info("insert fill createTime and updateTime = {}", now);
}
@Override
public void updateFill(MetaObject metaObject) {
LocalDateTime now = LocalDateTime.now();
metaObject.setValue("updateTime", now);
log.info("update fill updateTime = {}", now);
}
}
- 3)改造
EmployeeServiceImpl
类的addEmployee
和editEmployee
方法,注释关于时间的公共字段设置:
- 4)重启服务,测试一下创建时间和修改时间是否自动填充:
由上面的截图可以得到两个信息:第一是关于时间的公共字段确实自动填充了,第二是MyMetaObjectHandler
类的addEmployee
和editEmployee
方法和LoginCheckFilter
类的doFilter
方法在同一线程。
- 5)由于在
MyMetaObjectHandler
类中不能直接获得HttpSession
对象(直接注入会报空指针),所以必须用其他方式来获取当前登录员工的ID。我们可以使用ThreadLocal
来解决这个问题。
ThreadLocal并不是一个Thread,而是Thread的局部变量 ◦
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本 ◦ 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本 ◦
ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
这样分析过后,解决上述问题的思路是:在LoginCheckFilter
的doFilter
方法中获取当前登录员工的ID,并调用ThreadLocal
的set
方法来设置当前线程的局部变量的值(员工ID),然后在MyMetaObjectHandler
的insertFill
、updateFill
方法中调用ThreadLocal
的get
方法来获得当前线程所对应的局部变量的值(员工ID)。
- 6)创建
BaseContext
类,用于保存ThreadLocal
对象
java
public class BaseContext {
private static final ThreadLocal<Long> employeeIdThreadLocal = new ThreadLocal<>();
public static void setEmployeeId(Long employeeId) {
employeeIdThreadLocal.set(employeeId);
}
public static Long getEmployeeId() {
return employeeIdThreadLocal.get();
}
}
- 7)改造
LoginCheckFilter
的doFilter
方法,在放行之前将员工ID存放到ThreadLocal
中
java
// com.itweid.takeout.filter.LoginCheckFilter
// 从session中获取员工信息以判断登录状态,已登录则放行
Object employeeId = request.getSession().getAttribute("login_employee");
if(employeeId != null) {
log.info("已登录,员工ID为{}", employeeId);
// 将员工ID存放到ThreadLocal中
BaseContext.setEmployeeId((Long) employeeId);
filterChain.doFilter(request, response);
return;
}
- 8)在
MyMetaObjectHandler
的insertFill
、updateFill
方法中从ThreadLocal
中获取员工ID
java
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
private HttpSession session;
@Override
public void insertFill(MetaObject metaObject) {
LocalDateTime now = LocalDateTime.now();
metaObject.setValue("createTime", now);
metaObject.setValue("updateTime", now);
log.info("insert fill createTime and updateTime = {}", now);
Long employeeId = BaseContext.getEmployeeId();
metaObject.setValue("createUser", employeeId);
metaObject.setValue("updateUser", employeeId);
log.info("insert fill createUser and updateUser = {}", employeeId);
}
@Override
public void updateFill(MetaObject metaObject) {
LocalDateTime now = LocalDateTime.now();
metaObject.setValue("updateTime", now);
log.info("update fill updateTime = {}", now);
Long employeeId = BaseContext.getEmployeeId();
metaObject.setValue("updateUser", employeeId);
log.info("insert fill and updateUser = {}", employeeId);
}
}
- 9)改造
EmployeeServiceImpl
类的addEmployee
和editEmployee
方法,注释关于员工ID的公共字段设置:
- 10)重启服务,测试一下创建人和修改人是否自动填充:
...
本节完,更多内容查阅:瑞吉外卖项目实战