spring boot Mybatis 拦截器,实现拼接sql和修改

定义一个 SqlIntercepor 类

复制代码
import com.culturalCenter.placeManage.globalConfig.Interface.InterceptAnnotation;import org.apache.ibatis.executor.statement.StatementHandler;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.plugin.*;import org.apache.ibatis.reflection.DefaultReflectorFactory;import org.apache.ibatis.reflection.MetaObject;import org.apache.ibatis.reflection.SystemMetaObject;import org.apache.ibatis.session.ResultHandler;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.context.annotation.Configuration;import org.springframework.stereotype.Component;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.sql.Statement;import java.util.Properties;

@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
        @Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
        @Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})})
@Component
@Configurationpublic class SqlInterceptor implements Interceptor {    private Logger logger = LoggerFactory.getLogger(SqlInterceptor.class);

    @Override    public Object intercept(Invocation invocation) throws Throwable {

        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());        //先拦截到RoutingStatementHandler,里面有个StatementHandler类型的delegate变量,其实现类是BaseStatementHandler,然后就到BaseStatementHandler的成员变量mappedStatement
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");        //id为执行的mapper方法的全路径名,如com.uv.dao.UserMapper.insertUser
        String id = mappedStatement.getId();
        logger.info("拦截到当前请求方法的全路径名为--->:  " + id);        //sql语句类型 select、delete、insert、update
        String sqlCommandType = mappedStatement.getSqlCommandType().toString();
        BoundSql boundSql = statementHandler.getBoundSql();        //获取到原始sql语句
        String sql = boundSql.getSql();
        String mSql = sql;        //获取参数
        Object parameter = statementHandler.getParameterHandler().getParameterObject();
        logger.info("拦截到当前请求SQL为--->: " + sql + "<------------>请求类型为:  " + sqlCommandType);
        logger.info("拦截到当前请求参数为--->: " + parameter);        //TODO 修改位置        //注解逻辑判断  添加注解了才拦截//InterceptAnnotation
        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()) {
                    mSql = sql + " limit 2";
                }
            }
        }        //通过反射修改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, new SqlInterceptor());
    }

    @Override    public void setProperties(Properties properties) {//        this.setProperties(properties);
    }
复制代码

 

自定义一个注解类实现局部处理SQL修改 

InterceptAnnotation
复制代码
import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/**
 * 配合SqlInterceptor实现局部拦截
 * */@Target({ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)public @interface InterceptAnnotation {    boolean flag() default  true;
}
复制代码

 

 

自定义数据源工厂类

SqlSessionFactoryConfig
复制代码
package com.culturalCenter.placeManage.globalConfig;import com.alibaba.druid.pool.DruidDataSource;import org.apache.ibatis.plugin.Interceptor;import org.apache.ibatis.session.SqlSessionFactory;import org.mybatis.spring.SqlSessionFactoryBean;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import org.springframework.core.io.Resource;import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.sql.DataSource;/**
 * @author wulincheng
 * @Date 2020年6月23日18:25:22
 *  创建SQL连接工厂类
 * */@Configurationpublic class SqlSessionFactoryConfig {
    @javax.annotation.Resource
    DruidDataSource dataSource;    /**
     * @Autowired SqlSessionFactory sqlSessionFactory;
     * SqlSession session = sqlSessionFactory.openSession();
     * //创建sqlMapper
     * SqlMapper sqlMapper = new SqlMapper(session);     */

    @Bean
    @Primary    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);//更多参数请自行注入
        bean.setPlugins(new Interceptor[]{new SqlInterceptor()});
        Resource[] resources = new PathMatchingResourcePatternResolver()
                .getResources("classpath*:mapper/*.xml");
        bean.setMapperLocations(resources);        return bean.getObject();
    }
}
复制代码


本文作者:admin

本文链接:https://www.javalc.com/post/3.html

版权声明:本篇文章于2020-09-10,由admin发表,转载请注明出处:分享你我。如有疑问,请联系我们

发表评论

取消
扫码支持