公共字段自动填充-Mybatis Plus实现

简历描述

使用ThreadLocal动态获取当前登录用户,从而解决MybatisPlus公共字段自动填充问题。达到简化编码的目的,使业务方法更加简洁。

问题分析

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

而针对于这些字段,我们的赋值方式为:

A. 在新增数据时, 将createTime、updateTime 设置为当前时间, createUser、updateUser设置为当前登录用户ID。

B. 在更新数据时, 将updateTime 设置为当前时间, updateUser设置为当前登录用户ID。

目前,在我们的项目中处理这些字段都是在每一个业务方法中进行赋值操作,如下:

如果都按照上述的操作方式来处理这些公共字段, 需要在每一个业务方法中进行操作, 编码相对冗余、繁琐,那能不能对于这些公共字段在某个地方统一处理,来简化开发呢?

答案是可以的,我们使用Mybatis Plus提供的公共字段自动填充功能。

基本功能实现

1 思路分析

Mybatis Plus公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码。在上述的问题分析中,我们提到有四个公共字段,需要在新增/更新中进行赋值操作, 具体情况如下:

实现步骤:

1、在实体类的属性上加入@TableField注解,指定自动填充的策略。

2、按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现MetaObjectHandler接口。

2 代码实现

1). 实体类的属性上加入@TableField注解,指定自动填充的策略。

在员工Employee实体类的公共字段属性上, 加上注解, 指定填充策略。(ps.在资料中提供的实体类,已经添加了该注解,并指定了填充策略)

2). 按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现MetaObjectHandler接口。

所属包: com.itheima.reggie.common


 

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

/**
 * 自定义元数据对象处理器
 */
@Component
@Slf4j
public class MyMetaObjecthandler implements MetaObjectHandler {
    /**
     * 插入操作,自动填充
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("公共字段自动填充[insert]...");
        log.info(metaObject.toString());
        
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("createUser",new Long(1));
        metaObject.setValue("updateUser",new Long(1));
    }

    /**
     * 更新操作,自动填充
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("公共字段自动填充[update]...");
        log.info(metaObject.toString());

3 功能测试

编写完了元数据对象处理器之后,我们就可以将之前在新增和修改方法中手动赋值的代码删除或注释掉。

然后,我们启动项目,在员工管理模块中,测试增加/更新员工信息功能,然后通过debug 或者 直接查询数据库数据变更的形式,看看我们在新增/修改数据时,这些公共字段数据是否能够完成自动填充。

1.3 功能完善

1.3.1 思路分析

前面我们已经完成了公共字段自动填充功能的代码开发,但是还有一个问题没有解决,就是我们在自动填充createUser和updateUser时设置的用户id是固定值,现在我们需要完善,改造成动态获取当前登录用户的id。

大家可能想到,用户登录成功后我们将用户id存入了HttpSession中,现在我从HttpSession中获取不就行了?

注意,我们在MyMetaObjectHandler类中是不能直接获得HttpSession对象的,所以我们需要通过其他方式来获取登录用户id。

那么我先搞清楚一点,当我们在修改员工信息时, 我们业务的执行流程是什么样子的,如下图:

客户端发送的每次http请求,对应的在服务端都会分配一个新的线程来处理,在处理过程中涉及到下面类中的方法都属于相同的一个线程:

1). LoginCheckFilter的doFilter方法

2). EmployeeController的update方法

3). MyMetaObjectHandler的updateFill方法

我们可以在上述类的方法中加入如下代码(获取当前线程ID,并输出):


 

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

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

经过上述的分析之后,发现我们可以使用JDK提供的一个类, 来解决此问题,它是JDK中提供的 ThreadLocal。

1.3.2 ThreadLocal

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

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

ThreadLocal常用方法:

A. public void set(T value) : 设置当前线程的线程局部变量的值

B. public T get() : 返回当前线程所对应的线程局部变量的值

C. public void remove() : 删除当前线程所对应的线程局部变量的值

我们可以在LoginCheckFilter的doFilter方法中获取当前登录用户id,并调用ThreadLocal的set方法来设置当前线程的线程局部变量的值(用户id),然后在MyMetaObjectHandler的updateFill方法中调用ThreadLocal的get方法来获得当前线程所对应的线程局部变量的值(用户id)。 如果在后续的操作中, 我们需要在Controller / Service中要使用当前登录用户的ID, 可以直接从ThreadLocal直接获取。

1.3.3 操作步骤

实现步骤:

1). 编写BaseContext工具类,基于ThreadLocal封装的工具类

2). 在LoginCheckFilter的doFilter方法中调用BaseContext来设置当前登录用户的id

3). 在MyMetaObjectHandler的方法中调用BaseContext获取登录用户的id

1.3.4 代码实现

1). BaseContext工具类

所属包: com.itheima.reggie.common

/**
 * 基于ThreadLocal封装工具类,用户保存和获取当前登录用户id
 */
public class BaseContext {
    private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
    /**
     * 设置值
     * @param id
     */
    public static void setCurrentId(Long id){
        threadLocal.set(id);
    }
    /**
     * 获取值
     * @return
     */
    public static Long getCurrentId(){
        return threadLocal.get();
    }
}

LoginCheckFilter中存放当前登录用户到ThreadLocal

在doFilter方法中, 判定用户是否登录, 如果用户登录, 在放行之前, 获取HttpSession中的登录用户信息, 调用BaseContext的setCurrentId方法将当前登录用户ID存入ThreadLocal。

Long empId = (Long) request.getSession().getAttribute("employee");
BaseContext.setCurrentId(empId);

3). MyMetaObjectHandler中从ThreadLocal中获取

