mybatisPlus拦截器使用demo

news2024/11/15 8:31:23

概述

顾名思义,就是一个拦截器,和springmvc的拦截器,servlet的过滤器差不多,就是在执行前拦了一道,里面可以做一些自己的事情。

平时用的mybatisPlus较多,直接以com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor
为例。其内部维护了一个拦截器List,在拦截的时候for循环依次去调用这些拦截器,这时候的执行顺序就是list中的元素下标

在这里插入图片描述

mybatis官方介绍中可以拦截的类型共4种:

  1. Executor(拦截执行器的方法),method=update包括了增删改,可以从MappedStatement中获取实际执行的是哪种类型
  2. ParameterHandler(拦截参数的处理)
  3. ResultSetHandler(拦截结果集的处理)
  4. StatementHandler(拦截Sql语法构建的处理)

平时业务中拦截较多的就是增删改查,经典的就是分页拦截器–查询拦截器。

mybatisPlus拦截器Demo

参考了mybatisPlus的com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor

写完拦截器后记得要放到mybatisPlus的拦截器集合中去。

package com.xxx.xxx.xxx;

import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.ISqlSegment;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.segments.NormalSegmentList;
import com.baomidou.mybatisplus.core.conditions.update.Update;
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
import com.baomidou.mybatisplus.core.mapper.Mapper;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;

import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class MyInnerInterceptor implements InnerInterceptor {


    /**
     *
     * @param executor  Executor(可能是代理对象)
     * @param ms        MappedStatement
     * @param parameter parameter
     * @throws SQLException
     */
    @Override
    public void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {
        SqlCommandType sqlCommandType = ms.getSqlCommandType();
        String msId = ms.getId();

        if(!Objects.equals(SqlCommandType.UPDATE, sqlCommandType)){
            return;
        }

        //更新
        if (parameter instanceof Map) {
            Map<String, Object> map = (Map<String, Object>) parameter;

            //被更新的实体类的对象在mybatis这里都是用et做别名
            Object et = map.getOrDefault("et", null);

            //对应mapper的class
            final String className = getMapperClassName(msId);

            //mapper使用的更新方法
            final String methodName = getMapperMethodName(msId);

            //实体类的class
            Class<?> entityClass = getEntityClass(className);

            //获取实体类的字段信息
            TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);

            //当前实体类的属性集合
            List<TableFieldInfo> fieldList = tableInfo.getFieldList();

            // updateById(et), update(et, wrapper);
            if(Objects.nonNull(et)){

                try {


                    for (TableFieldInfo fieldInfo : fieldList) {

                        //field
                        Field field = fieldInfo.getField();

                        //获取column
                        String column = fieldInfo.getColumn();

                        //旧的value
                        Object oldValue = field.get(et);


                    }



                } catch (IllegalAccessException e) {
                    throw ExceptionUtils.mpe(e);
                }


                // update(LambdaUpdateWrapper) or update(UpdateWrapper)
            }else if (map.entrySet().stream().anyMatch(t -> Objects.equals(t.getKey(), "ew"))) {


                Object ew = map.get("ew");

                if (!(ew instanceof AbstractWrapper && ew instanceof Update)) {
                    return;
                }

                final Map<String, Object> paramNameValuePairs = ((AbstractWrapper<?, ?, ?>) ew).getParamNameValuePairs();


                for (TableFieldInfo fieldInfo : fieldList) {

                    //field
                    Field field = fieldInfo.getField();

                    //获取column
                    String column = fieldInfo.getColumn();


                    Wrapper<?> wrapper = (Wrapper<?>) ew;

                    //查询更新条件中指定的列名对应的值
                    String valueKey = getValueKey(column, wrapper);

                    final Object conditionValue = paramNameValuePairs.get(valueKey);



                }


            }



        }


    }


    /**
     * 查询更新条件中指定的列名对应的值
     * 即查询 where xxx = value 这个条件中的 xxx 对应的 value
     * @param column
     * @param wrapper
     * @return
     */
    private String getValueKey(String column, Wrapper<?> wrapper){
        Pattern pattern = Pattern.compile("#\\{ew\\.paramNameValuePairs\\.(" + "MPGENVAL" + "\\d+)\\}");

        final NormalSegmentList segments = wrapper.getExpression().getNormal();

        String fieldName = null;
        ISqlSegment eq = null;
        String valueKey = null;

        for (ISqlSegment segment : segments) {

            String sqlSegment = segment.getSqlSegment();

                //如果字段已找到并且当前segment为EQ
            if(Objects.nonNull(fieldName) && segment == SqlKeyword.EQ){

                eq = segment;

                //如果EQ找到并且value已找到
            }else if(Objects.nonNull(fieldName) && Objects.nonNull(eq)){

                Matcher matcher = pattern.matcher(sqlSegment);
                if(matcher.matches()){
                    valueKey = matcher.group(1);
                    return valueKey;
                }


                //处理嵌套
            }else if (segment instanceof Wrapper){

                if(null != (valueKey = getValueKey(column, ((Wrapper<?>) segment)))){
                    return valueKey;
                }

                //判断字段是否是要查找字段
            }else if(Objects.equals(column, sqlSegment)){
                fieldName = sqlSegment;
            }

        }

        return valueKey;
    }






    private String getMapperMethodName(String msId){
        return msId.substring(msId.lastIndexOf('.') + 1);
    }

    private String getMapperClassName(String msId){
        return msId.substring(0, msId.lastIndexOf('.'));
    }

    /**
     * 通过mapper上实体类信息获取实体类class
     * @param className
     * @return
     */
    private Class<?> getEntityClass(String className){
        try {
            return ReflectionKit.getSuperClassGenericType(Class.forName(className), Mapper.class, 0);
        } catch (ClassNotFoundException e) {
            throw ExceptionUtils.mpe(e);
        }
    }
}

