疯狂的狮子Li
2024-11-22 dd2abd95c951f8e037e78c421a37ffb5aa999e57
fix 修复 aop 无法拦截mapper接口上的注解导致的问题 类上依旧使用扫描处理
已修改3个文件
99 ■■■■■ 文件已修改
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
@@ -52,7 +52,7 @@
     * 数据权限拦截器
     */
    public PlusDataPermissionInterceptor dataPermissionInterceptor() {
        return new PlusDataPermissionInterceptor();
        return new PlusDataPermissionInterceptor(SpringUtils.getProperty("mybatis-plus.mapperPackage"));
    }
    /**
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
@@ -1,5 +1,6 @@
package org.dromara.common.mybatis.handler;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
@@ -8,6 +9,7 @@
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import org.apache.ibatis.io.Resources;
import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
@@ -19,17 +21,26 @@
import org.dromara.common.mybatis.enums.DataScopeType;
import org.dromara.common.mybatis.helper.DataPermissionHelper;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.ClassUtils;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/**
@@ -42,6 +53,11 @@
public class PlusDataPermissionHandler {
    /**
     * 类名称与注解的映射关系缓存(由于aop无法拦截mybatis接口类上的注解 只能通过启动预扫描的方式进行)
     */
    private final Map<String, DataPermission> dataPermissionCacheMap = new ConcurrentHashMap<>();
    /**
     * spel 解析器
     */
    private final ExpressionParser parser = new SpelExpressionParser();
@@ -50,6 +66,15 @@
     * bean解析器 用于处理 spel 表达式中对 bean 的调用
     */
    private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory());
    /**
     * 构造方法,扫描指定包下的 Mapper 类并初始化缓存
     *
     * @param mapperPackage Mapper 类所在的包路径
     */
    public PlusDataPermissionHandler(String mapperPackage) {
        scanMapperClasses(mapperPackage);
    }
    /**
     * 获取数据过滤条件的 SQL 片段
@@ -62,7 +87,7 @@
    public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
        try {
            // 获取数据权限配置
            DataPermission dataPermission = DataPermissionHelper.getPermission();
            DataPermission dataPermission = getDataPermission(mappedStatementId);
            // 获取当前登录用户信息
            LoginUser currentUser = DataPermissionHelper.getVariable("user");
            if (ObjectUtil.isNull(currentUser)) {
@@ -170,11 +195,67 @@
    }
    /**
     * 扫描指定包下的 Mapper 类,并查找其中带有特定注解的方法或类
     *
     * @param mapperPackage Mapper 类所在的包路径
     */
    private void scanMapperClasses(String mapperPackage) {
        // 创建资源解析器和元数据读取工厂
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
        // 将 Mapper 包路径按分隔符拆分为数组
        String[] packagePatternArray = StringUtils.splitPreserveAllTokens(mapperPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
        try {
            for (String packagePattern : packagePatternArray) {
                // 将包路径转换为资源路径
                String path = ClassUtils.convertClassNameToResourcePath(packagePattern);
                // 获取指定路径下的所有 .class 文件资源
                Resource[] resources = resolver.getResources(classpath + path + "/*.class");
                for (Resource resource : resources) {
                    // 获取资源的类元数据
                    ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata();
                    // 获取资源对应的类对象
                    Class<?> clazz = Resources.classForName(classMetadata.getClassName());
                    // 查找类中的特定注解
                    if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) {
                        DataPermission dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class);
                        dataPermissionCacheMap.put(clazz.getName(), dataPermission);
                    }
                }
            }
        } catch (Exception e) {
            log.error("初始化数据安全缓存时出错:{}", e.getMessage());
        }
    }
    /**
     * 根据映射语句 ID 或类名获取对应的 DataPermission 注解对象
     *
     * @param mapperId 映射语句 ID
     * @return DataPermission 注解对象,如果不存在则返回 null
     */
    public DataPermission getDataPermission(String mapperId) {
        // 检查上下文中是否包含映射语句 ID 对应的 DataPermission 注解对象
        if (DataPermissionHelper.getPermission() != null) {
            return DataPermissionHelper.getPermission();
        }
        // 如果缓存中不包含映射语句 ID 对应的 DataPermission 注解对象,则尝试使用类名作为键查找
        String clazzName = mapperId.substring(0, mapperId.lastIndexOf("."));
        if (dataPermissionCacheMap.containsKey(clazzName)) {
            return dataPermissionCacheMap.get(clazzName);
        }
        return null;
    }
    /**
     * 检查给定的映射语句 ID 是否有效,即是否能够找到对应的 DataPermission 注解对象
     *
     * @param mapperId 映射语句 ID
     * @return 如果找到对应的 DataPermission 注解对象,则返回 false;否则返回 true
     */
    public boolean invalid() {
        return DataPermissionHelper.getPermission() == null;
    public boolean invalid(String mapperId) {
        return getDataPermission(mapperId) == null;
    }
}
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java
@@ -39,9 +39,11 @@
    /**
     * 构造函数,初始化 PlusDataPermissionHandler 实例
     *
     * @param mapperPackage 扫描的映射器包
     */
    public PlusDataPermissionInterceptor() {
        this.dataPermissionHandler = new PlusDataPermissionHandler();
    public PlusDataPermissionInterceptor(String mapperPackage) {
        this.dataPermissionHandler = new PlusDataPermissionHandler(mapperPackage);
    }
    /**
@@ -62,7 +64,7 @@
            return;
        }
        // 检查是否缺少有效的数据权限注解
        if (dataPermissionHandler.invalid()) {
        if (dataPermissionHandler.invalid(ms.getId())) {
            return;
        }
        // 解析 sql 分配对应方法
@@ -90,7 +92,7 @@
                return;
            }
            // 检查是否缺少有效的数据权限注解
            if (dataPermissionHandler.invalid()) {
            if (dataPermissionHandler.invalid(ms.getId())) {
                return;
            }
            PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();