将之前在代码中固定的当前登录用户1, 修改为动态调用BaseContext中的getCurrentId方法获取当前登录用户ID

1.3.5 功能测试

完善了元数据对象处理器之后,我们就可以重新启动项目,完成登录操作后, 在员工管理模块中,测试增加/更新员工信息功能, 直接查询数据库数据变更,看看我们在新增/修改数据时,这些公共字段数据是否能够完成自动填充, 并且看看填充的create_user 及 update_user字段值是不是本地登录用户的ID。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Zabbix5.0部署及应用

环境 主机名 IP 类型server01192.168.134.165zabbix-serverserver02 192.168.134.166zabbix-agent 官方部署文档 1 .安装yum源 [rootserver01 ~]# rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-rel…

浅谈WPF之控件模板和数据模板

WPF不仅支持传统的Windows Forms编程的用户界面和用户体验设计&#xff0c;同时还推出了以模板为核心的新一代设计理念。在WPF中&#xff0c;通过引入模板&#xff0c;将数据和算法的“内容”和“形式”进行解耦。模板主要分为两大类&#xff1a;数据模板【Data Template】和控…

初刷leetcode题目(2)——数据结构与算法

&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️…

PostgreSQL 难搞的事系列 --- vacuum 的由来与PG16的命令的改进 (1)

开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, Sql Server等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友…

从零开始:抖音酒店景区小程序开发指南

为了满足用户多样化的需求&#xff0c;开发一款抖音酒店景区小程序成为了业界的一个新兴趋势。在这篇文章中&#xff0c;我们将探讨如何开发一款引人注目的抖音风格的酒店景区小程序。 一、抖音风格的设计理念 在设计酒店景区小程序时&#xff0c;我们需要融入抖音的设计理念。…

22 - 如何优化垃圾回收机制?

我们知道&#xff0c;在 Java 开发中&#xff0c;开发人员是无需过度关注对象的回收与释放的&#xff0c;JVM 的垃圾回收机制可以减轻不少工作量。但完全交由 JVM 回收对象&#xff0c;也会增加回收性能的不确定性。在一些特殊的业务场景下&#xff0c;不合适的垃圾回收算法以及…

Leetcode—剑指OfferII LCR 022.环形链表II【中等】

2023每日刷题&#xff08;三十三&#xff09; Leetcode—LCR 022.环形链表II 算法思想 参考k神的博客 实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode *detectCycle(struct List…

【C++】类和对象(6)--运算符重载

目录 一 概念 二 运算符重载的实现 三 关于时间的所有运算符重载 四 默认赋值运算符 五 const取地址操作符重载 一 概念 C为了增强代码的可读性引入了运算符重载&#xff0c;运算符重载是具有特殊函数名的函数&#xff0c;也具有其返回值类型&#xff0c;函数名字以及参数…

