From c9774e78c48302af2891f84f679aacd7e9405509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E8=BE=9E=E6=9C=AA=E5=AF=92?= <545073804@qq.com> Date: Fri, 6 Mar 2026 17:32:28 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E9=80=9A=E8=BF=87=E7=B1=BB=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E7=9A=84=E6=96=B9=E5=BC=8F=E4=BC=98=E5=8C=96=20Javado?= =?UTF-8?q?c=20=E8=A7=A3=E6=9E=90=E5=99=A8=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E5=A4=9A=E4=B8=AA=20Javadoc=20=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-common/ruoyi-common-doc/pom.xml | 5 - .../common/doc/config/SpringDocConfig.java | 14 +- .../core/enhancer/SaTokenJavadocResolver.java | 185 ------------------ .../enhancer/SaTokenMetadataResolver.java | 38 ---- .../AbstractMetadataJavadocResolver.java | 163 +++++++++++++++ .../doc/core/resolver/JavadocResolver.java | 51 +++++ ...okenAnnotationMetadataJavadocResolver.java | 163 +++++++++++++++ .../common/doc/handler/OpenApiHandler.java | 25 ++- 8 files changed, 395 insertions(+), 249 deletions(-) delete mode 100644 ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/enhancer/SaTokenJavadocResolver.java delete mode 100644 ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/enhancer/SaTokenMetadataResolver.java create mode 100644 ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/AbstractMetadataJavadocResolver.java create mode 100644 ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/JavadocResolver.java create mode 100644 ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/SaTokenAnnotationMetadataJavadocResolver.java diff --git a/ruoyi-common/ruoyi-common-doc/pom.xml b/ruoyi-common/ruoyi-common-doc/pom.xml index 390d34f01..c6199a17c 100644 --- a/ruoyi-common/ruoyi-common-doc/pom.xml +++ b/ruoyi-common/ruoyi-common-doc/pom.xml @@ -21,11 +21,6 @@ ruoyi-common-core - - cn.dev33 - sa-token-core - - org.springdoc springdoc-openapi-starter-webmvc-api diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java index b22d91139..63b5e9494 100644 --- a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java +++ b/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 org.dromara.common.core.utils.StringUtils; 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.springdoc.core.configuration.SpringDocConfiguration; import org.springdoc.core.customizers.OpenApiBuilderCustomizer; @@ -87,8 +87,8 @@ public class SpringDocConfig { SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, Optional> openApiBuilderCustomisers, Optional> serverBaseUrlCustomisers, Optional javadocProvider, - SaTokenMetadataResolver saTokenMetadataResolver) { - return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider, saTokenMetadataResolver); + List javadocResolvers) { + return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider, javadocResolvers); } /** @@ -116,11 +116,11 @@ public class SpringDocConfig { } /** - * 注册JavaDoc权限解析器 + * 注册SaToken JavaDoc权限注解解析器 */ @Bean - public SaTokenMetadataResolver saTokenJavadocResolver() { - return new SaTokenJavadocResolver(); + public JavadocResolver saTokenAnnotationJavadocResolver() { + return new SaTokenAnnotationMetadataJavadocResolver(); } /** diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/enhancer/SaTokenJavadocResolver.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/enhancer/SaTokenJavadocResolver.java deleted file mode 100644 index f7c12525c..000000000 --- a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/enhancer/SaTokenJavadocResolver.java +++ /dev/null @@ -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 SA_CHECK_ROLE_CLASS = SaCheckRole.class; - public static final Class SA_CHECK_PERMISSION_CLASS = SaCheckPermission.class; - public static final Class SA_IGNORE_CLASS = SaIgnore.class; - public static final Class 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; - } - } - -} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/enhancer/SaTokenMetadataResolver.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/enhancer/SaTokenMetadataResolver.java deleted file mode 100644 index 0b42b23c7..000000000 --- a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/enhancer/SaTokenMetadataResolver.java +++ /dev/null @@ -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(); - } - -} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/AbstractMetadataJavadocResolver.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/AbstractMetadataJavadocResolver.java new file mode 100644 index 000000000..e9333c044 --- /dev/null +++ b/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 元数据类型 + * @author 秋辞未寒 + */ +public abstract class AbstractMetadataJavadocResolver implements JavadocResolver { + + public static final int HIGHEST_PRECEDENCE = Integer.MIN_VALUE; + public static final int LOWEST_PRECEDENCE = Integer.MAX_VALUE; + + private final Supplier metadataProvider; + + private final int order; + + public AbstractMetadataJavadocResolver(Supplier metadataProvider) { + this(metadataProvider, LOWEST_PRECEDENCE); + } + + public AbstractMetadataJavadocResolver(Supplier 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 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 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 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 getClassAnnotationValueMap(HandlerMethod handlerMethod, Class annotationClass) { + return AnnotationUtil.getAnnotationValueMap(handlerMethod.getBeanType(), annotationClass); + } + + /** + * 获取处理器方法所属类上的注解的值 + * @param handlerMethod 处理器方法 + * @param annotationClassName 注解类名称 + * @return 注解的值 + */ + @SuppressWarnings("unchecked") + public Map getClassAnnotationValueMap(HandlerMethod handlerMethod, String annotationClassName) { + Class annotationClass = (Class) ClassLoaderUtil.loadClass(annotationClassName, false); + return AnnotationUtil.getAnnotationValueMap(handlerMethod.getBeanType(), annotationClass); + } + + /** + * 获取处理器方法上的注解的值 + * @param handlerMethod 处理器方法 + * @param annotationClass 注解类 + * @return 注解的值 + */ + public Map getMethodAnnotationValueMap(HandlerMethod handlerMethod, Class annotationClass) { + return AnnotationUtil.getAnnotationValueMap(handlerMethod.getMethod(), annotationClass); + } + + /** + * 获取处理器方法所属类上的注解的值 + * @param handlerMethod 处理器方法 + * @param annotationClassName 注解类名称 + * @return 注解的值 + */ + @SuppressWarnings("unchecked") + public Map getMethodAnnotationValueMap(HandlerMethod handlerMethod, String annotationClassName) { + Class annotationClass = (Class) ClassLoaderUtil.loadClass(annotationClassName, false); + return AnnotationUtil.getAnnotationValueMap(handlerMethod.getMethod(), annotationClass); + } + + private Map getAnnotationValueMap(AnnotatedElement annotatedElement, Class annotationClass) { + return AnnotationUtil.getAnnotationValueMap(annotatedElement, annotationClass); + } +} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/JavadocResolver.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/JavadocResolver.java new file mode 100644 index 000000000..1e295b8a1 --- /dev/null +++ b/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, 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()); + } +} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/SaTokenAnnotationMetadataJavadocResolver.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/SaTokenAnnotationMetadataJavadocResolver.java new file mode 100644 index 000000000..4fe8933c7 --- /dev/null +++ b/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 { + + /** + * 默认元数据提供者,每次解析都会创建一个新的元数据对象 + */ + public static final Supplier 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 SA_CHECK_ROLE_CLASS; + private static final Class SA_CHECK_PERMISSION_CLASS; + private static final Class SA_IGNORE_CLASS; + private static final Class SA_CHECK_LOGIN_CLASS; + + + static { + // 通过类加载器去加载注解类Class实例 + SA_CHECK_ROLE_CLASS = (Class) ClassLoaderUtil.loadClass(SA_CHECK_ROLE_CLASS_NAME, false); + SA_CHECK_PERMISSION_CLASS = (Class) ClassLoaderUtil.loadClass(SA_CHECK_PERMISSION_CLASS_NAME, false); + SA_IGNORE_CLASS = (Class) ClassLoaderUtil.loadClass(SA_IGNORE_CLASS_NAME, false); + SA_CHECK_LOGIN_CLASS = (Class) 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 metadataProvider) { + super(metadataProvider); + } + + public SaTokenAnnotationMetadataJavadocResolver(int order) { + this(DEFAULT_METADATA_PROVIDER,order); + } + + public SaTokenAnnotationMetadataJavadocResolver(Supplier 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 annotationValueMap = getMethodAnnotationValueMap(handlerMethod, SA_CHECK_PERMISSION_CLASS); + resolvePermissionAnnotation(metadata, annotationValueMap); + } + // 解析获取类上的注解角色信息 + if (hasClassAnnotation(handlerMethod, SA_CHECK_PERMISSION_CLASS_NAME)) { + Map annotationValueMap = getClassAnnotationValueMap(handlerMethod, SA_CHECK_PERMISSION_CLASS); + resolvePermissionAnnotation(metadata, annotationValueMap); + } + } + + /** + * 解析权限注解 + */ + private void resolvePermissionAnnotation(SaTokenSecurityMetadata metadata, Map 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 annotationValueMap = getMethodAnnotationValueMap(handlerMethod, SA_CHECK_ROLE_CLASS); + resolveRoleAnnotation(metadata, annotationValueMap); + } + // 解析获取类上的注解角色信息 + if (hasClassAnnotation(handlerMethod, SA_CHECK_ROLE_CLASS_NAME)) { + Map annotationValueMap = getClassAnnotationValueMap(handlerMethod, SA_CHECK_ROLE_CLASS); + resolveRoleAnnotation(metadata, annotationValueMap); + } + } + + /** + * 解析角色注解 + */ + private void resolveRoleAnnotation(SaTokenSecurityMetadata metadata, Map 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) { + // 忽略解析错误 + } + } + +} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java index b6e0195d3..32be73227 100644 --- a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java +++ b/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 org.apache.commons.lang3.StringUtils; 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.ServerBaseUrlCustomizer; import org.springdoc.core.properties.SpringDocConfigProperties; @@ -86,9 +85,9 @@ public class OpenApiHandler extends OpenAPIService { private final PropertyResolverUtils propertyResolverUtils; /** - * 权限元数据解析器接口 + * Javadoc解析器接口 */ - private final SaTokenMetadataResolver saTokenJavadocResolver; + private final List javadocResolvers; /** * The javadoc provider. @@ -131,7 +130,7 @@ public class OpenApiHandler extends OpenAPIService { Optional> openApiBuilderCustomizers, Optional> serverBaseUrlCustomizers, Optional javadocProvider, - SaTokenMetadataResolver saTokenJavadocResolver) { + List javadocResolvers) { super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider); if (openAPI.isPresent()) { this.openAPI = openAPI.get(); @@ -148,7 +147,7 @@ public class OpenApiHandler extends OpenAPIService { this.openApiBuilderCustomisers = openApiBuilderCustomizers; this.serverBaseUrlCustomizers = serverBaseUrlCustomizers; this.javadocProvider = javadocProvider; - this.saTokenJavadocResolver = saTokenJavadocResolver; + this.javadocResolvers = javadocResolvers == null ? new ArrayList<>() : javadocResolvers; if (springDocConfigProperties.isUseFqn()) TypeNameResolver.std.setUseFqn(true); } @@ -235,16 +234,14 @@ public class OpenApiHandler extends OpenAPIService { if (StringUtils.isNotBlank(description)){ 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;