Mybatis-plus 怎么使用拦截器拿到SQL,并解析

1、自定义拦截器



import cn.hutool.json.JSONUtil;
import com.mqtt.common.CacheDev;
import com.mqtt.common.CacheMQ;
import com.mqtt.entity.log.DevLog;
import com.mqtt.service.DevLogService;
import com.mqtt.util.JsonUtils;
import com.mqtt.util.SQLParseUtils;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.defaults.DefaultSqlSession;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.Properties;

@Intercepts({
    @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class OperationLogInterceptor implements Interceptor{




    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];

        Object parameter = invocation.getArgs()[1];

        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        //sql
        String sql = boundSql.getSql();
        //获取表名
        String tableName = SQLParseUtils.getTableName(sql);
        if (tableName==null){
            throw new Exception("表名解析失败");
        }


        //如果是日志,就放行,不用加日志
        if (tableName.equalsIgnoreCase("DevLog")){
            return invocation.proceed();
        }


        long start =System.currentTimeMillis();
        // 执行 SQL 操作
        Object result = invocation.proceed();

        long end =System.currentTimeMillis();





        //参数
        String param = JsonUtils.getJson(parameter);
        System.out.println("json:    "+param);

        //判断sql类型
        String sqlType = SQLParseUtils.parseSQLType(sql);

        if (sqlType==null){
            throw new Exception("日志SQL解析失败");
        }



        sql= sql.replaceAll("\n", "");




        Date createTime =new Date();

        Long executeTime=end-start;


        DevLog devLog = new DevLog(null, tableName, sqlType, sql, param, executeTime, createTime);
        System.out.println("devLog:"+devLog);


        boolean offer = CacheMQ.logQueue.offer(devLog);
        if (offer){
            System.out.println("成功放入队列,异步执行日志存入数据库");
        }



        return result;
    }

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

    @Override
    public void setProperties(Properties properties) {
        // 可以在此处配置插件的属性
    }


//    @Override
//    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//        OperationLogInterceptor.applicationContext=applicationContext;
//        OperationLogInterceptor.devLogService=applicationContext.getBean(DevLogService.class);
//
//    }




}

2、mybatis-config.xml配置文件

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration 核心配置文件-->
<configuration>
    <!-- 配置拦截器 -->
    <plugins>
        <plugin interceptor="com.tigeriot.mqtt.config.mybatis.OperationLogInterceptor">
            <!-- 可以在此处配置插件的属性 -->
        </plugin>
    </plugins>

</configuration>

3、springboot配置 这个 mybatis-config.xml

mybatis-plus:
  configLocation: classpath:mybatis/mybatis-config.xml

4、SQL工具类


import cn.hutool.json.JSONUtil;

import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class SQLParseUtils {



    public static String parseSQLType(String sql){
        if (sql==null){
            return null;
        }

        String type = sql.split(" ")[0];
       if (type.equalsIgnoreCase("INSERT")){
           return "INSERT";
       } else if (type.equalsIgnoreCase("UPDATE")) {
           return "UPDATE";
       } else if (type.equalsIgnoreCase("DELETE")) {
           return "DELETE";
       }else {
           return null;
       }

    }


    public static String getTableName(String sql) {
        String tableName = null;

        // 正则表达式匹配 INSERT、UPDATE 和 DELETE 语句
        String regex = "(?i)(?:INSERT\\s+INTO|UPDATE|DELETE\\s+FROM)\\s+(\\w+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(sql.trim());

        if (matcher.find()) {
            tableName = matcher.group(1);
        }

        return tableName;
    }


    public static String getParam(String json,String type) throws Exception {
//        try {
//            if (type.equalsIgnoreCase("INSERT")){
//
//
//
//            } else if (type.equalsIgnoreCase("UPDATE")) {
//                Map bean = JSONUtil.parseObj(json).toBean(Map.class);
//                Map<String,Object> o = (Map<String, Object>) bean.get("ew");
//                Object o1 = o.get("sqlSet");
//                return   JsonUtils.getJson(o1);
//
//
//            }else if (type.equalsIgnoreCase("DELETE")){
//                Map bean = JSONUtil.parseObj(json).toBean(Map.class);
//                Map<String,Object> o = (Map<String, Object>) bean.get("ew");
//                Object o1 = o.get("paramNameValuePairs");
//                return   JsonUtils.getJson(o1);
//
//
//            }else {
//               throw new Exception("type不合法");
//            }
//        } catch (Exception e) {
//            System.out.println(e.getMessage());
//            return null;
//        }

        return null;

    }




    public static void main(String[] args) {
        String tableName = getTableName("INSERT INTO orders (customer_id, product_id, quantity) VALUES (789, 123, 5)");
        System.out.println(tableName);
    }

}