Git 简介及使用

前言 假设有这样一个场景&#xff0c;老板让员工做一个档案&#xff0c;员工这个档案做好了之后交给老板看&#xff0c;此时老板不满意&#xff0c;又让回去改&#xff0c;改完给老板看&#xff0c;但是老板又不是很满意&#xff0c;就这样改了又改&#xff0c;给老板看过之后&…

代码随想录算法训练营第四十五天| 139.单词拆分

文档讲解&#xff1a;代码随想录 视频讲解&#xff1a;代码随想录B站账号 状态&#xff1a;看了视频题解和文章解析后做出来了 139.单词拆分 class Solution:def wordBreak(self, s: str, wordDict: List[str]) -> bool:n len(s)dp [False] * (n1)dp[0] Truemax_len m…

WMS重力式货架库位对应方法

鉴于重力式货架的特殊结构和功能&#xff0c;货物由高的一端存入&#xff0c;滑至低端&#xff0c;从低端取出。所以重力式货架的每个货位在物理上都会有一个进货口和一个出货口。因此&#xff0c;在空间上&#xff0c;对同一个货位执行出入库操作需要处于不同的位置。 比如对…

【AD封装】芯片IC-SOP,SOIC,SSOP,TSSOP,SOT(带3D)

包含了我们平时常用的芯片IC封装&#xff0c;包含SOP,SOIC,SSOP,TSSOP,SOT&#xff0c;总共171种封装及精美3D模型。完全能满足日常设计使用。每个封装都搭配了精美的3D模型哦。 ❖ TSSOP和SSOP 均为SOP衍生出来的封装。TSSOP的中文解释为&#xff1a;薄的缩小型 SOP封装。SSO…

GSVA,GSEA,KEGG,GO学习

目录 GSVA 1&#xff1a;获取注释基因集 2&#xff1a;运行 GSEA 1,示例数据集 2,运行 GSEA_KEGG富集分析 GSEA_GO富集分析 DO数据库GSEA MSigDB数据库选取GSEA KEGG 1&#xff1a;运行 2&#xff1a;绘图 bar图 气泡图 绘图美化 GO GSVA 1&#xff1a;获取注…

springBoot 配置druid多数据源 MySQL+SQLSERVER

1:pom 文件引入数据 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.0</version> </dependency>…

mysql服务器数据同步

在Linux和Windows之间实现MySQL服务器数据的同步。下面是一些常见的方法和工具&#xff1a; 复制&#xff08;Replication&#xff09;&#xff1a;MySQL复制是一种常见的数据同步技术&#xff0c;可用于将一个MySQL服务器的数据复制到其他服务器。您可以设置主服务器&#xff…

CMSIS-RTOS在stm32使用

目录&#xff1a; 一、安装和配置CMSIS_RTOS.1.打开KEIL工程&#xff0c;点击MANAGE RUN-TIME Environment图标。2.勾选CMSIS CORE和RTX.3.配置RTOS 时钟频率、任务栈大小和数量&#xff0c; 软件定时器. 二、CMSIS_RTOS内核启动和创建线程。1.包含头文件。2.内核初始化和启动。…

C#,数值计算——插值和外推,曲线插值(Curve_interp)的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Object for interpolating a curve specified by n points in dim dimensions. /// </summary> public class Curve_interp { private int dim { get; s…

openGauss通过VIP实现的故障转移

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

VisualGDB 6.0 R2 Crack

轻松跨平台"VisualGDB 使 Visual Studio 的跨平台开发变得简单、舒适。它支持&#xff1a; 准系统嵌入式系统和物联网模块&#xff08;查看完整列表&#xff09; C/C Linux 应用程序 本机 Android 应用程序和库 Raspberry Pi 和其他Linux 板 Linux 内核模块&#xff08;单…

【PTA题目】6-13 求叠数(递归版) 分数 10

6-13 求叠数(递归版) 分数 10 全屏浏览题目 切换布局 作者 李祥 单位 湖北经济学院 请编写递归函数&#xff0c;生成叠数。 例如&#xff1a;Redup(5,8)88888 函数原型 long long Redup(int n, int d); 说明&#xff1a;参数 n 为重复次数(非负整数)&#xff0c;d 为数字…