mybatisPlus拦截sql失败----已解决

1. 在使用MybatisPlusInterceptor想对数据权限做限制,但是发现使用寻常的配置,在执行sql后也不会被拦截 代码如下:

@Configuration public class MybatisPlusConfig { public MybatisPlusInterceptor setMybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new DataPermissionInterceptor(new MyDataPermissionHandler())); return interceptor; }
}

执行sql语句后拦截器没有反应

@Slf4j
public class MyDataPermissionHandler implements DataPermissionHandler {

    @Override
    @SneakyThrows
    public Expression getSqlSegment(Expression where, String mappedStatementId) {
        // 超级管理员不受数据权限控制

        Class<?> clazz = Class.forName(mappedStatementId.substring(0, mappedStatementId.lastIndexOf(StringPool.DOT)));
        String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(StringPool.DOT) + 1);
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            DataPermission annotation = method.getAnnotation(DataPermission.class);
            if (ObjectUtils.isNotEmpty(annotation)
                    && (method.getName().equals(methodName) || (method.getName() + "_COUNT").equals(methodName))) {

                return dataScopeFilter(annotation.dataScope(), annotation.deptAlias(), annotation.deptIdColumnName(), annotation.userAlias(), annotation.userIdColumnName(), where);
            }
        }
        return where;
    }


    /**
     * 构建过滤条件
     *
     * @param where 当前查询条件
     * @return 构建后查询条件
     */
    @SneakyThrows
    public static Expression dataScopeFilter(DataPermissionEnum dataScopeEnum, String deptAlias, String deptIdColumnName, String userAlias, String userIdColumnName, Expression where) {


        String deptColumnName = StrUtil.isNotBlank(deptAlias) ? (deptAlias + StringPool.DOT + deptIdColumnName) : deptIdColumnName;
        String userColumnName = StrUtil.isNotBlank(userAlias) ? (userAlias + StringPool.DOT + userIdColumnName) : userIdColumnName;

        TspUserInfo tspUserInfo = ThreadContext.getSubject();
        if (dataScopeEnum == null) {
            String dataPermission = tspUserInfo.getDataPermission();
            // 获取当前用户的数据权限
            dataScopeEnum = DataPermissionEnum.getByCode(dataPermission);
        }

        //部门ID 包含多个部门,同一个用户的部门来源于用户组
        String orgCode = tspUserInfo.getOrgCode();
        String userId = tspUserInfo.getUserId();
        String acctOrgCode = tspUserInfo.getAcctOrgCode();
        List<String> dataPermissionOrgCodes = tspUserInfo.getDataPermissionOrgCodes();
        String appendSqlStr;
        switch (Objects.requireNonNull(dataScopeEnum)) {
            case Org:
//                appendSqlStr = deptColumnName + " in (" + orgCode + ")";
                appendSqlStr = deptColumnName + StringPool.EQUALS + orgCode;
                break;
            case Personal:
                appendSqlStr = userColumnName + StringPool.EQUALS + userId;
                break;
            case AcctOrg:
                appendSqlStr = userColumnName + StringPool.EQUALS + acctOrgCode;
                break;
            // 默认部门及子部门数据权限
            default:
                appendSqlStr = deptColumnName + " in (" + String.join(",", dataPermissionOrgCodes) + ")";
                break;
        }


        if (StrUtil.isBlank(appendSqlStr)) {
            return where;
        }

        Expression appendExpression = CCJSqlParserUtil.parseCondExpression(appendSqlStr);

        if (where == null) {
            return appendExpression;
        }

        return new AndExpression(where, appendExpression);
    }


}

2. 就认为是拦截器没有起作用,后面同事大哥给了一个解决方法

@Slf4j
public class SqlSessionFactoryBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof SqlSessionFactory) { //所有bean初始化之后都会进入这个方法,这个时候需要滤出需要的类型,比如这次就只需要拿到SqlSessionFactory类型的对象对其设置拦截器就行了
            SqlSessionFactory nowBean = (SqlSessionFactory) bean;
            nowBean.getConfiguration().addInterceptor(new RowVersionUpdateInterceptor());
            nowBean.getConfiguration().addInterceptor(setMybatisPlusInterceptor());
        }
        return bean; //完成后返回出去,可能直接进入容器,也可能会去执行其他的BeanPostProcessor
    }
    public MybatisPlusInterceptor setMybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new DataPermissionInterceptor(new MyDataPermissionHandler()));
        return interceptor;
    }
}

