Browse Source

update 通过类加载的方式优化 Javadoc 解析器,支持执行多个 Javadoc 解析器

秋辞未寒 4 months ago
parent
commit
c9774e78c4

+ 0 - 5
ruoyi-common/ruoyi-common-doc/pom.xml

@@ -21,11 +21,6 @@
             <artifactId>ruoyi-common-core</artifactId>
             <artifactId>ruoyi-common-core</artifactId>
         </dependency>
         </dependency>
 
 
-        <dependency>
-            <groupId>cn.dev33</groupId>
-            <artifactId>sa-token-core</artifactId>
-        </dependency>
-
         <dependency>
         <dependency>
             <groupId>org.springdoc</groupId>
             <groupId>org.springdoc</groupId>
             <artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
             <artifactId>springdoc-openapi-starter-webmvc-api</artifactId>

+ 7 - 7
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java

@@ -7,8 +7,8 @@ import io.swagger.v3.oas.models.security.SecurityRequirement;
 import lombok.RequiredArgsConstructor;
 import lombok.RequiredArgsConstructor;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.doc.config.properties.SpringDocProperties;
 import org.dromara.common.doc.config.properties.SpringDocProperties;
-import org.dromara.common.doc.core.enhancer.SaTokenJavadocResolver;
-import org.dromara.common.doc.core.enhancer.SaTokenMetadataResolver;
+import org.dromara.common.doc.core.resolver.JavadocResolver;
+import org.dromara.common.doc.core.resolver.SaTokenAnnotationMetadataJavadocResolver;
 import org.dromara.common.doc.handler.OpenApiHandler;
 import org.dromara.common.doc.handler.OpenApiHandler;
 import org.springdoc.core.configuration.SpringDocConfiguration;
 import org.springdoc.core.configuration.SpringDocConfiguration;
 import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
 import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
@@ -87,8 +87,8 @@ public class SpringDocConfig {
                                          SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
                                          SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
                                          Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers,
                                          Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers,
                                          Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers, Optional<JavadocProvider> javadocProvider,
                                          Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers, Optional<JavadocProvider> javadocProvider,
-                                         SaTokenMetadataResolver saTokenMetadataResolver) {
-        return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider, saTokenMetadataResolver);
+                                         List<JavadocResolver> javadocResolvers) {
+        return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider, javadocResolvers);
     }
     }
 
 
     /**
     /**
@@ -116,11 +116,11 @@ public class SpringDocConfig {
     }
     }
 
 
     /**
     /**
-     * 注册JavaDoc权限解析器
+     * 注册SaToken JavaDoc权限注解解析器
      */
      */
     @Bean
     @Bean
