文章目录

  • 自定义MyBatis拦截器
    • 作用
    • MyBatis中的四大核心对象
    • 在mybatis中可被拦截的类型有四种(按照拦截顺序)
    • 拦截器需要实现Mybatis提供的Interceptor接口
    • 利用反射获取运行中的实体字段的名字
    • 利用反射动态的为sql语句传递新参数
    • 使用mybatis自定义的拦截器为插入,更新语句自动赋值的时候的小bug
    • 使用自定义MyBatis拦截器在对数据库进行更新插入的时候动态添加修改人,创建人参数
      • 定义拦截器类
      • 在mybatis的配置文件中声明拦截器
      • 在mapper映射文件中获取拦截器中设置的参数
      • 验证结果
    • MyBatis会把动态代理中所有的接口生成一个map集合以及BeanUtils.setProperty()可以往这个map集合里面动态添加键值对
    • interceptor方法中的invocation对象

自定义MyBatis拦截器

作用

通过拦截器可以拦截四大核心对象中的其中一个,我下文中拦截的是Executor核心对象,然后对这个核心对象的update方法进行了拦截,再结合反射,在每次更新的时候都动态的给sql加上一个更新人操作,在每次插入的时候都动态的给sql加上一个创建人操作。下文中的拦截器主要是在更新或者插入的时候,给sql语句多传递一个参数。
我们还可以通过拦截StatementHandler核心对象修改sql语句,还可以通过拦截其它两个核心对象达到某些目的。但是目前只掌握拦截Executor核心对象给sql语句动态的增加参数就行了。

MyBatis中的四大核心对象

MyBatis中的四大核心对象:Executor,StatementHandler,ParamterHandler,ResultSetHandler

拦截器可以拦截四大核心对象中的其中一个对象,然后对这个对象进行增强,如下图:

2.各个参数的含义:
@Intercepts:标识该类是一个拦截器;
@Signature:指明自定义拦截器需要拦截哪一个类型,哪一个方法;2.1 type:对应四种类型中的一种;2.2 method:对应接口中的哪个方法;2.3 args:对应哪一个方法参数类型(因为可能存在重载方法);

上图中的MyInterceptor拦截器,拦截的就是StatementHandler对象。至于上图中的method的值是什么,那就具体要看你是什么需求了,如下图:

通过args来指定上图中的方法中的参数,如下图:

什么叫做增强呢,就比如现在有一个sql语句,那么它在经过拦截器的时候,拦截器会给这个sql语句在原有的基础上增加一些新的东西,这就叫做增强。

在mybatis中可被拦截的类型有四种(按照拦截顺序)

Executor:拦截执行器的方法。
ParameterHandler:拦截参数的处理。
StatementHandler:拦截Sql语法构建的处理。
ResultHandler:拦截结果集的处理。拦截器顺序
Executor -> ParameterHandler -> StatementHandler -> ResultSetHandler

拦截器需要实现Mybatis提供的Interceptor接口

拦截器通过实现Mybatis提供的Interceptor拦截接口,重写了三个方法:setProperties/plugin/ intercept,三者执行顺序是setProperties—》plugin—》Interceptor。

 setProperties方法:该方法通过设置属性,将核心配置文件configuration.xml文件中对拦截器的配置项下的属性获取过来,便于在拦截器中使用。plugin方法:该方法用来协商,达成协议,把代理权给普通的业务员this,传进wrap方法实现的源码去做代理,没有获取代理权的代理人在这个地方就会停下,不会向下走了,获取代理权的代理人可以去做拦截代理。intercept方法:则是获取拦截对象下的要拦截的东西,然后对其加以改编,添加自己的行为,按照条件进行改编拦截对象,然后通过源码下的反射invocation来调用被拦截的方法,让原本被拦截的方法继续执行(invocation.proceed())。

invocation.proceed()是拦截器是否放行,如果拦截器执行了此句代码,那么表示拦截器要放行,那么我们的动态代理接口可以成功执行,但是如果拦截器中的intercept方法中,没有执行此句代码,那么就表示拦截器没有放行,那么动态代理接口就不可以成功执行;

如果我们在intercept方法中想要放行,直接return invocation.proceed();就可以了。

利用反射获取运行中的实体字段的名字

利用反射获取实体类中的字段的时候,必须要把setAccessible方法的值设置成true,这样在进行访问安全检查的时候才不会抛出异常,要不然利用反射获取实体类中的字段的时候会抛IllegalAccessException异常。

利用反射动态的为sql语句传递新参数

我们如果没有用反射,那么传递给sql语句的参数就是动态代理接口中传递的哪些参数,是不能够更改的,但是如果用上了反射,也就是使用BeanUtils.setProperty(bean,name,value)方法,那么我们会在运行期间,增加新的参数传递给sql语句。我们这里的bean对象是一个Map集合,如下图:


