瑞吉外卖 - 公共字段自动填充功能(10)

news2024/11/28 6:47:00

某马瑞吉外卖单体架构项目完整开发文档,基于 Spring Boot 2.7.11 + JDK 11。预计 5 月 20 日前更新完成,有需要的胖友记得一键三连,关注主页 “瑞吉外卖” 专栏获取最新文章。
相关资料:https://pan.baidu.com/s/1rO1Vytcp67mcw-PDe_7uIg?pwd=x548
提取码:x548

文章目录

    • 1.问题分析
    • 2.代码实现
    • 3.功能测试

1.问题分析

前面我们已经完成了后台系统的员工管理功能开发,在新增员工时需要设置创建时间(create_time)、创建人(create_user)、修改时间(update_time)、修改人(update_user)等字段,在编辑员工时需要设置修改世纪那和修改人等字段。显然,这些字段属于公共字段,也就是很多表格中都有这些字段,如下:

那能不能对于这些公共字段在某个地方统一处理,来简化开发呢?答案就是使用 MyBatis Plus 提供的公共字段自动填充功能

2.代码实现

MyBatis Plus 公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码。

实现步骤如下:

  1. 在实体类的属性上加入 @TableField 注解,指定自动填充的策略;
  2. 按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现 MetaObjectHandler 接口。

修改后的 Employee 实体类如下:

@Data
public class Employee implements Serializable {

    // 用于序列化的版本号
    private static final long serialVersionUID = 1L;
    // 自增主键
    private Long id;
    // 用户名
    private String username;
    // 姓名
    private String name;
    // 密码
    private String password;
    // 手机号
    private String phone;
    // 性别
    private String sex;
    // 身份证号
    private String idNumber;
    // 状态,0:禁用,1:启用
    private Integer status;
    
    // 创建时间(插入时自动填充)
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    // 更新时间(插入和更新时自动填充)
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    // 创建人(插入时自动填充)
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    // 更新人(插入和更新时自动填充)
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
}

接下来按照框架的要求编写元数据对象处理器,我们可以在之前创建的 handler 包下创建一个 MyMetaObjectHandler 类实现 MetaObjectHandler 接口。

完整代码如下:

package cn.javgo.reggie_take_out.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;

/**
 * 自定义元对象处理器
 * @author: JavGo
 * @description: TODO
 * @date: 2023/5/17 16:36
 */
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    /**
     * 插入时填充
     * @param metaObject 元对象,该对象中封装了需要被填充的字段的值
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("createUser", 1L);
        metaObject.setValue("updateUser", 1L);
    }

    /**
     * 更新时填充
     * @param metaObject 元对象
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("updateUser",1L);
    }
}

上面我们就已经完成了公共字段自动填充功能的代码开发,但是还有一个问题没有解决,就是我们在自动填充 createUserupdateUser 时设置的用户 id 如何获取呢?(上面我们暂时都写为了 1L)

对于获取用户 id,容易想到的是用户登录成功后我们将用户 id 存入了 HttpSession 中,现在我从 HttpSession 中获取不就行了?注意,我们在 MyMetaObjectHandler 类中是不能获得 HttpSession 对象的,所以我们需要通过其他方式来获取登录用户 id。可以使用 ThreadLocal 来解决此问题,它是 JDK 中提供的一个类。

在学习 ThreadLocal 之前,我们需要先确认一个事情,就是客户端发送的每次 http 请求,对应的在服务端都会分配一个新的线程来处理,在处理过程中涉及到下面类中的方法都属于相同的一个线程(以更新为例):

  1. LoginCheckFilter 的 doFilter 方法;
  2. EmployeeController 的 update 方法;
  3. MyMetaObjectHandler 的 updateFill 方法。

我们可以在上面的三个方法中分别加入下面代码片段 (获取当前线程 id) :

long threadId = Thread.currentThread().getId();
log.info("当前线程id:{}",threadId);

注意:需要在类上添加 @Slf4j 注解。

执行编辑员工功能进行验证,通过观察控制台输出可以发现,一次请求对应的线程 id 是相同的:

什么是 ThreadLocalThreadLocal 并不是一个 Thread,而是 Thread 的局部变量。当使用 ThreadLocal 维护变量时,ThreadLocal 为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。ThreadLocal 为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。

ThreadLocal 常用方法:

方法说明
public void set(T value)设置当前线程的线程局部变量的值
public T get()返回当前线程所对应的线程局部变量的值

我们可以在 LoginCheckFilterdoFilter 方法中获取当前登录用户 id,并调用 ThreadLocalset 方法来设置当前线程的线程局部变量的值 (用户 id),然后在 MyMetaObjectHandlerupdateFill 方法中调用 ThreadLocalget 方法来获得当前线程所对应的线程局部变量的值 (用户 id)。

OK,简单分析后的实现步骤如下:

  1. 编写 BaseContext 工具类,基于 ThreadLocal 封装的工具类;
  2. LoginCheckFilterdoFilter 方法中调用 BaseContext 来设置当前登录用户的 id;
  3. MyMetaObjectHandler 的方法中调用 BaseContext 获取登录用户的 id。

common/BaseContext.java 工具类完整代码如下:

package cn.javgo.reggie_take_out.common;

/**
 * 基于 ThreadLocal 封装的工具类,用于保存和获取当前线程中的登录用户 id
 */
