自定义MyBatis拦截器
Posted 杀手不太冷!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义MyBatis拦截器相关的知识,希望对你有一定的参考价值。
文章目录
自定义MyBatis拦截器
作用
MyBatis拦截器的主要作用是在不改变原有逻辑的基础上,对我们的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语句。如下图:
使用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
@Override
public 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)
//安全性访问检查:设置为true
field.setAccessible(true);
String fieldName = field.getName();
if(fieldName.equals(man))
BeanUtils.setProperty(parameter,man,"wangxuan");
System.out.println(parameter);
return invocation.proceed();
@Override
public Object plugin(Object target)
//plugin方法主要是将拦截器中定义的增强功能(也就是拦截器)和原来的核心对象合并起来,成为最终的核心对象wrap,然后把这个对象返回
Object wrap = Plugin.wrap(target, this);
return wrap;
@Override
public void setProperties(Properties properties)
//这个方法里面可以取出来我们mybatis的配置文件中插件中配置的属性
在mybatis的配置文件中声明拦截器
在mapper映射文件中获取拦截器中设置的参数
验证结果
以上是关于自定义MyBatis拦截器的主要内容,如果未能解决你的问题,请参考以下文章
使用Mybatis自定义拦截器处理CreateBy,UpdateBy审计数据的填充