<think>嗯,用户问的是MyBatis-Plus拦截器为什么拦截不到内置的getById方法。首先,我需要回想一下MyBatisMyBatis-Plus的拦截机制有什么不同。MyBatis拦截器通常是基于Executor接口的,而MyBatis-Plus可能用了自己的实现或者扩展了某些方法。 用户之前已经了解过如何在Spring Boot中配置MyBatisSQL拦截器,现在遇到的是MyBatis-Plus特有的问题。可能他们按照之前的做法配置了拦截器,但是发现像getById这样的内置方法没有被拦截到。这时候需要分析MyBatis-Plus的工作机制。 首先,MyBatis-Plus的BaseMapper中的方法,比如selectById,实际上可能会调用MyBatis的底层方法,但可能使用了不同的接口或者代理方式。例如,getById可能最终会调用到MyBatis的selectOne或者selectList方法,这取决于具体的实现。如果拦截器只拦截了Executor的update和query方法,可能需要检查这些方法是否被正确覆盖。 另外,MyBatis-Plus可能对Executor进行了包装或者使用了自定义的组件,比如自己的SqlSession,这可能导致传统的拦截点失效。这时候需要找到正确的拦截点,可能不是Executor,而是其他接口,比如StatementHandler或者ParameterHandler。 还有可能是拦截器的@Signature配置不正确,比如方法名或参数类型不匹配。比如,getById方法可能对应的底层MyBatis方法是query,但参数类型可能有变化,或者方法名不同,需要具体查看MyBatis-Plus的源码。 另外,用户可能需要确认拦截器是否正确注册到了MyBatis的配置中。在MyBatis-Plus中,可能需要通过特定的配置类或者使用MyBatis-Plus的配置方式来添加拦截器,而不是传统的MyBatis配置方式。例如,使用MybatisPlusInterceptor这个类来添加插件,而不是直接使用addInterceptor方法。 还可能存在多个拦截器的执行顺序问题,或者拦截器被其他拦截器覆盖了。需要检查是否有其他拦截器影响了当前拦截器的执行。 最后,建议用户通过调试或者日志来确认拦截器是否被加载,以及具体的拦截点是否被触发。可能需要查看MyBatis-Plus生成的SQL语句对应的MappedStatement,确认其ID是否正确,以及拦截器是否针对了正确的方法和参数类型。</think>在MyBatis-Plus中拦截不到内置的`getById`方法,通常是由于以下原因及解决方案: --- ### 一、核心原因分析 1. **方法调用链路差异** MyBatis-Plus的`getById`方法底层实际调用的是`selectById`,而该方法是通过`SqlSessionTemplate`执行的,可能绕过了标准MyBatis拦截点 2. **拦截器签名不匹配** MyBatis-Plus的CRUD方法可能使用`SELECT_ONE`或`SELECT_LIST`类型的SQL命令,需要调整拦截的目标方法 3. **自动生成的SQL差异** 内置方法可能使用`SqlMethod`生成的SQL,与自定义SQL的执行路径不同 --- ### 二、正确配置方式 #### 1. 使用MyBatis-Plus原生拦截器接口 ```java @Configuration public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new InnerInterceptor() { @Override public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { System.out.println("拦截到查询操作:" + ms.getId()); } }); return interceptor; } } ``` #### 2. 精确指定拦截方法(传统MyBatis方式) ```java @Intercepts({ @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}) }) public class CustomInterceptor implements Interceptor { // 实现逻辑 } ``` --- ### 三、验证步骤 1. 打印被拦截的SQL ID: ```java System.out.println("拦截SQL ID: " + ms.getId()); ``` 2. 观察控制台输出,确认是否出现类似`com.baomidou.mybatisplus.core.mapper.BaseMapper.selectById`的语句 --- ### 四、特殊场景解决方案 如果仍无法拦截,可尝试以下方式: ```java // 在拦截器中添加对StatementHandler的拦截 @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}) }) public class StatementInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler handler = (StatementHandler) invocation.getTarget(); BoundSql boundSql = handler.getBoundSql(); System.out.println("最终执行SQL: " + boundSql.getSql()); return invocation.proceed(); } } ``` --- ### 五、原理示意图 ``` MyBatis-Plus CRUD方法 ↓ SqlSessionTemplate ↓ MyBatis-Plus执行器(自动生成SQL) ↓ DefaultSqlSession ↓ Executor (需在此层拦截) ``` --- ### 六、注意事项 1. 优先使用MyBatis-Plus提供的`InnerInterceptor`体系 2. 避免与分页插件等内置拦截器冲突 3. 通过`@MapperScan`确保Mapper接口被正确扫描 4. 检查是否有多个拦截器相互覆盖的情况 通过上述配置可以成功拦截到`getById`等内置方法的SQL执行过程,实际开发中建议结合具体需求选择拦截层级。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值