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

瑞吉外卖项目学习笔记(一)准备工作、员工登录功能实现
瑞吉外卖项目学习笔记(二)Swagger、logback、表单校验和参数打印功能的实现
瑞吉外卖项目学习笔记(三)过滤器实现登录校验、添加员工、分页查询员工信息

文章目录

  • 7 修改员工信息
    • 7.1 启用/禁用员工账号
      • 7.1.1 需求梳理
      • 7.1.2 具体实现
    • 7.2 修改员工基本信息
      • 7.2.1 需求梳理
      • 7.2.2 具体实现
      • 7.2.3 公共字段自动填充

7 修改员工信息

  • 启用/禁用员工账号
  • 修改员工基本信息

7.1 启用/禁用员工账号

7.1.1 需求梳理

在“员工管理”页面,在每一行员工信息的“操作”栏,都支持“启用/禁用”员工的操作:

从业务角度来说,禁用员工就是把员工的状态改为“禁用”,启用员工就是改为“正常”。只有状态为“正常”的员工可以登录系统。

API文档如下:

接口功能请求方法请求路径请求参数
启用/禁用员工PUT/employee/staus{id: 1, status: 1}

7.1.2 具体实现

  • 1)在EmployeeController类中创建修改员工信息方法status
@ApiOperation("启用/禁用员工")
@PutMapping("/staus")
public BaseResult staus(@RequestBody @Validated(EditStatus.class) EmployeeQuery employeeQuery) {
    return employeeService.editEmployee(employeeQuery);
}
  • 2)在Service层具体实现业务逻辑:
@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
@ApiOperation("根据ID查询员工信息")
@GetMapping("/{id}")
public BaseResult<Employee> get(@NotNull(message = "员工ID不能为空") @PathVariable Long id) {
    return employeeService.getEmployeeById(id);
}
  • 2)在Service层具体实现业务逻辑:
@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
@ApiOperation("修改员工信息")
@PutMapping("/edit")
public BaseResult edit(@RequestBody @Validated(Edit.class) EmployeeQuery employeeQuery) {
    return employeeService.editEmployee(employeeQuery);
}
  • 5)和启用/禁用员工一样,调用Service层的editEmployee方法,对该方法进行改造:
@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注解,指定自动填充的策略:
// 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方法:
@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对象
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
// 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
@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)重启服务,测试一下创建人和修改人是否自动填充:


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


http://www.niftyadmin.cn/n/5796970.html

相关文章

vscode怎么设置anaconda python解释器(anaconda解释器、vscode解释器)

文章目录 先在ananconda prompt里创建并激活了虚拟环境&#xff0c;然后执行where python&#xff0c;显示的第一个就是这个虚拟环境python解释器路径&#xff1a;然后我们可以在vscode里添加这个python解释器&#xff1a; 先在ananconda prompt里创建并激活了虚拟环境&#xf…

【从零开始入门unity游戏开发之——C#篇25】C#面向对象动态多态——virtual、override 和 base 关键字、抽象类和抽象方法

文章目录 多态多态的主要类型 一、virtual、override 和 base 关键字1、**virtual 关键字** (虚方法)2、**override 关键字** (重写)3、**base 关键字** (基类访问)4、总结&#xff1a; 二、抽象类和抽象方法1、抽象类1.1 什么是抽象类1.2 定义和使用抽象类 2、抽象方法2.1 什么…

python报错系列(16)--pyinstaller ????????

系列文章目录 文章目录 系列文章目录前言一、pyinstaller ????????1.报错如下2.安装pyinstaller3.报错如下&#xff1a;4.封装py文件为exe成功5.国内源 总结 前言 一、pyinstaller ??? 1.报错如下 PS D:\Users\gxcaoty\Desktop\性能覆盖率> pyinstaller37.exe…

远程过程调用(RPC,Remote Procedure Call)是一种协议

远程过程调用&#xff08;RPC&#xff0c;Remote Procedure Call&#xff09;是一种协议&#xff0c;允许程序在不同的计算机上执行代码&#xff0c;就像调用本地函数一样。在Python中&#xff0c;有几种常见的RPC框架和库可以用来实现远程过程调用。 以下是一些常用的Python …

Pytorch | 从零构建ParNet/Non-Deep Networks对CIFAR10进行分类

Pytorch | 从零构建ParNet/Non-Deep Networks对CIFAR10进行分类 CIFAR10数据集ParNet架构特点优势应用 ParNet结构代码详解结构代码代码详解SSEParNetBlock 类DownsamplingBlock 类FusionBlock 类ParNet 类 训练过程和测试结果代码汇总parnet.pytrain.pytest.py 前面文章我们构…

【Redis】缓存

什么是缓存 https://tech.meituan.com/2017/03/17/cache-about.html Spring Data Redis Spring Data Redis提供了从Spring应用程序轻松配置和访问Redis的功能。 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>sp…

【HTML】Shadow DOM

Shadow DOM 允许将隐藏的 DOM 树附加到常规的 DOM 树中。它以 shadow root 节点为起始根节点&#xff0c;在这个根节点的下方&#xff0c;可以是任意元素&#xff0c;和普通的 DOM 元素一样。这样&#xff0c;你就可以创建一个独立的 DOM 子树&#xff0c;它与主文档隔离开来&a…

苍穹外卖-day05redis 缓存的学习

苍穹外卖-day05 课程内容 Redis入门Redis数据类型Redis常用命令在Java中操作Redis店铺营业状态设置 学习目标 了解Redis的作用和安装过程 掌握Redis常用的数据类型 掌握Redis常用命令的使用 能够使用Spring Data Redis相关API操作Redis 能够开发店铺营业状态功能代码 功能实…