注意上图中的叙述有错误,不是改变一个实体类中的属性,而是往map集合中加一个键值对,bean是一个map集合。

使用mybatis自定义的拦截器为插入,更新语句自动赋值的时候的小bug

mapper映射文件中,从拦截器中取值的参数,一定要和拦截器中自动设置的参数保持一致,要不然的话是取不到拦截器中的值的,如下图:

update修改的时候,我们传递的goodsDO并没有modifyMan字段的值,但是因为有拦截器自动添加了modifyMan字段,所以数据库中的值会被自动插入,如下图:

使用自定义MyBatis拦截器在对数据库进行更新插入的时候动态添加修改人,创建人参数

定义拦截器类

如下图:

/*** @Date 2022/1/29 17:42* @Author 望轩*/
@Intercepts({@Signature(type = Executor.class ,method = "update",args={MappedStatement.class,Object.class})
})
public class MyInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {//invocation.getArgs()得到的结果就是args中的参数,第一个元素肯定是MappedStatement,第二个元素是我们传递给sql语句的参数//如果没有传递则只能得到一个元素,也就是invocation.getArgs().length的长度是1//如果相关的动态代理接口没有传递参数,则我们不需要对传递给sql语句的参数进行处理,直接放行动态代理接口方法if(invocation.getArgs().length == 1){//只要执行了invocation.proceed()方法才会对动态代理接口进行放行,否则动态代理接口不会执行return invocation.proceed();}//获取动态代理接口传递给sql语句的参数实体Object parameter = invocation.getArgs()[1];System.out.println(parameter);//获取Sql语句的类型,也即是Sql语句是增删改查中的哪一个MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();//修改人或者是创建人String man = "";if(sqlCommandType.equals(SqlCommandType.INSERT)){man = "createMan";}if(sqlCommandType.equals(SqlCommandType.UPDATE)){man = "modifyMan";}//通过反射获取我们传递给sql语句也即是动态代理接口中的实体属性Field[] fields = GoodsDO.class.getDeclaredFields();for(Field field : fields){//安全性访问检查:设置为truefield.setAccessible(true);String fieldName = field.getName();if(fieldName.equals(man)){BeanUtils.setProperty(parameter,man,"wangxuan");System.out.println(parameter);}}return invocation.proceed();}@Overridepublic Object plugin(Object target) {//plugin方法主要是将拦截器中定义的增强功能(也就是拦截器)和原来的核心对象合并起来,成为最终的核心对象wrap,然后把这个对象返回Object wrap = Plugin.wrap(target, this);return wrap;}@Overridepublic void setProperties(Properties properties) {//这个方法里面可以取出来我们mybatis的配置文件中插件中配置的属性}}

在mybatis的配置文件中声明拦截器

在mapper映射文件中获取拦截器中设置的参数

验证结果

MyBatis会把动态代理中所有的接口生成一个map集合以及BeanUtils.setProperty()可以往这个map集合里面动态添加键值对

当MyBatis底层在处理动态代理接口中的参数的时候,会把动态代理接口中的参数处理成一个map集合。

如果动态代理接口中没有使用@Param注解。假设某个动态代理接口inter1(Object A,Object B,Object C),那么Mybatis最终会处理成Map{A:A(),B:B(),C:C(),param1:A(),param2:B(),param3:C()};我们在mapper的xml映射文件中,可以通过#{A}获取参数,也可以通过#{param1}获取参数。

**如果动态代理接口中使用了@Param注解。**假设某个动态代理接口inter2(@Param(“variable1”) Object A,@Param(“variable2”) Object B,@Param(“variable3”) Object C),那么MyBatis最终会处理成Map{“variable1”:A(),“variable2”:B(),“variable3”:C()}的形式。

interceptor方法中的invocation对象

Invocation对象可以通过反射调度获取到拦截的某个核心对象的具体内容,比如说拦截的核心对象的名字,拦截的核心对象的方法,传递给核心对象的这个方法的参数,这些参数包括动态代理接口中传递给sql语句的参数。总之我们可以通过invocation这个对象通过反射调度,获取到sql语句的全部信息。

拦截器其实拦截的是四大核心对象中的某个方法,如果它拦截这个方法不放行,对应的动态代理接口,它就过不去,所以就不能执行sql语句;只要当拦截器放行了,动态代理接口才会执行。
invocation.proceed()是拦截器是否放行,如果拦截器执行了此句代码,那么表示拦截器要放行,那么我们的动态代理接口可以成功执行,但是如果拦截器中的intercept方法中,没有执行此句代码,那么就表示拦截器没有放行,那么动态代理接口就不可以成功执行;

如果我们在intercept方法中想要放行,直接return invocation.proceed();就可以了。

自定义MyBatis拦截器相关推荐

  1. Springboot 自定义mybatis 拦截器,实现我们要的扩展