-    public SaTokenMetadataResolver saTokenJavadocResolver() {
-        return new SaTokenJavadocResolver();
+    public JavadocResolver saTokenAnnotationJavadocResolver() {
+        return new SaTokenAnnotationMetadataJavadocResolver();
     }
     }
 
 
     /**
     /**

+ 0 - 185
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/enhancer/SaTokenJavadocResolver.java

@@ -1,185 +0,0 @@
-package org.dromara.common.doc.core.enhancer;
-
-import cn.dev33.satoken.annotation.SaCheckLogin;
-import cn.dev33.satoken.annotation.SaCheckPermission;
-import cn.dev33.satoken.annotation.SaCheckRole;
-import cn.dev33.satoken.annotation.SaIgnore;
-import cn.hutool.core.convert.Convert;
-import io.swagger.v3.oas.models.Operation;
-import org.dromara.common.doc.core.model.SaTokenSecurityMetadata;
-import org.springframework.web.method.HandlerMethod;
-
-import java.lang.annotation.Annotation;
-
-/**
- * 基于JavaDoc的SaToken权限解析器
- *
- * @author echo
- */
-public class SaTokenJavadocResolver implements SaTokenMetadataResolver {
-
-    public static final Class<SaCheckRole> SA_CHECK_ROLE_CLASS = SaCheckRole.class;
-    public static final Class<SaCheckPermission> SA_CHECK_PERMISSION_CLASS = SaCheckPermission.class;
-    public static final Class<SaIgnore> SA_IGNORE_CLASS = SaIgnore.class;
-    public static final Class<SaCheckLogin> SA_CHECK_LOGIN = SaCheckLogin.class;
-
-    /**
-     * 核心解析方法
-     */
-    @Override
-    public void resolve(HandlerMethod handlerMethod, Operation operation, SaTokenSecurityMetadata metadata) {
-        // 检查是否忽略校验
-        if (isIgnore(handlerMethod)) {
-            metadata.setIgnore(true);
-            return;
-        }
-
-        // 解析权限校验
-        resolvePermissionCheck(handlerMethod, metadata);
-
-        // 解析角色校验
-        resolveRoleCheck(handlerMethod, metadata);
-    }
-
-    /**
-     * 解析器优先级
-     */
-    @Override
-    public int getOrder() {
-        return 100;
-    }
-
-    /**
-     * 判断是否支持当前HandlerMethod
-     */
-    @Override
-    public boolean supports(HandlerMethod handlerMethod) {
-        return hasAnnotation(handlerMethod
-            .getMethodAnnotation(SA_CHECK_PERMISSION_CLASS)) || hasAnnotation(handlerMethod
-            .getMethodAnnotation(SA_CHECK_ROLE_CLASS)) || hasAnnotation(handlerMethod
-            .getMethodAnnotation(SA_IGNORE_CLASS)) || hasAnnotation(handlerMethod
-            .getBeanType()
-            .getAnnotation(SA_CHECK_PERMISSION_CLASS)) || hasAnnotation(handlerMethod
-            .getBeanType()
-            .getAnnotation(SA_CHECK_ROLE_CLASS)) || hasAnnotation(handlerMethod
-            .getBeanType()
-            .getAnnotation(SA_IGNORE_CLASS));
-    }
-
-    @Override
-    public String getName() {
-        return "SaTokenJavadocResolver";
-    }
-
-    /**
-     * 检查是否忽略校验
-     */
-    private boolean isIgnore(HandlerMethod handlerMethod) {
-        // 检查方法上的注解
-        if (hasAnnotation(handlerMethod.getMethodAnnotation(SA_IGNORE_CLASS))) {
-            return true;
-        }
-        // 检查类上的注解
-        return hasAnnotation(handlerMethod.getBeanType().getAnnotation(SA_IGNORE_CLASS));
-    }
-
-    /**
-     * 解析权限校验
-     */
-    private void resolvePermissionCheck(HandlerMethod handlerMethod, SaTokenSecurityMetadata metadata) {
-        // 获取方法上的注解
-        Annotation methodAnnotation = handlerMethod
-            .getMethodAnnotation(SA_CHECK_PERMISSION_CLASS);
-        // 获取类上的注解
-        Annotation classAnnotation = handlerMethod.getBeanType()
-            .getAnnotation(SA_CHECK_PERMISSION_CLASS);
-
-        // 解析权限信息
-        if (hasAnnotation(methodAnnotation)) {
-            resolvePermissionAnnotation(metadata, methodAnnotation);
-        }
-        if (hasAnnotation(classAnnotation)) {
-            resolvePermissionAnnotation(metadata, classAnnotation);
-        }
-    }
-
-    /**
-     * 解析权限注解
-     */
-    private void resolvePermissionAnnotation(SaTokenSecurityMetadata metadata, Annotation annotation) {
-        try {
-            // 反射获取注解属性
-            Object value = getAnnotationValue(annotation, "value");
-            Object mode = getAnnotationValue(annotation, "mode");
-            Object type = getAnnotationValue(annotation, "type");
-            Object orRole = getAnnotationValue(annotation, "orRole");
-
-            String[] values = Convert.toStrArray(value);
-            String modeStr = mode != null ? mode.toString() : "AND";
-            String typeStr = type != null ? type.toString() : "";
-            String[] orRoles = Convert.toStrArray(orRole);
-
-            metadata.addPermission(values, modeStr, typeStr, orRoles);
-        } catch (Exception ignore) {
-            // 忽略解析错误
-        }
-    }
-
-    /**
-     * 解析角色校验
-     */
-    private void resolveRoleCheck(HandlerMethod handlerMethod, SaTokenSecurityMetadata metadata) {
-        // 获取方法上的注解
-        Annotation methodAnnotation = handlerMethod.getMethodAnnotation(SA_CHECK_ROLE_CLASS);
-        // 获取类上的注解
-        Annotation classAnnotation = handlerMethod.getBeanType()
-            .getAnnotation(SA_CHECK_ROLE_CLASS);
-
-        // 解析角色信息
-        if (hasAnnotation(methodAnnotation)) {
-            resolveRoleAnnotation(metadata, methodAnnotation);
-        }
-        if (hasAnnotation(classAnnotation)) {
-            resolveRoleAnnotation(metadata, classAnnotation);
-        }
-    }
-
-    /**
-     * 解析角色注解
-     */
-    private void resolveRoleAnnotation(SaTokenSecurityMetadata metadata, Annotation annotation) {
-        try {
-            // 反射获取注解属性
-            Object value = getAnnotationValue(annotation, "value");
-            Object mode = getAnnotationValue(annotation, "mode");
-            Object type = getAnnotationValue(annotation, "type");
-
-            String[] values = Convert.toStrArray(value);
-            String modeStr = mode != null ? mode.toString() : "AND";
-            String typeStr = type != null ? type.toString() : "";
-
-            metadata.addRole(values, modeStr, typeStr);
-        } catch (Exception ignore) {
-            // 忽略解析错误
-        }
-    }
-
-    /**
-     * 检查注解是否存在
-     */
-    private boolean hasAnnotation(Annotation annotation) {
-        return annotation != null;
-    }
-
-    /**
-     * 获取注解属性值
-     */
-    private Object getAnnotationValue(Annotation annotation, String attributeName) {
-        try {
-            return annotation.annotationType().getMethod(attributeName).invoke(annotation);
-        } catch (Exception e) {
-            return null;
-        }
-    }
-
-}

