Mybatis-Plus——实现公共字段自动填充(瑞吉外卖)

news2025/6/12 23:28:13

目录

一、公共字段自动填充

    1.1 问题分析

    1.2 实现思路及代码编写

二、 知识补充: ThreadLocal

2.1  使用背景

2.2 ThreadLocal介绍

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

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

2.3  实现功能

2.3.1 基于ThreadLocal封装BaseContext工具类

2.3.2 在过滤器方法中调用BaseContext工具类设置当前登录用户id

2.3.3 在MyMetaObjectHandler的方法中调用BaseContext工具类获取登录用户id


一、公共字段自动填充

    1.1 问题分析

    比如说在新增用户需要指定创建时间、创建人等字段,

                   修改用户时需要指定修改时间、修改人等字段

   这些字段属于公共字段,也就是很多表中都有这些字段

这样我们在以后写起来非常的麻烦, 每次做操作都需要自己手动写。但是对于Mybatis plus来说这些是小意思,它为我们提供了公共字段自动填充功能

  1.2 实现思路及代码编写

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

      

     实现步骤:

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

    @TableField(value ="create_time",fill = FieldFill.INSERT)    //插入时填充字段
    private LocalDateTime createTime;

    @TableField(value ="update_time",fill = FieldFill.INSERT_UPDATE)//插入和更新时填充字段
    private LocalDateTime updateTime;

    @TableField(value = "create_user",fill = FieldFill.INSERT)//插入时填充字段
    private Long createUser;

    @TableField(value = "update_user",fill = FieldFill.INSERT_UPDATE)//插入和更新时填充字段
    private Long updateUser;

   其中FieldFill是一个枚举类,如下所示:

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

package com.reggie_take_out.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 {
    /**
     * 执行insert语句的时候执行
     *
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("公共字段自动填充——insertFill");
//      自动填充
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime", LocalDateTime.now());

//      获取session对象
        metaObject.setValue("createUser", BaseContext.getCurrentId());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());
    }

    /**
     * 执行update语句的时候执行
     *
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("公共字段自动填充——updateFill");
        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());

    }

}

二、 知识补充: ThreadLocal

  

2.1  使用背景

 为什么要使用这个类?

      比如我们要给updateUser与createUser字段设置值的时候,我们是通过HttpServletRequest对象获取

 request.getSession().getAttribute("employee");

      但是我们在写公共字段自动填充的时候发现不能使用HttpServletRequest。

      除此之外,将用户id放入到HttpSession中也是获取不到的,MyMetaObjectHandler类中是不能获取HttpSession对象的所以我们需要其他方式来进行获取。

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

        1.LoginCheckFilter 的doFilter方法

        2.EmployeeController的update方法

        3.MyMetaObjectHandler的updateFill方法 

            

         

解决思路:

     我们可以在LoginCheckFilter的doFilter方法中获取当前登录用户id,并调用ThreadLocal的set方法来设置当前线程的线程局部变量的值(用户id),然后再MyMetaObjectHandler的updateFill方法中调用ThreadLocal的get方法来获取当前线程所对应的线程局部变量的值(用户id)

2.2 ThreadLocal介绍

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

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

    具体代码查看2.3.1 

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

    具体代码查看2.3.1 

2.3  实现功能

2.3.1 基于ThreadLocal封装BaseContext工具类

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

    public static void setCurrentId(Long id){
        threadLocal.set(id);
    }

    public static Long getCurrentId(){
        return threadLocal.get();
    }
}

2.3.2 在过滤器方法中调用BaseContext工具类设置当前登录用户id

/**
 * 检查用户是否已经完成登录
 * 过滤器与拦截器的区别:Filter对所有访问进行增强(在Tomcat服务器进行配置),Interceptor仅针对SpringMVC的访问进行增强
 */
@Slf4j
@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*")  //urlPatterns指定拦截哪些路径
public class LoginCheckFilter implements Filter {

    //  此对象的作用:路径匹配器,  匹配路径时支持通配符
    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//      servletRequest向下强制类型转换
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;


        //1. 获取本次请求的URI( URI:请求的资源路径)
        String requestURI = request.getRequestURI();

        log.info("拦截到请求:{}", request.getRequestURI());
        // 定义不用处理的请求路径
        String[] urls = new String[]{
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**"
        };

        //2. 判断本次请求是否需要处理(因为有些请求并不需要用户登录)
        boolean check = check(requestURI, urls);

        //3.如果不需要处理,则直接放行
        if (check) {
            log.info("本次请求{}不需要处理", request.getRequestURI());
            filterChain.doFilter(request, response);
            return;
        }

        //4.判断登录状态,如果已登录,则直接放行.从session中获取用户,如果获取到说明已经登录
        if (request.getSession().getAttribute("employee") != null) {
            log.info("用户已登录,用户id为{}", request.getSession().getAttribute("employee"));

            Long empId = (Long) request.getSession().getAttribute("employee");
            BaseContext.setCurrentId(empId);
            
            filterChain.doFilter(request, response);
            return;
        }

        //5.如果未登录则返回未登录结果
        log.info("资源路径路径:{},用户未登录{}", request.getRequestURI(), request.getSession().getAttribute("employee"));
//           通过输出流的方式向客户端响应数据   (为什么要返回这个NOTLOGIN?  因为前端需要这个来进行判定是否登录)
        response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
//        filterChain.doFilter(request, response);  加上这个就无法实现

    }

    /**
     * 检查本次请求是否需要放行
     *
     * @param requestURI 请求的资源路径
     * @param urls       放过的路径
     * @return true 放行
     */
    public boolean check(String requestURI, String[] urls) {
        for (String url : urls) {
            boolean match = PATH_MATCHER.match(url, requestURI);
            if (match) {
//           放行
                return true;
            }
        }
        return false;
    }
}