public class BaseContext {
    private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    /**
     * 设置当前线程中的登录用户 id
     * @param id 用户 id
     */
    public static void setCurrentId(Long id){
        threadLocal.set(id);
    }

    /**
     * 获取当前线程中的登录用户 id
     * @return 用户 id
     */
    public static Long getCurrentId(){
        return threadLocal.get();
    }
}

修改后的 LoginCheckFilter#doFilter 方法如下:

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    long threadId = Thread.currentThread().getId();
    log.info("当前线程id:{}",threadId);

    // 类型转换
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    HttpServletResponse response = (HttpServletResponse) servletResponse;

    // 1.获取请求的 URI 地址
    String requestURI = request.getRequestURI();
    // 2.判断当前的 URI 地址是否需要忽略
    boolean check = Arrays.stream(IGNORE_URI).anyMatch(uri -> ANT_PATH_MATCHER.match(uri, requestURI));
    // 3.如果需要忽略,则直接放行
    if(check){
        filterChain.doFilter(request,response);
        return;
    }
    // 4.如果用户已经登录,则直接放行
    Long empId = (Long) request.getSession().getAttribute("employee");
    if(empId != null){
        // 将当前登录用户的 id 存入 ThreadLocal 中
        BaseContext.setCurrentId(empId);
        // 放行
        filterChain.doFilter(request,response);
        return;
    }
    // 5.用户未登录,通过输出流方式向客户端页面响应数据
    response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
}

最后注释掉 EmployeeController 中的 setCreateTimesetUpdateTimesetCreateUsersetUpdateUser 部分代码即可。

3.功能测试

下面以新增员工为例进行测试:

点击保存后,查看对应数据库表中是否自动填充了我们设置的公共字段:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/537754.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

每日一练 | 网络工程师软考真题 Day3

1、以下图的两种编码方案分别是 。 A&#xff0e;①差分曼彻斯特编码&#xff0c;②双相码 B&#xff0e;①NRZ编码&#xff0c;②差分曼彻斯特编码 C&#xff0e;①NRZ-I编码&#xff0c;②曼彻斯特编码 D&#xff0e;①极性码&#xff0c;②双极性码 2、假设模拟…

windows下安装emsdk

先从github上下载emsdk工程&#xff1a; # Get the emsdk repo git clone https://github.com/emscripten-core/emsdk.git# Enter that directory cd emsdkgit pull 更新到最新代码 clone 工程可以在 git bash here 命令行下&#xff1a; 执行下面的指令用cmd命令行&#xf…

chatgpt赋能Python-numpy_加速

介绍 NumPy是Python编程语言的数值计算扩展库。它包括一个强大的N维数组对象和用于处理这些数组的函数。NumPy是一个基于Python的免费开源软件项目&#xff0c;由社区驱动。这个库提供了一种高效的存储和处理大型矩阵数据的方式&#xff0c;同时也提供了非常高效的处理大量数据…

chatgpt赋能Python-jinja_python

Jinja Python介绍及SEO优化 Jinja是一个流行的Python模板引擎&#xff0c;它允许开发人员使用简单的语法来生成动态内容。在本文中&#xff0c;我们将介绍Jinja的基础知识&#xff0c;并探讨如何将其应用于搜索引擎优化。 Jinja Python介绍 Jinja是Python语言的一种模板引擎…

Java面向对象程序设计实验报告(实验一 面向对象基础练习)

✨作者&#xff1a;命运之光 ✨ 专栏&#xff1a;Java面向对象程序设计实验报告 目录 ✨一、需求分析 ✨二、概要设计 ✨三、详细设计 ✨四、调试分析 ✨附录&#xff1a;源代码&#xff08;带注释&#xff09; 实验一 面向对象基础练习 实验环境&#xff1a;EclipseJDK …

MindFusion.JavaScript Pack 2023 crack

MindFusion.JavaScript Pack 2023 crack 径向树布局-添加了新的类&#xff0c;它将树级别排列在围绕根的同心圆中。 套索缩放工具-控件现在支持使用套索工具进行缩放的几种方法&#xff1a; 可以将行为属性设置为“缩放”以始终绘制缩放套索。 用户可以使用修改键和鼠标左键绘制…

如何用Nginx快速搭建个人下载站?

1.开篇 我们在下载Nginx的时候&#xff0c;发现其下载地址遵循一定的规则。 发现其下载地址为&#xff1a;https://nginx.org/download/nginx-1.24.0.tar.gz&#xff0c; 可以猜测出其下载的主页为&#xff1a;https://nginx.org/download 果然&#xff0c;该页面提供了各个版…

chatgpt赋能Python-num_python

