瑞吉外卖项目学习笔记(四)@TableField(fill = FieldFill.INSERT)公共字段填充、启用/禁用/修改员工信息

瑞吉外卖项目学习笔记(一)准备工作、员工登录功能实现
瑞吉外卖项目学习笔记(二)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接口,并重写insertFillupdateFill方法:
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类的addEmployeeeditEmployee方法,注释关于时间的公共字段设置:
  • 4)重启服务,测试一下创建时间和修改时间是否自动填充:


由上面的截图可以得到两个信息:第一是关于时间的公共字段确实自动填充了,第二是MyMetaObjectHandler类的addEmployeeeditEmployee方法和LoginCheckFilter类的doFilter方法在同一线程。

  • 5)由于在MyMetaObjectHandler类中不能直接获得HttpSession对象(直接注入会报空指针),所以必须用其他方式来获取当前登录员工的ID。我们可以使用ThreadLocal来解决这个问题。

ThreadLocal并不是一个Thread,而是Thread的局部变量 ◦

当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本 ◦ 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本 ◦

ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。

这样分析过后,解决上述问题的思路是:在LoginCheckFilterdoFilter方法中获取当前登录员工的ID,并调用ThreadLocalset方法来设置当前线程的局部变量的值(员工ID),然后在MyMetaObjectHandlerinsertFillupdateFill方法中调用ThreadLocalget方法来获得当前线程所对应的局部变量的值(员工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)改造LoginCheckFilterdoFilter方法,在放行之前将员工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)在MyMetaObjectHandlerinsertFillupdateFill方法中从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类的addEmployeeeditEmployee方法,注释关于员工ID的公共字段设置:
  • 10)重启服务,测试一下创建人和修改人是否自动填充:

...

本节完,更多内容查阅:瑞吉外卖项目实战

相关推荐
taoyong00110 分钟前
Java线程核心01-中断线程的理论原理
java·开发语言
Yhame.36 分钟前
Java 集合框架中的 List、ArrayList 和 泛型 实例
java
coding侠客37 分钟前
Spring Boot 多数据源解决方案:dynamic-datasource-spring-boot-starter 的奥秘
java·spring boot·后端
委婉待续42 分钟前
java抽奖系统(八)
java·开发语言·状态模式
覆东流1 小时前
PR基本操作二
学习笔记·pr
weixin_537590451 小时前
《Java编程入门官方教程》第八章练习答案
java·开发语言·servlet
CodeClimb2 小时前
【华为OD-E卷-最左侧冗余覆盖子串 100分(python、java、c++、js、c)】
java·python·华为od
Q_19284999062 小时前
基于Spring Boot的大学就业信息管理系统
java·spring boot·后端
xmh-sxh-13142 小时前
常用数据库类型介绍
java