14.mybatis拦截器原理

mybatis拦截器介绍

MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用,默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

1.Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) 拦截执行器的方法

2.ParameterHandler (getParameterObject, setParameters) 拦截参数的处理

2.ResultSetHandler (handleResultSets, handleOutputParameters) 拦截结果集的处理

4.StatementHandler (prepare, parameterize, batch, update, query) 拦截Sql语法和会话构建的处理

执行过程中按照Executor => StatementHandler => ParameterHandler => ResultSetHandler。

Executor在执行过程中会创建StatementHandler,在创建StatementHandler过程中会创建 ParameterHandler和ResultSetHandler。

StatementHandler改写sql 实现分页插件

ParameterHandler 改写拦截参数的处理

ResultSetHandler 数据结果 数据库结果二次加密返回客户端

Executor

StatementHandler

ParameterHandler

ResultSetHandler

mybatis拦截器应用场景

拦截器一般在业务处理中用于:

1.分页查询

2.对返回结果,过滤掉审计字段,敏感字段

3.对返回结果中的加密数据进行解密

4.对新增数据自动添加创建人,创建时间,更新时间,更新人 ,对更新数据自动新增更新时间,更新人

mybatis拦截器实现分页

package com.mayikt.config;

import lombok.extern.slf4j.Slf4j;
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.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;

/**
* 拦截Sql语法和会话构建的处理
*/
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare",
                        args = {Connection.class, Integer.class}),
            })
@Component
@Slf4j
public class MybatisSqlInterceptor implements Interceptor {
    @Value("${mayikt.pagehelper.rule}")
    private String pagehelperRule;
    
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        log.info("<mayikt limit>");
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        //sql类型
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        switch (sqlCommandType) {
                // 判断sql语句是为查询类型
            case SELECT:
                extendLimit(statementHandler);
                break;
        }
        
        
        return invocation.proceed();
    }
    
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
    
    
    @Override
    public void setProperties(Properties properties) {
        
    }
    
    /**
    * 对sql实现 修改  加上limit
    */
    private void extendLimit(StatementHandler statementHandler) throws NoSuchFieldException, IllegalAccessException {
        // 获取到原生sql语句
        BoundSql boundSql = statementHandler.getBoundSql();
        Class<? extends BoundSql> aClass = boundSql.getClass();
        // 使用反射机制修改原生sqk语句
        Field sql = aClass.getDeclaredField("sql");
        sql.setAccessible(true);
        String oldSqlStr = boundSql.getSql();
        // 后面加上 limit
        sql.set(boundSql, oldSqlStr + "   " + pagehelperRule);
    }
    
    
}
mayikt:
  pagehelper:
   rule: limit 2

mybatis拦截器自动添加创建时间,更新时间

package com.mayikt.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
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.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.util.Date;
import java.util.Properties;

@Intercepts({
        @Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class)
})
@Slf4j
@Component
public class ParamInterceptor implements Interceptor {


    private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
    private static final ReflectorFactory REFLECTOR_FACTORY = new DefaultReflectorFactory();

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        log.info("<mayikt ParamInterceptor>");
        // 获取拦截器拦截的设置参数对象DefaultParameterHandler
        ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();

        // 通过mybatis的反射来获取对应的值
        MetaObject metaResultSetHandler = MetaObject.forObject(parameterHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, REFLECTOR_FACTORY);
        MappedStatement mappedStatement = (MappedStatement) metaResultSetHandler.getValue("mappedStatement");
        Object parameterObject = metaResultSetHandler.getValue("parameterObject");
        //sql类型
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        // 回写parameterObject对象
        metaResultSetHandler.setValue("parameterObject", updateInsertParam(sqlCommandType, parameterObject));
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }

    private Object updateInsertParam(SqlCommandType sqlCommandType, Object parameterObject) throws NoSuchFieldException, IllegalAccessException {
        Class<?> aClass = parameterObject.getClass();
        switch (sqlCommandType) {
            case INSERT:
                // 使用反射获取到createDatetime修改时间为当前系统时间
                Field createDatetime = aClass.getSuperclass().getDeclaredField("createDatetime");
                createDatetime.setAccessible(true);
                createDatetime.set(parameterObject, new Date());
            case UPDATE:
                //updateDatetime字段 修改时间为当前系统时间
                Field updateDatetime = aClass.getSuperclass().getDeclaredField("updateDatetime");
                updateDatetime.setAccessible(true);
                updateDatetime.set(parameterObject, new Date());
                break;
        }
        return parameterObject;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值