Просмотр исходного кода

fix 修复 aop 无法拦截mapper接口上的注解导致的问题 类上依旧使用扫描处理

疯狂的狮子Li 8 месяцев назад
Родитель
Сommit
dd2abd95c9

+ 1 - 1
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java

@@ -52,7 +52,7 @@ public class MybatisPlusConfig {
      * 数据权限拦截器
      * 数据权限拦截器
      */
      */
     public PlusDataPermissionInterceptor dataPermissionInterceptor() {
     public PlusDataPermissionInterceptor dataPermissionInterceptor() {
-        return new PlusDataPermissionInterceptor();
+        return new PlusDataPermissionInterceptor(SpringUtils.getProperty("mybatis-plus.mapperPackage"));
     }
     }
 
 
     /**
     /**

+ 84 - 3
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;
 package org.dromara.common.mybatis.handler;
 
 
+import cn.hutool.core.annotation.AnnotationUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ObjectUtil;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
@@ -8,6 +9,7 @@ import net.sf.jsqlparser.expression.Expression;
 import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
 import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
 import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
 import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
 import net.sf.jsqlparser.parser.CCJSqlParserUtil;
 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.dto.RoleDTO;
 import org.dromara.common.core.domain.model.LoginUser;
 import org.dromara.common.core.domain.model.LoginUser;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.exception.ServiceException;
@@ -19,17 +21,26 @@ import org.dromara.common.mybatis.annotation.DataPermission;
 import org.dromara.common.mybatis.enums.DataScopeType;
 import org.dromara.common.mybatis.enums.DataScopeType;
 import org.dromara.common.mybatis.helper.DataPermissionHelper;
 import org.dromara.common.mybatis.helper.DataPermissionHelper;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.satoken.utils.LoginHelper;
+import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.expression.BeanFactoryResolver;
 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.BeanResolver;
 import org.springframework.expression.ExpressionParser;
 import org.springframework.expression.ExpressionParser;
 import org.springframework.expression.ParserContext;
 import org.springframework.expression.ParserContext;
 import org.springframework.expression.common.TemplateParserContext;
 import org.springframework.expression.common.TemplateParserContext;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
 import org.springframework.expression.spel.support.StandardEvaluationContext;
 import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.util.ClassUtils;
 
 
 import java.util.Arrays;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
 import java.util.function.Function;
 
 
 /**
 /**
@@ -41,6 +52,11 @@ import java.util.function.Function;
 @Slf4j
 @Slf4j
 public class PlusDataPermissionHandler {
 public class PlusDataPermissionHandler {
 
 
+    /**
+     * 类名称与注解的映射关系缓存(由于aop无法拦截mybatis接口类上的注解 只能通过启动预扫描的方式进行)
+     */
+    private final Map<String, DataPermission> dataPermissionCacheMap = new ConcurrentHashMap<>();
+
     /**
     /**
      * spel 解析器
      * spel 解析器
      */
      */
@@ -51,6 +67,15 @@ public class PlusDataPermissionHandler {
      */
      */
     private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory());
     private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory());
 
 
+    /**
+     * 构造方法,扫描指定包下的 Mapper 类并初始化缓存
+     *
+     * @param mapperPackage Mapper 类所在的包路径
+     */
+    public PlusDataPermissionHandler(String mapperPackage) {
+        scanMapperClasses(mapperPackage);
+    }
+
     /**
     /**
      * 获取数据过滤条件的 SQL 片段
      * 获取数据过滤条件的 SQL 片段
      *
      *
@@ -62,7 +87,7 @@ public class PlusDataPermissionHandler {
     public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
     public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
         try {
         try {
             // 获取数据权限配置
             // 获取数据权限配置
-            DataPermission dataPermission = DataPermissionHelper.getPermission();
+            DataPermission dataPermission = getDataPermission(mappedStatementId);
             // 获取当前登录用户信息
             // 获取当前登录用户信息
             LoginUser currentUser = DataPermissionHelper.getVariable("user");
             LoginUser currentUser = DataPermissionHelper.getVariable("user");
             if (ObjectUtil.isNull(currentUser)) {
             if (ObjectUtil.isNull(currentUser)) {
@@ -169,12 +194,68 @@ public class PlusDataPermissionHandler {
         return "";
         return "";
     }
     }
 
 
+    /**
+     * 扫描指定包下的 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 注解对象
      * 检查给定的映射语句 ID 是否有效,即是否能够找到对应的 DataPermission 注解对象
      *
      *
+     * @param mapperId 映射语句 ID
      * @return 如果找到对应的 DataPermission 注解对象,则返回 false;否则返回 true
      * @return 如果找到对应的 DataPermission 注解对象,则返回 false;否则返回 true
      */
      */
-    public boolean invalid() {
-        return DataPermissionHelper.getPermission() == null;
+    public boolean invalid(String mapperId) {
+        return getDataPermission(mapperId) == null;
     }
     }
+
 }
 }

+ 6 - 4
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java

@@ -39,9 +39,11 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
 
 
     /**
     /**
      * 构造函数,初始化 PlusDataPermissionHandler 实例
      * 构造函数,初始化 PlusDataPermissionHandler 实例
+     *
+     * @param mapperPackage 扫描的映射器包
      */
      */
-    public PlusDataPermissionInterceptor() {
-        this.dataPermissionHandler = new PlusDataPermissionHandler();
+    public PlusDataPermissionInterceptor(String mapperPackage) {
+        this.dataPermissionHandler = new PlusDataPermissionHandler(mapperPackage);
     }
     }
 
 
     /**
     /**
@@ -62,7 +64,7 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
             return;
             return;
         }
         }
         // 检查是否缺少有效的数据权限注解
         // 检查是否缺少有效的数据权限注解
-        if (dataPermissionHandler.invalid()) {
+        if (dataPermissionHandler.invalid(ms.getId())) {
             return;
             return;
         }
         }
         // 解析 sql 分配对应方法
         // 解析 sql 分配对应方法
@@ -90,7 +92,7 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
                 return;
                 return;
             }
             }
             // 检查是否缺少有效的数据权限注解
             // 检查是否缺少有效的数据权限注解
-            if (dataPermissionHandler.invalid()) {
+            if (dataPermissionHandler.invalid(ms.getId())) {
                 return;
                 return;
             }
             }
             PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
             PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();