+ 0 - 38
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/enhancer/SaTokenMetadataResolver.java

@@ -1,38 +0,0 @@
-package org.dromara.common.doc.core.enhancer;
-
-import io.swagger.v3.oas.models.Operation;
-import org.dromara.common.doc.core.model.SaTokenSecurityMetadata;
-import org.springframework.web.method.HandlerMethod;
-
-/**
- * 权限元数据解析器接口
- *
- * @author echo
- */
-public interface SaTokenMetadataResolver {
-
-    /**
-     * 解析权限元数据
-     */
-    void resolve(HandlerMethod handlerMethod, Operation operation, SaTokenSecurityMetadata metadata);
-
-    /**
-     * 获取解析器优先级
-     */
-    int getOrder();
-
-    /**
-     * 判断是否支持当前HandlerMethod
-     */
-    boolean supports(HandlerMethod handlerMethod);
-
-    /**
-     * 获取解析器的名称
-     *
-     * @return 解析器名称
-     */
-    default String getName() {
-        return this.getClass().getSimpleName();
-    }
-
-}

+ 163 - 0
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/AbstractMetadataJavadocResolver.java

@@ -0,0 +1,163 @@
+package org.dromara.common.doc.core.resolver;
+
+import cn.hutool.core.annotation.AnnotationUtil;
+import cn.hutool.core.util.ClassLoaderUtil;
+import io.swagger.v3.oas.models.Operation;
+import org.springframework.web.method.HandlerMethod;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.util.Map;
+import java.util.function.Supplier;
+
+/**
+ * 抽象元数据 Javadoc 解析器
+ *
+ * @param <M> 元数据类型
+ * @author 秋辞未寒
+ */
+public abstract class AbstractMetadataJavadocResolver<M> implements JavadocResolver {
+
+    public static final int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
+    public static final int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
+
+    private final Supplier<M> metadataProvider;
+
+    private final int order;
+
+    public AbstractMetadataJavadocResolver(Supplier<M> metadataProvider) {
+        this(metadataProvider, LOWEST_PRECEDENCE);
+    }
+
+    public AbstractMetadataJavadocResolver(Supplier<M> metadataProvider, int order) {
+        this.metadataProvider = metadataProvider;
+        this.order = order;
+    }
+
+    @Override
+    public int getOrder() {
+        return order;
+    }
+
+    @Override
+    public String resolve(HandlerMethod handlerMethod, Operation operation) {
+        return resolve(handlerMethod, operation, metadataProvider.get());
+    }
+
+    /**
+     * 执行解析并返回解析到的 Javadoc 内容
+     * @param handlerMethod 处理器方法
+     * @param operation Swagger Operation实例
+     * @param metadata 元信息
+     * @return 解析到的 Javadoc 内容
+     */
+    public abstract String resolve(HandlerMethod handlerMethod, Operation operation, M metadata);
+
+    /**
+     * 检查处理器方法所属的类上是否存在注解
+     * @param handlerMethod 处理器方法
+     * @param annotationClass 注解类
+     * @return 是否存在注解
+     */
+    public boolean hasClassAnnotation(HandlerMethod handlerMethod,Class<? extends Annotation> annotationClass){
+        return AnnotationUtil.hasAnnotation(handlerMethod.getBeanType(), annotationClass);
+    }
+
+    /**
+     * 检查处理器方法所属的类上是否存在注解
+     * @param handlerMethod 处理器方法
+     * @param annotationTypeName 注解类名称
+     * @return 是否存在注解
+     */
+    public boolean hasClassAnnotation(HandlerMethod handlerMethod, String annotationTypeName){
+        return AnnotationUtil.hasAnnotation(handlerMethod.getBeanType(), annotationTypeName);
+    }
+
+    /**
+     * 检查处理器方法上是否存在注解
+     * @param handlerMethod 处理器方法
+     * @param annotationClass 注解类
+     * @return 是否存在注解
+     */
+    public boolean hasMethodAnnotation(HandlerMethod handlerMethod,Class<? extends Annotation> annotationClass){
+        return AnnotationUtil.hasAnnotation(handlerMethod.getMethod(), annotationClass);
+    }
+
+    /**
+     * 检查处理器方法上是否存在注解
+     * @param handlerMethod 处理器方法
+     * @param annotationTypeName 注解类名称
+     * @return 是否存在注解
+     */
+    public boolean hasMethodAnnotation(HandlerMethod handlerMethod, String annotationTypeName){
+        return AnnotationUtil.hasAnnotation(handlerMethod.getMethod(), annotationTypeName);
+    }
+
+    /**
+     * 检查处理器方法上是否存在注解
+     * @param handlerMethod 处理器方法
+     * @param annotationClass 注解类
+     * @return 是否存在注解
+     */
+    public boolean hasAnnotation(HandlerMethod handlerMethod,Class<? extends Annotation> annotationClass){
+        return this.hasClassAnnotation(handlerMethod, annotationClass) || this.hasMethodAnnotation(handlerMethod, annotationClass);
+    }
+
+    /**
+     * 检查处理器方法上是否存在注解
+     * @param handlerMethod 处理器方法
+     * @param annotationTypeName 注解类名称
+     * @return 是否存在注解
+     */
+    public boolean hasAnnotation(HandlerMethod handlerMethod, String annotationTypeName){
+        return this.hasClassAnnotation(handlerMethod, annotationTypeName) || this.hasMethodAnnotation(handlerMethod, annotationTypeName);
+    }
+
+    /**
+     * 获取处理器方法所属类上的注解的值
+     * @param handlerMethod 处理器方法
+     * @param annotationClass 注解类
+     * @return 注解的值
+     */
+    public Map<String, Object> getClassAnnotationValueMap(HandlerMethod handlerMethod, Class<? extends Annotation> annotationClass) {
+        return AnnotationUtil.getAnnotationValueMap(handlerMethod.getBeanType(), annotationClass);
+    }
+
+    /**
+     * 获取处理器方法所属类上的注解的值
+     * @param handlerMethod 处理器方法
+     * @param annotationClassName 注解类名称
+     * @return 注解的值
+     */
+    @SuppressWarnings("unchecked")
+    public Map<String, Object> getClassAnnotationValueMap(HandlerMethod handlerMethod, String annotationClassName) {
+        Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) ClassLoaderUtil.loadClass(annotationClassName, false);
+        return AnnotationUtil.getAnnotationValueMap(handlerMethod.getBeanType(), annotationClass);
+    }
+
+    /**
+     * 获取处理器方法上的注解的值
+     * @param handlerMethod 处理器方法
+     * @param annotationClass 注解类
+     * @return 注解的值
+     */
+    public Map<String, Object> getMethodAnnotationValueMap(HandlerMethod handlerMethod, Class<? extends Annotation> annotationClass) {
+        return AnnotationUtil.getAnnotationValueMap(handlerMethod.getMethod(), annotationClass);
+    }
+
+    /**
+     * 获取处理器方法所属类上的注解的值
+     * @param handlerMethod 处理器方法
+     * @param annotationClassName 注解类名称
+     * @return 注解的值
+     */
+    @SuppressWarnings("unchecked")
+    public Map<String, Object> getMethodAnnotationValueMap(HandlerMethod handlerMethod, String annotationClassName) {
+        Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) ClassLoaderUtil.loadClass(annotationClassName, false);
+        return AnnotationUtil.getAnnotationValueMap(handlerMethod.getMethod(), annotationClass);
+    }
+
+    private Map<String, Object> getAnnotationValueMap(AnnotatedElement annotatedElement, Class<? extends Annotation> annotationClass) {
+        return AnnotationUtil.getAnnotationValueMap(annotatedElement, annotationClass);
+    }
+}

