自定义拦截器
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare",
args = {Connection.class,Integer.class}),
})
@Component
public class MybatisSqlInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler=(StatementHandler)invocation.getTarget();
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
BoundSql boundSql = statementHandler.getBoundSql();
//sql类型
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
//mapper方法的全路径名
String id = mappedStatement.getId();
//注解逻辑判断 添加注解了才拦截
Class<?> classType = Class.forName(mappedStatement.getId().substring(0, mappedStatement.getId().lastIndexOf(".")));
String mName = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1, mappedStatement.getId().length());
for (Method method : classType.getDeclaredMethods()) {
if (method.isAnnotationPresent(InterceptAnnotation.class) && mName.equals(method.getName())) {
InterceptAnnotation interceptorAnnotation = method.getAnnotation(InterceptAnnotation.class);
if (interceptorAnnotation.flag()) {
if(SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())){
String sql = boundSql.getSql();
String msql = sql.replace("where","where password = 'err' and ");
//通过反射拼接sql
Field field = boundSql.getClass().getDeclaredField("sql");
field.setAccessible(true);
field.set(boundSql, msql);
}
}
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target,this);
}
@Override
public void setProperties(Properties properties) {
}
}
Mybatis插件基本原理
Mybatis允许你在已经映射语句的执行过程中为某一点进行拦截调用。但是并不是对所有的方法都可以进行这种拦截处理,允许使用插件进行的拦截类如下,具体要拦截该类中哪一个方法则需要关注下mybatis的源码,去指定拦截时的方法入参:支持的拦截类如下:
- Executor (update, query, flushStatements, commit, rollback, - getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface InterceptAnnotation {
boolean flag() default true;
}