2.3.3 在MyMetaObjectHandler的方法中调用BaseContext工具类获取登录用户id

package com.reggie_take_out.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 {
    /**
     * 执行insert语句的时候执行
     *
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("公共字段自动填充——insertFill");
//      自动填充
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime", LocalDateTime.now());

//      获取session对象
        metaObject.setValue("createUser", BaseContext.getCurrentId());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());
    }

    /**
     * 执行update语句的时候执行
     *
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("公共字段自动填充——updateFill");
        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());

    }

}

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

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

相关文章

Linux 下 QT 安卓开发环境搭建

1、采用QT5.14.2&#xff0c;主要是安装1、jdk 2、SDK 3、NDK 三个工具包&#xff0c;版本要匹配上&#xff1b; 备注&#xff1a;配置SDK需要注意&#xff1a; 解压SDK&#xff0c;进入到tools目录下&#xff0c;运行android可执行文件&#xff0c;会打开一个页面&#xff0c…

nvm软件使用-同一个环境下控制多个不同node版本

1.使用场景 nvm是一个用于管理Node.js版本的工具&#xff0c;它可以让你在同一台机器上安装和切换不同的Node.js版本。使用nvm的好处有以下几点&#xff1a; 1.1.nvm可以让你轻松地测试你的代码在不同的Node.js版本下的兼容性和性能&#xff0c;避免因为版本差异导致的问题。…

代码随想录_二叉树_leetcode530 501

leetcode 530 二叉搜索树的最小绝对差 530. 二叉搜索树的最小绝对差 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数&#xff0c;其数值等于两值之差的绝对值。 示例 1&#xff1a; 输入&#xff1a;root [4,2,6…

ChatGTP如此强大,我们普通人如何利用它来赚钱?

我从效率提升的角度&#xff0c;分享了我这段时间看到的、用到的&#xff0c;以及思考的一些内容。 最近这段时间&#xff0c;我算是密集的学习。不得不说&#xff0c;优质的资料在推特和油管上特别多&#xff0c;看科技大佬的分享真是一种享受。 很多大神也会录制各种详细的…

项目进度把控难题,项目管理系统轻松帮你解决!

项目管理是企业中非常重要的一项工作&#xff0c;无论是新的项目还是旧的项目&#xff0c;都需要对其进行有效的管理&#xff0c;以确保项目顺利完成并达到预期目标。项目管理涉及到很多方面&#xff0c;比如项目交接、实施计划管理、项目功能管理、项目设备管理等等&#xff0…

tcp三次握手与四次分手

一、tcp三次握手 1、TCP建立连接的流程 1&#xff09;client首先给server发送一个SYN报文&#xff0c;表示想要与server建立TCP连接&#xff0c;此时seq序列号为0 2&#xff09;server收到了报文后&#xff0c;向client发送一个SYN和ACK确认报文&#xff0c;将ACK和SYN放到同一…

SpringSecurity之CSRF

前言 前一篇讲解了关于用户注销以及自动登录&#xff08;记住我&#xff09;等功能。今天我们来看一下关于CSRF的使用及避免。 什么是CSRF 跨站请求伪造&#xff08;英语&#xff1a;Cross-site request forgery&#xff09;&#xff0c;也被称为 one-click attack 或者 ses…

74-网络一(基础知识)

网络一一.基础知识1.什么是网络2.互联网3.IP地址(1)什么是IP地址及其作用(2)IP地址的组成(3)IP地址的分类(4)IP地址的查询4.MAC地址5.端口号(1)端口号及其作用(2)怎么实现A主机上的一个进程和B进程上的一个进程实现通讯?网络二见:网络二 一.基础知识 1.什么是网络 网络是由…

亚马逊云科技开启您的云财务管理之旅——成本优化

众所周知&#xff0c;当你想要从头开始建立一个云财务管理计划似乎是稍有难度的。因此&#xff0c;亚马逊云科技解构了4个云财务管理CFM原则——查看、节省、计划和运营——并分享可以实施的操作指南&#xff0c;帮助您在云上取得成功。 云成本管理工具 亚马逊云科技提供一系列…

VVC之编码结构

VVC之编码结构&#xff08;新一代通用视频编码的读书笔记&#xff09;缩写概述EncAppmain函数解读缩写 缩写含义CVSCoded Video Sequence, 编码视频序列IRAPIntra Random Access Point, 帧内随机接入点GDRGradual Decoding Refresh, 逐渐解码刷新AUAccess Unit, 访问单元PUPic…

5.3 定积分的换元积分法和分部积分法

学习目标&#xff1a; 学习定积分的换元积分法和分部积分法&#xff0c;我会采取以下步骤&#xff1a; 熟悉基本概念和公式&#xff1a;首先&#xff0c;要对定积分、换元积分法和分部积分法有基本的理解&#xff0c;并掌握它们的基本公式和性质。 学习经典例题&#xff1a;找…

OSPF(开放式最短路径优先协议)简介

一.OSPF协议原理简介 二.OSPF协议特点 三.OSPF区域 1.OSPF区域划分作用 2.OSPF 区域划分方式&#xff1a;基于接口(链路)划分区域 3.OSPF 区域标识&#xff1a; 最终归结为32个二进制 4.区域分类&#xff1a; 便于区域设计 5.OSPF 路由器角色&#xff1a; 四.OSPF简单配…

Spring项目创建与 Spring Bean 的存储与读取

目录 一、创建Spring项目 1.1 创建Maven项目 1.2 添加 Spring 框架依赖 1.3 添加启动类 二、Bean对象的创建与存储 2.1 创建Bean 2.2 将Bean注册到容器 2.3 获取并使用Bean对象 2.3.1 创建Spring上下文 2.3.2 从Spring容器中获取Bean对象​编辑 延申&#xff08;多种…

开放式耳机新巅峰!南卡OE Pro兼备澎湃音质、舒适佩戴、创新设计

众所周知&#xff0c;当初苹果带来TWS耳机新时代以后&#xff0c;后面有许多的蓝牙耳机相继跟随和模仿&#xff0c;但NANK南卡却独辟蹊径&#xff0c;将在近日重磅推出首款0压无感全开放无线耳机——南卡OE Pro&#xff0c;走向开放式TWS耳机的新时代。 31度黄金倾斜受力面&…

BGP策略实验

实验要求&#xff1a; 1、使用PreVa1策略&#xff0c;确保R4通过R2到达192.168.10.0/24 2、使用AS_Path策略&#xff0c;确保R4通过R3到达192.168.11.0/24 3、配置MED策略&#xff0c;确保R4通过R3到达192.168.12.0/24 4、使用Local Preference策略&#xff0c;确保R1通过R2到…

有人靠ChatGPT 狂赚200W !有人到现在,连账号都没开通......

作者| Mr.K 编辑| Emma来源| 技术领导力(ID&#xff1a;jishulingdaoli)互联网风水轮流转&#xff0c;当初元宇宙盛极一时之际&#xff0c;在一些知识付费平台上&#xff0c;任何一个关于元宇宙的课程或培训&#xff0c;都很热销&#xff0c;有一定号召力的博主&#xff0c;登…

【JS】1651- 10 个 JS 中 try...catch 使用技巧

作为一位 Web 前端工程师&#xff0c;JavaScript 中的 try...catch 是我们常用的特性之一。本文我将分享 10 个有用的 try...catch 使用技巧&#xff0c;让你在处理异常时更加得心应手。1. 捕获所有异常如果你想捕获代码中所有可能的异常&#xff0c;可以使用一个不带参数的 ca…

对标ChatGPT的开源中文方案

目录 前言 一、Meta发布大语言模型LLaMA 二、斯坦福基于 Meta 的 LLaMA 7B 模型微调出Alpaca 三、基于TencentPretrain训练中文LLaMA大规模语言模型 四、基于斯坦福Alpaca训练中文对话大模型BELLE 五、 清华开源项目ChatGLM中文对话模型 六、基于LLaMA的开源中文语言模型…

SpringBoot整合xxl-job详细教程

SrpingBoot整合xxl-job&#xff0c;实现任务调度说明调度中心执行器调试整合SpringBoot说明 Xxl-Job是一个轻量级分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线&#xff0c;开箱即用。Xxl-Job有…

三菱PLC GX Work2学习笔记

Programmable Logic Controller 1 指令集 1.1 触点指令 指令名称指令示例图示常开触点LDLD X01常闭触点LDILDI X12输出线圈OUTOUT Y03或常开触点OROR X33或常闭触点ORIORI X33置位SETSET Y03复位RSTRST Y03区域复位ZRSTZRST Y0 Y53上升沿LDPLDP X03下降沿LDFLDF X13结果上升…