+ 51 - 0
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/JavadocResolver.java

@@ -0,0 +1,51 @@
+package org.dromara.common.doc.core.resolver;
+
+import io.swagger.v3.oas.models.Operation;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.core.Ordered;
+import org.springframework.web.method.HandlerMethod;
+
+/**
+ * Javadoc解析器接口
+ *
+ * @author echo
+ * @author 秋辞未寒
+ */
+public interface JavadocResolver extends Comparable<JavadocResolver>, Ordered {
+
+    /**
+     * 检查解析器是否支持解析 HandlerMethod
+     * @param handlerMethod 处理器方法
+     * @return 是否支持解析
+     */
+    boolean supports(HandlerMethod handlerMethod);
+
+    /**
+     * 执行解析并返回解析到的 Javadoc 内容
+     * @param handlerMethod 处理器方法
+     * @param operation Swagger Operation实例
+     * @return 解析到的 Javadoc 内容
+     */
+    String resolve(HandlerMethod handlerMethod, Operation operation);
+
+    /**
+     * 获取解析器优先级
+     */
+    default int getOrder() {
+        return Ordered.LOWEST_PRECEDENCE;
+    }
+
+    /**
+     * 获取解析器的名称
+     *
+     * @return 解析器名称
+     */
+    default String getName() {
+        return this.getClass().getSimpleName();
+    }
+
+    @Override
+    default int compareTo(@NotNull JavadocResolver o) {
+        return Integer.compare(getOrder(), o.getOrder());
+    }
+}