    前言 相信大家对拦截器并不陌生,对mybatis也不陌生. 有用过pagehelper的,那么对mybatis拦截器也不陌生了,按照使用的规则触发sql拦截,帮我们自动添加分页参数 . 那么今天,我们 ...

  2. 自定义 MyBatis 拦截器

    1.自定义拦截器类,实现 Interceptor 接口 @Intercepts({@Signature(type = StatementHandler.class,method = "pre ...

  3. SpringBoot2整合Mybatis拦截器,拦截mapper接口的某个方法

    需求: 在执行某个动态sql时,where 子句,希望通过用户进行自定义查询条件,比如用户可以传入 "id > 100011 and name = '张三'" 的多条件表达式 ...

  4. Mybatis自定义SQL拦截器

    本博客介绍的是继承Mybatis提供的Interface接口,自定义拦截器,然后将项目中的sql拦截一下,打印到控制台. 先自定义一个拦截器 package com.muses.taoshop.com ...

  5. by mybatis 自定义order_springboot2结合mybatis拦截器实现主键自动生成

    点击上方蓝字关注我们 1 01 前言 前阵子和朋友聊天,他说他们项目有个需求,要实现主键自动生成,不想每次新增的时候,都手动设置主键.于是我就问他,那你们数据库表设置主键自动递增不就得了.他的回答是他 ...

  6. list mybatis 接收 类型_基于mybatis拦截器实现的一款简易影子表自动切换插件

    近期因工作需要,小编基于mybatis拦截器开发了一款简易影子表自动切换插件,可以根据配置实现动态修改表名,即将对原source table表的操作自动切换到对target table表的操作.该插件 ...

  7. 犯罪心理解读Mybatis拦截器

    原文链接:"犯罪心理"解读Mybatis拦截器 Mybatis拦截器执行过程解析 文章写过之后,我觉得 "Mybatis 拦截器案件"背后一定还隐藏着某种设计动 ...

  8. insert into select 主键自增_springboot2结合mybatis拦截器实现主键自动生成

    点击上方蓝字关注我们 1 01 前言 前阵子和朋友聊天,他说他们项目有个需求,要实现主键自动生成,不想每次新增的时候,都手动设置主键.于是我就问他,那你们数据库表设置主键自动递增不就得了.他的回答是他 ...

  9. Mybatis 拦截器介绍

    Mybatis 拦截器介绍 1.1 目录 1.2 前言 1.3 Interceptor接口 1.4 注册拦截器 1.5 Mybatis可拦截的方法 1.6 利用拦截器进行分页 拦截器的一个作用就是我们 ...

  10. mysql拦截器实现crud_Mybatis自定义SQL拦截器

    本博客介绍的是继承Mybatis提供的Interface接口,自定义拦截器,然后将项目中的sql拦截一下,打印到控制台. 先自定义一个拦截器 package com.muses.taoshop.com ...

最新文章

  1. 视觉里程计 | 关于Stereo DSO中的高斯牛顿的一点注释
  2. windows 2008 r2 系统默认80端口被系统占用的处理
  3. elementUI的DatePicker+DateTimePicker组件的自定义日期禁用
  4. java分割汉字_Java分割中英文,并且中文不能分割一半?
  5. python中pip的安装与使用
  6. html5number最小值,JavaScript Number(数字)
  7. 腾讯音乐娱乐集团宣布管理层调整,着眼长远战略发展与行业生态布局
  8. 数据结构上机实践第11周项目2 - 操作用邻接表存储的图
  9. Java 员工信息管理系统
  10. python与或非运算规则_Python逻辑运算符之与或非
  11. 如何从本地硬盘启动计算机,解密:如何在计算机BIOS中设置硬盘启动
  12. iOS 各版本系统占比
  13. 年产3000吨冲压型果味硬糖生产车间工艺设计
  14. WC2017 Day3
  15. GSAP,专业的Web动画库
  16. Python——保存图片到本地
  17. 给浏览器升个级,5款必备浏览器插件推荐
  18. 超静音服务器性能强,静音服务器:最适合办公环境的静音服务器
  19. 使用woo 语言开发 sockets4 sockets5 http https代理完整记录
  20. Android ImageView.setVisibility(GONE)不生效

热门文章

  1. 数学建模教程:CBA-基于关联规则的分类算法
  2. Windows8.1-KB2999226-x64安装提示 此更新不适用你的计算机
  3. 如何分辨usb压枪芯片是无后座压枪还是键鼠模拟压枪
  4. 2020-6 android kernel vulnerability
  5. 桌面太单调?一起用Python做个自定义动态壁纸,竟然还可以放视频!
  6. Windows下安装Redis图文教程
  7. 基于蚁群算法的二维路径规划算法
  8. NoteExpress 3.2下载
  9. 【数学建模】相关性分析 - 皮尔逊相关系数 斯皮尔曼相关系数
  10. 小米手机怎么复制加密门禁卡_使用小米手机复制加密门禁卡的方法