zoukankan      html  css  js  c++  java
  • 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
    @Configuration
    public 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连接工厂类
     * */
    @Configuration
    public 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();
        }
    }
  • 相关阅读:
    window端口被占用
    webstorm中关闭烦人Eslint语法检查
    STM32 printf 函数原型
    Memset、Memcpy、Strcpy 的作用和区别(转)
    SMD贴片元件的封装尺寸(转)
    Windows Phone开发工具初体验(转载)
    Open Cell(转载)
    标题:常用贴片元件封装(转载)
    关于TV Dongle的功能设计和思考【图】(转载)
    图片预览加上传遇到的一系列问题
  • 原文地址:https://www.cnblogs.com/Mr-lin66/p/13218467.html
Copyright © 2011-2022 走看看