+ 163 - 0
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/SaTokenAnnotationMetadataJavadocResolver.java

@@ -0,0 +1,163 @@
+package org.dromara.common.doc.core.resolver;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ClassLoaderUtil;
+import io.swagger.v3.oas.models.Operation;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.doc.core.model.SaTokenSecurityMetadata;
+import org.springframework.web.method.HandlerMethod;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
+
+/**
+ * 基于JavaDoc的SaToken权限解析器
+ *
+ * @author echo
+ * @author 秋辞未寒
+ */
+@SuppressWarnings("unchecked")
+@Slf4j
+public class SaTokenAnnotationMetadataJavadocResolver extends AbstractMetadataJavadocResolver<SaTokenSecurityMetadata> {
+
+    /**
+     * 默认元数据提供者,每次解析都会创建一个新的元数据对象
+     */
+    public static final Supplier<SaTokenSecurityMetadata> DEFAULT_METADATA_PROVIDER = SaTokenSecurityMetadata::new;
+
+    private static final String SA_CHECK_ROLE_CLASS_NAME = "cn.dev33.satoken.annotation.SaCheckRole";
+    private static final String SA_CHECK_PERMISSION_CLASS_NAME = "cn.dev33.satoken.annotation.SaCheckPermission";
+    private static final String SA_IGNORE_CLASS_NAME = "cn.dev33.satoken.annotation.SaIgnore";
+    private static final String SA_CHECK_LOGIN_NAME = "cn.dev33.satoken.annotation.SaCheckLogin";
+
+    private static final Class<? extends Annotation> SA_CHECK_ROLE_CLASS;
+    private static final Class<? extends Annotation> SA_CHECK_PERMISSION_CLASS;
+    private static final Class<? extends Annotation> SA_IGNORE_CLASS;
+    private static final Class<? extends Annotation> SA_CHECK_LOGIN_CLASS;
+
+
+    static {
+        // 通过类加载器去加载注解类Class实例
+        SA_CHECK_ROLE_CLASS = (Class<? extends Annotation>) ClassLoaderUtil.loadClass(SA_CHECK_ROLE_CLASS_NAME, false);
+        SA_CHECK_PERMISSION_CLASS = (Class<? extends Annotation>) ClassLoaderUtil.loadClass(SA_CHECK_PERMISSION_CLASS_NAME, false);
+        SA_IGNORE_CLASS = (Class<? extends Annotation>) ClassLoaderUtil.loadClass(SA_IGNORE_CLASS_NAME, false);
+        SA_CHECK_LOGIN_CLASS = (Class<? extends Annotation>) ClassLoaderUtil.loadClass(SA_CHECK_LOGIN_NAME, false);
+        if (log.isInfoEnabled()) {
+            log.info("SaTokenAnnotationJavadocResolver init success, load annotation class: {}", List.of(SA_CHECK_ROLE_CLASS, SA_CHECK_PERMISSION_CLASS, SA_IGNORE_CLASS, SA_CHECK_LOGIN_CLASS));
+        }
+    }
+
+    public SaTokenAnnotationMetadataJavadocResolver() {
+        this(DEFAULT_METADATA_PROVIDER);
+    }
+
+    public SaTokenAnnotationMetadataJavadocResolver(Supplier<SaTokenSecurityMetadata> metadataProvider) {
+        super(metadataProvider);
+    }
+
+    public SaTokenAnnotationMetadataJavadocResolver(int order) {
+        this(DEFAULT_METADATA_PROVIDER,order);
+    }
+
+    public SaTokenAnnotationMetadataJavadocResolver(Supplier<SaTokenSecurityMetadata> metadataProvider, int order) {
+        super(metadataProvider,order);
+    }
+
+    @Override
+    public boolean supports(HandlerMethod handlerMethod) {
+        return hasAnnotation(handlerMethod, SA_CHECK_ROLE_CLASS) || hasAnnotation(handlerMethod, SA_CHECK_PERMISSION_CLASS) || hasAnnotation(handlerMethod, SA_IGNORE_CLASS);
+    }
+
+    @Override
+    public String resolve(HandlerMethod handlerMethod, Operation operation, SaTokenSecurityMetadata metadata) {
+        // 检查是否忽略校验
+        if(hasAnnotation(handlerMethod, SA_IGNORE_CLASS_NAME)){
+            metadata.setIgnore(true);
+            return metadata.toMarkdownString();
+        }
+
+        // 解析权限校验
+        resolvePermissionCheck(handlerMethod, metadata);
+
+        // 解析角色校验
+        resolveRoleCheck(handlerMethod, metadata);
+        return metadata.toMarkdownString();
+    }
+
+    /**
+     * 解析权限校验
+     */
+    private void resolvePermissionCheck(HandlerMethod handlerMethod, SaTokenSecurityMetadata metadata) {
+        // 解析获取方法上的注解角色信息
+        if (hasMethodAnnotation(handlerMethod, SA_CHECK_PERMISSION_CLASS_NAME)) {
+            Map<String, Object> annotationValueMap = getMethodAnnotationValueMap(handlerMethod, SA_CHECK_PERMISSION_CLASS);
+            resolvePermissionAnnotation(metadata, annotationValueMap);
+        }
+        // 解析获取类上的注解角色信息
+        if (hasClassAnnotation(handlerMethod, SA_CHECK_PERMISSION_CLASS_NAME)) {
+            Map<String, Object> annotationValueMap = getClassAnnotationValueMap(handlerMethod, SA_CHECK_PERMISSION_CLASS);
+            resolvePermissionAnnotation(metadata, annotationValueMap);
+        }
+    }
+
+    /**
+     * 解析权限注解
+     */
+    private void resolvePermissionAnnotation(SaTokenSecurityMetadata metadata, Map<String, Object> annotationValueMap) {
+        try {
+            // 反射获取注解属性
+            Object value = annotationValueMap.get( "value");
+            Object mode = annotationValueMap.get( "mode");
+            Object type = annotationValueMap.get( "type");
+            Object orRole = annotationValueMap.get( "orRole");
+
+            String[] values = Convert.toStrArray(value);
+            String modeStr = mode != null ? mode.toString() : "AND";
+            String typeStr = type != null ? type.toString() : "";
+            String[] orRoles = Convert.toStrArray(orRole);
+
+            metadata.addPermission(values, modeStr, typeStr, orRoles);
+        } catch (Exception ignore) {
+            // 忽略解析错误
+        }
+    }
+
+    /**
+     * 解析角色校验
+     */
+    private void resolveRoleCheck(HandlerMethod handlerMethod, SaTokenSecurityMetadata metadata) {
+        // 解析获取方法上的注解角色信息
+        if (hasMethodAnnotation(handlerMethod, SA_CHECK_ROLE_CLASS_NAME)) {
+            Map<String, Object> annotationValueMap = getMethodAnnotationValueMap(handlerMethod, SA_CHECK_ROLE_CLASS);
+            resolveRoleAnnotation(metadata, annotationValueMap);
+        }
+        // 解析获取类上的注解角色信息
+        if (hasClassAnnotation(handlerMethod, SA_CHECK_ROLE_CLASS_NAME)) {
+            Map<String, Object> annotationValueMap = getClassAnnotationValueMap(handlerMethod, SA_CHECK_ROLE_CLASS);
+            resolveRoleAnnotation(metadata, annotationValueMap);
+        }
+    }
+
+    /**
+     * 解析角色注解
+     */
+    private void resolveRoleAnnotation(SaTokenSecurityMetadata metadata, Map<String, Object> annotationValueMap) {
+        try {
+            // 反射获取注解属性
+            Object value = annotationValueMap.get("value");
+            Object mode = annotationValueMap.get("mode");
+            Object type = annotationValueMap.get("type");
+
+            String[] values = Convert.toStrArray(value);
+            String modeStr = mode != null ? mode.toString() : "AND";
+            String typeStr = type != null ? type.toString() : "";
+
+            metadata.addRole(values, modeStr, typeStr);
+        } catch (Exception ignore) {
+            // 忽略解析错误
+        }
+    }
+
+}