NumPy简介&#xff1a;为什么它对数据科学如此重要&#xff1f; 什么是NumPy&#xff1f; NumPy是一种Python库&#xff0c;帮助程序员在Python中进行高度优化的科学计算。NumPy提供了许多独特的工具&#xff0c;以帮助数据科学家和工程师进行线性代数、离散傅立叶变换和其他…

三十七、微服务保护

1、初识Sentinel 1.1雪崩问题 微服务调用链路中的某个服务故障&#xff0c;引起整个链路中的所有微服务都不可用&#xff0c;这就是雪崩。 解决雪崩问题的常见方式有四种&#xff1a; 超时处理&#xff1a;设定超时时间&#xff0c;请求超过一定时间没有响应就返回错误信息&am…

DEJA_VU3D - Cesium功能集 之 109-三角形(标绘+编辑)

前言 编写这个专栏主要目的是对工作之中基于Cesium实现过的功能进行整合,有自己琢磨实现的,也有参考其他大神后整理实现的,初步算了算现在有差不多实现小140个左右的功能,后续也会不断的追加,所以暂时打算一周2-3更的样子来更新本专栏(每篇博文都会奉上完整demo的源代码…

HTTP第15讲——HTTP的连接管理

短连接 HTTP 协议最初&#xff08;0.9/1.0&#xff09;是个非常简单的协议&#xff0c;通信过程也采用了简单的“请求 - 应答”方式。 它底层的数据传输基于 TCP/IP&#xff0c;每次发送请求前需要先与服务器建立连接&#xff0c;收到响应报文后会立即关闭连接。 因为客户端与…

chatgpt赋能Python-numpy_数据归一化

Numpy 数据归一化&#xff1a;介绍和原理 随着大数据和机器学习的发展&#xff0c;数据预处理变得越来越重要。对于数据进行标准化和归一化是其中的一项常见操作。本文将介绍numpy中的数据归一化&#xff0c;包括其原理和实现方法。 什么是数据归一化&#xff1f; 在数据处理…

Spring AOP的概念和使用

什么是AOP AOP是一种思想&#xff0c;它叫做面向切面编程&#xff0c;简单的来说就是对某一类事请做集中处理。比如说&#xff1a;登录效验功能&#xff0c;在使用AOP之前&#xff0c;我们进行登录效验需要在每个方法中写一遍登录效验的代码&#xff1b;使用AOP后&#xff0c;…

chatgpt赋能Python-numpy提取数据

Numpy提取数据&#xff1a;一种高效处理数据的方法 Numpy是Python中一个用于科学计算的库&#xff0c;它提供了一些高效的数值计算工具和数据结构。其中一个重要的功能是对大量数据进行高效的处理与分析。本文将介绍Numpy提取数据的用法&#xff0c;帮助您更高效地处理数据。 …

Java参数绑定(包括按值传递和按引用传递)

在Java中&#xff0c;参数绑定是一种将实际参数值传递给方法或函数的过程。在方法调用中&#xff0c;参数绑定决定了方法的形式参数&#xff08;在方法声明中定义的参数&#xff09;和实际参数&#xff08;传递给方法的参数&#xff09;之间的关系。 Java中的参数绑定有两种形…

chatgpt赋能Python-numpy数据归一化

Numpy数据归一化&#xff1a;什么是归一化以及为什么要归一化&#xff1f; 当我们处理数据时&#xff0c;我们常常要将它们归一化。归一化是将数值范围缩放到标准范围内的过程。这可以确保不同的特征或变量在计算机算法中具有相同的权重。这对于一些机器学习算法、人工神经网络…

chatgpt赋能Python-mac_python怎么用

如何在Mac上使用Python进行编程&#xff1f; 如果你是一位Python开发者&#xff0c;想在Mac上进行编程&#xff0c;本篇文章将会告诉你如何使用Python在Mac上进行编程。首先&#xff0c;你需要确认你的Mac上是否安装了Python&#xff0c;如果你是新手&#xff0c;可以去Python…

nginx(七十六)nginx与HTTP请求行的深入探讨

一 nginx与请求行相关 nginx处理来自客户端的HTTP请求行和请求头 ① 关于请求行的变量 $request $request_method SP $request_uri SP $server_protocol "案例讲解" ② nginx作为服务端接收关于method控制 1) 请求方法和支持的协议版本包含如下: -->协议…

离线安装apisix

公司部分机器因为某些原因无法联网&#xff0c;只能离线安装apisix&#xff0c;折腾了很久&#xff0c;走了很多弯路&#xff0c;记录一下安装过程。 下载所有的包 安装epel源 sudo yum install epel-release在home下创建文件夹/apisix-dependence 下载apache-apisix-repo以…

chatgpt赋能Python-mac上的python

在Mac上使用Python编程的好处 作为一名有10年Python编程经验的工程师&#xff0c;我必须说Mac是一个出色的编程工作台。Mac操作系统本质上就是一个整合了各种开发工具的平台&#xff0c;为Python编程提供了很好的支持。这篇文章将介绍在Mac上使用Python编程的好处。 简单易用…