注册拦截器

@Bean
public MyInnerInterceptor myInnerInterceptor(ApplicationContext applicationContext){
    MyInnerInterceptor myInnerInterceptor = new MyInnerInterceptor();
    MybatisPlusInterceptor bean = applicationContext.getBean(MybatisPlusInterceptor.class);
    bean.addInnerInterceptor(myInnerInterceptor);
    return myInnerInterceptor;
}

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

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

相关文章

VUE中使用element-china-area-data

使用element-china-area-data的中国省市区级联数据编写城市选择器。以下为解决效果图&#xff1a; &#xff08;1&#xff09;安装 npm install element-china-area-data -S &#xff08;2&#xff09;引入 import { regionData, CodeToText, TextToCode } from ‘element-ch…

LDO系列--LDO并联扩容

1、不能简单并联&#xff08;无法电流均衡&#xff09; 两个LDO的内部的带隙基准源(参考电压)&#xff0c;FET的特性&#xff0c;以及误差放大器的噪声不同(如失调电压)&#xff0c;实际LDO输出的目标电压依旧是有差异的。 这就导致了&#xff0c;LDO-High的目标输出电压高一些…

STM32F103基于标准库+I2C SSD1306仿数码管RTC时钟显示

STM32F103基于标准库I2C SSD1306仿数码管RTC时钟显示 ✨申明&#xff1a;本文章仅发表在CSDN网站&#xff0c;任何其他网站&#xff0c;未注明来源&#xff0c;见此内容均为盗链和爬取。 &#x1f341;对于文中所提供的相关资源链接将作不定期更换。 &#x1f4fa;显示效果&a…

UWB芯片DW300之CRC模式介绍及代码实现

SPI CRC模式 当启用SPI CRC模式时,可以为SPI传输提供循环冗余校验序列的额外保护。这种操作模式在默认情况下是禁用的,但可以通过SYS_CFG寄存器中的SPI_CRCEN位启用(和禁用)。 虽然SPI CRC检查在主机微处理器必须为每个SPI写入和读取事务计算CRC的附加软件开销方面有缺点,但…

SOFA Weekly|SOFARPC 5.10.0 版本发布、SOFA 五周年回顾、Layotto 社区会议回顾与预告...

SOFA WEEKLY | 每周精选 筛选每周精华问答&#xff0c;同步开源进展 欢迎留言互动&#xff5e; SOFAStack&#xff08;Scalable Open Financial Architecture Stack&#xff09;是蚂蚁集团自主研发的金融级云原生架构&#xff0c;包含了构建金融级云原生架构所需的各个组件&am…

【Mysql】分库分表

【Mysql】分库分表 文章目录 【Mysql】分库分表1. 介绍2. 拆分策略2.1 垂直拆分2.1.1 垂直分库2.1.2 垂直分表 2.2 水平拆分2.2.1 水平分库2.2.2 水平分表 3. MyCat3.1 概述 1. 介绍 采用单数据库进行数据存储存在以下瓶颈&#xff1a; IO瓶颈&#xff1a;热点数据太多&#x…

项目管理必备!20个实用技巧全掌握!

即使在最完美的条件下&#xff0c;管理一个项目也是很困难的。 ​项目管理的成败好坏与优秀项目团队密不可分的,建设一个好的团队将会更团结、更坚强、更具有竞争力, 更能适应无限变化的环境。 ​不幸的是&#xff0c;还是有很多项目经理实质上没有没有总结出自己思维方法和运…

进程状态

理念上的状态 新建 子面意思运行 task_struct在运行队列中排队&#xff0c;就叫做运行态阻塞 等待非CPU资源就绪挂起 当内存不足的时候&#xff0c;OS通过适当的置换进程的代码和数据到磁盘&#xff0c;进程的状态就叫做挂起退出 子面意思 实际上的状态 …