+ 11 - 14
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java

@@ -12,8 +12,7 @@ import io.swagger.v3.oas.models.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.core.utils.StreamUtils;
-import org.dromara.common.doc.core.enhancer.SaTokenMetadataResolver;
-import org.dromara.common.doc.core.model.SaTokenSecurityMetadata;
+import org.dromara.common.doc.core.resolver.JavadocResolver;
 import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
 import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
 import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
 import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
 import org.springdoc.core.properties.SpringDocConfigProperties;
 import org.springdoc.core.properties.SpringDocConfigProperties;
@@ -86,9 +85,9 @@ public class OpenApiHandler extends OpenAPIService {
     private final PropertyResolverUtils propertyResolverUtils;
     private final PropertyResolverUtils propertyResolverUtils;
 
 
     /**
     /**
-     * 权限元数据解析器接口
+     * Javadoc解析器接口
      */
      */
-    private final SaTokenMetadataResolver saTokenJavadocResolver;
+    private final List<JavadocResolver> javadocResolvers;
 
 
     /**
     /**
      * The javadoc provider.
      * The javadoc provider.
@@ -131,7 +130,7 @@ public class OpenApiHandler extends OpenAPIService {
                           Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomizers,
                           Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomizers,
                           Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers,
                           Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers,
                           Optional<JavadocProvider> javadocProvider,
                           Optional<JavadocProvider> javadocProvider,
-                          SaTokenMetadataResolver saTokenJavadocResolver) {
+                          List<JavadocResolver> javadocResolvers) {
         super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider);
         super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider);
         if (openAPI.isPresent()) {
         if (openAPI.isPresent()) {
             this.openAPI = openAPI.get();
             this.openAPI = openAPI.get();
@@ -148,7 +147,7 @@ public class OpenApiHandler extends OpenAPIService {
         this.openApiBuilderCustomisers = openApiBuilderCustomizers;
         this.openApiBuilderCustomisers = openApiBuilderCustomizers;
         this.serverBaseUrlCustomizers = serverBaseUrlCustomizers;
         this.serverBaseUrlCustomizers = serverBaseUrlCustomizers;
         this.javadocProvider = javadocProvider;
         this.javadocProvider = javadocProvider;
-        this.saTokenJavadocResolver = saTokenJavadocResolver;
+        this.javadocResolvers = javadocResolvers == null ? new ArrayList<>() : javadocResolvers;
         if (springDocConfigProperties.isUseFqn())
         if (springDocConfigProperties.isUseFqn())
             TypeNameResolver.std.setUseFqn(true);
             TypeNameResolver.std.setUseFqn(true);
     }
     }
@@ -235,16 +234,14 @@ public class OpenApiHandler extends OpenAPIService {
             if (StringUtils.isNotBlank(description)){
             if (StringUtils.isNotBlank(description)){
                 operation.setSummary(summary);
                 operation.setSummary(summary);
             }
             }
-            // 调用SaToken解析器提取JavaDoc中的权限信息
-            if (saTokenJavadocResolver.supports(handlerMethod)) {
-                SaTokenSecurityMetadata metadata = new SaTokenSecurityMetadata();
-                saTokenJavadocResolver.resolve(handlerMethod, operation, metadata);
-                String markdownString = metadata.toMarkdownString();
-                if (StringUtils.isNotBlank(markdownString)) {
-                    description = description + markdownString;
+            // 调用解析器提取JavaDoc中的权限信息
+            if (javadocResolvers != null && !javadocResolvers.isEmpty()) {
+                for (JavadocResolver resolver : javadocResolvers) {
+                    String desc = resolver.resolve(handlerMethod, operation);
+                    description = description + desc;
                 }
                 }
+                operation.setDescription(description);
             }
             }
-            operation.setDescription(description);
         }
         }
 
 
         return operation;
         return operation;