直接在注册Bean的时候,将SqlSessionFactory相关的bean都加上拦截器,然后再把SqlSessionFactoryBeanPostProcessor 注册到ioc中

@Configuration
public class MybatisPlusConfig {

    @Bean
    public SqlSessionFactoryBeanPostProcessor sqlSessionFactoryBeanPostProcessor() {
        return new SqlSessionFactoryBeanPostProcessor();
    }
}

3.可以解决问题,但是又不知道这个问题出在哪里,因为我之前都是这样配的,且重新搭建一个新的环境按照原来的方法依然可以,等我了解后问题,在来加更。。。。。。

### MyBatis-Plus 拦截器执行完成后的处理机制 MyBatis-Plus 提供了一种灵活的方式来定义自定义拦截器,这些拦截器可以在 SQL 执行的不同阶段介入并进行额外的操作。当拦截器在 SQL 执行完成后需要进行后续处理时,可以通过实现 `Interceptor` 接口中的 `afterCompletion` 方法来达成目标。 #### 自定义拦截器的结构 MyBatis-Plus 的拦截器通常继承于 `AbstractSqlParserInterceptor` 或直接实现 `org.apache.ibatis.plugin.Interceptor` 接口[^1]。通过重写接口的方法可以控制 SQL 执行前、执行中以及执行后的逻辑行为。 以下是核心方法的作用说明: - **`intercept(Invocation invocation)`**: 主要用于拦截 SQL 执行请求,在此方法中可以修改 SQL 参数或返回结果。 - **`plugin(Object target)`**: 返回一个代理对象,该对象会替换原始的目标对象。 - **`setProperties(Properties properties)`**: 设置配置属性。 - **`afterCompletion(int executionStatus, Exception exception)`**: 当 SQL 执行完毕后调用,可用于清理资源或记录日志等操作[^2]。 #### 实现 SQL 完成后的处理逻辑 为了实现在 SQL 执行完成后的特定业务逻辑,开发者需关注以下几个方面: 1. **异常捕获与状态判断** 在 `afterCompletion` 方法中,参数 `executionStatus` 表示当前事务的状态(成功或失败),而 `exception` 则表示可能抛出的异常。可以根据这两个参数决定是否执行某些清理工作或者触发补偿措施[^3]。 2. **性能监控与统计** 可在此处收集 SQL 执行时间、影响行数等相关数据,并将其存储到数据库或其他持久化介质中以便后续分析[^4]。 3. **缓存更新策略** 如果应用依赖分布式缓存,则可在 SQL 成功提交之后同步刷新对应的缓存条目,从而保持一致性[^5]。 下面是一个简单的代码示例展示如何创建一个带有 `afterCompletion` 处理功能的自定义拦截器: ```java import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.MappedStatement; public class CustomAfterExecutionInterceptor extends InnerInterceptor { @Override public void afterQuery(Executor executor, MappedStatement ms, Object parameter, Object result) { System.out.println("SQL 查询已结束..."); // 进行业务级别的日志记录或者其他必要的操作 } @Override public void afterUpdate(Executor executor, MappedStatement ms, Object parameter) { System.out.println("SQL 更新/删除已完成!"); // 清除关联表的数据缓存 } } ``` 上述代码片段展示了两个典型的场景——查询结束后打印提示信息;对于增删改类操作则进一步实施清除缓存的动作[^6]。 #### 配置自定义拦截器 最后一步就是将这个新构建好的拦截器注册至 Spring Boot 应用程序上下文中。这可通过如下方式完成: ```yaml mybatis-plus: global-config: db-config: id-type: auto configuration: map-underscore-to-camel-case: true interceptors: - com.example.demo.interceptor.CustomAfterExecutionInterceptor ``` 以上 YAML 文件片断指定了我们刚刚开发出来的拦截器会被加载入框架运行环境之中[^7]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘个Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值