mybatis拦截器
一、mybatis拦截器是什么
mybatis拦截器顾名思义就是一个mybatis的拦截器,在mybatis内部维护了一个拦截器链,和spring拦截器链相似,采用责任链模式进行操作,他的作用就是可以干扰mybatis的执行流程,可以做到向spring的aop那样子去更改拦截mybatis的sql或者执行流程,
Mybatis拦截器并不是每个对象里面的方法都可以被拦截的。Mybatis拦截器只能拦截Executor、ParameterHandler、StatementHandler、ResultSetHandler四个对象里面的方法。
二、怎么玩
直接上个例子吧,用mybatis拦截器拦截StatementHandler,获取
sql,如果是全局查询的sql则直接返回null,防止全表查询内存溢出
首先,写个拦截器
package com.jlpay.micro.merch.framework.config.log;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
import com.alibaba.fastjson.JSON;
import com.jlpay.commons3.exception.ExceptionCode;
import com.jlpay.commons3.exception.JlpayException;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
/**
* @Author: zzx
* @Time 2020/12/19 13:46
* @Description:
*/
@Intercepts({
@Signature(method = "prepare", type = StatementHandler.class, args = {Connection.class,Integer.class})
})
public class ExamplePlugin implements Interceptor {
//拦截器的逻辑就写在这里,invocation.proceed()相当于责任链继续往下
@Override
public Object intercept(Invocation invocation) throws Throwable {
RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(handler, "delegate");
BoundSql boundSql = delegate.getBoundSql();
System.out.println("------------------------------------------------"+ JSON.toJSONString(boundSql.getSql()));
//这里的逻辑就不写了,就是用你的方法去判断怎样的sql不能执行
if (true){throw new Exception(ExceptionCode.NO_RECORD,"非法sql");}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
private static class ReflectUtil {
/**
* 利用反射获取指定对象的指定属性
* @param obj 目标对象
* @param fieldName 目标属性
* @return 目标属性的值
*/
public static Object getFieldValue(Object obj, String fieldName) {
Object result = null;
Field field = ReflectUtil.getField(obj, fieldName);
if (field != null) {
field.setAccessible(true);
try {
result = field.get(obj);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return result;
}
/**
* 利用反射获取指定对象里面的指定属性
* @param obj 目标对象
* @param fieldName 目标属性
* @return 目标字段
*/
private static Field getField(Object obj, String fieldName) {
Field field = null;
for (Class<?> clazz=obj.getClass(); clazz != Object.class; clazz=clazz.getSuperclass()) {
try {
field = clazz.getDeclaredField(fieldName);
break;
} catch (NoSuchFieldException e) {
//这里不用做处理,子类没有该字段可能对应的父类有,都没有就返回null。
}
}
return field;
}
/**
* 利用反射设置指定对象的指定属性为指定的值
* @param obj 目标对象
* @param fieldName 目标属性
* @param fieldValue 目标值
*/
public static void setFieldValue(Object obj, String fieldName,
String fieldValue) {
Field field = ReflectUtil.getField(obj, fieldName);
if (field != null) {
try {
field.setAccessible(true);
field.set(obj, fieldValue);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
第二步,将拦截器加入到mybatis的拦截器链
在mybatis的配置文件(一般是mybatis-config.xml)里加入
<configuration>
<plugins>
<plugin interceptor="com.jlpay.micro.merch.framework.config.log.ExamplePlugin" />
</plugins>
</configuration>