ARM Coresight 及 DS-5 介绍 5 - DS-5 断点设置及常用Debug 命令

文章目录 1.1 DS-5 Debug 方法梳理1.2.1 DS-5 设置断点 Debug1.2.2 DS-5 常用 Debug 命令 1.1 DS-5 Debug 方法梳理 通常在调试过程中需要打断点来进行单步调试&#xff0c;这个时候可以按照下面步骤来进行&#xff1a; 在使用 DS-5 Debug 之前需要先 load 所编译的 elf 文件&…

【css】使用css实现提示框各种弹出效果。

简言 最近工作编写页面时&#xff0c;需要有一个提示框从下到上弹出的效果。 冥想了一下&#xff0c;实现了出来。 记录下实现思路。 实现思路 实现步骤如下&#xff1a; 编写样式。 首页要有承载内容的容器&#xff08;box)。外层在套一个包装盒子&#xff08;用来进行定位…

超详细的ubuntu安装opencv2.0//test ok

目录 1. 首先确保在Ubuntu上已经安装了cmake和make 1.1 安装make 1.2 安装cmake 2 安装依赖环境 3 下载opencv源码 4 编译源码并安装 4.1 进入opencv源码目录中&#xff0c;新建build文件夹 4.2 进入build文件夹&#xff0c;打开终端使用cmake生成makefile 4.3 安装ope…

Windows环境下实现设计模式——迭代器模式(JAVA版)

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天总结一下Windows环境下如何编程实现迭代器模式&#xff08;设计模式&#xff09;。 不知道大家有没有这样的感觉&#xff0c;看了一大堆编程和设计模式的书&#xff0c;却还是很难理解设计模式&#xff…

轻松掌握k8s的kubectl使用命令行操作Ingress知识点03

1、Ingress将所有Service统一网关入口 底层也是使用了nginx&#xff0c;所以使用Ingress才是整个项目的统一入口。 官网地址&#xff1a;https://kubernetes.github.io/ingress-nginx/ 1、安装 先下载安装文件 wget https://raw.githubusercontent.com/kubernetes/ingress-…

HTB-Tenet

HTB-Tenet 信息收集80端口/users.txt目录/wordpress/wp-login.php tenet.htb 立足www-data -> neilneil -> root 信息收集 80端口 apache 2.4.49存在的exploit。 目录扫描 /users.txt目录 /wordpress/wp-login.php 在Go to Tenet超链接会出现tenet.htb。 添加至hosts再…

【Linux基础IO之 内存文件操作】

目录&#xff1a; 前言一、引入C语言中的文件操作系统文件操作open 位图权限close、write、readlseek C语言中的文件操作函数与系统文件操作函数的联系 三、文件描述符1.文件描述符是什么2.文件缓冲区再谈重定向 四、文件缓冲区分类语言级缓冲区为什么要有两个缓冲区 五、仿写c…

如何选择CDN加速平台?

现如今全球CDN市场规模逐年攀升&#xff0c;在2017年全球CDN市场规模约为75亿美元,到2021年增长到200亿美元左右。我国CDN行业同样保持高速发展,自2017年的135亿元增长到2022年的300亿元左右。但是国内的CDN市场规模仅为全球市场的15%-20%&#xff0c;海外CDN市场空间巨大。 接…

每日学术速递4.21

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Pretrained Language Models as Visual Planners for Human Assistance 标题&#xff1a;预训练语言模型作为人工协助的视觉规划器 作者&#xff1a;Dhruvesh Patel, Hamid Eghbal…

【Linux高性能服务器编程】信号处理方法之统一事件源

目录 为什么要用统一事件源统一事件源的概念统一事件源的应用 为什么要用统一事件源 信号是一种异步事件&#xff1a;信号处理函数和程序的主循环是两条不同的执行路径。即当进程收到信号时&#xff0c;操作系统会中断进程当前的正常流程&#xff0c;转而进入信号处理函数去处…

机器学习笔记 - MediaPipe结合OpenCV分析人体标准运动姿势

一、简述 在之前的文章中,对于MediaPipe进行了初步了解,并对结合OpenCV进行人体姿势估计的技术的处理思路进行看了一些探讨。 https://skydance.blog.csdn.net/article/details/123508782https://skydance.blog.csdn.net/article/details/123508782 这里我们要进行一…

奥艺大会 | 国际奥艺委员会与意大利环境基金会达成合作

4月17日&#xff0c;国际奥艺委员会执行主席Rachel Qin和副秘书长Linda Xu受邀前往意大利环境基金会&#xff08;Fondo Ambiente Italiano&#xff0c;简称FAI&#xff09;&#xff0c;与意大利环境基金会罗马主席Giuseppe Morganti进行会面。 OLYMP’ARTS 2023奥艺大会以“环…