From 28772b8b3061f52299a14e8f58d2e109e84d7e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Thu, 5 Mar 2026 17:05:45 +0800 Subject: [PATCH 01/14] =?UTF-8?q?fix=20=E4=BF=AE=E6=AD=A3=20SysDictDataCon?= =?UTF-8?q?troller=20=E6=8E=A5=E5=8F=A3=E6=B3=A8=E9=87=8A=E5=8F=8A?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=B3=A8=E8=A7=A3=E4=B8=AD=E7=9A=84=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/controller/system/SysDictDataController.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java index ae6d5808c..5ad4272f2 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java @@ -83,7 +83,7 @@ public class SysDictDataController extends BaseController { } /** - * 新增字典类型 + * 新增字典数据 */ @SaCheckPermission("system:dict:add") @Log(title = "字典数据", businessType = BusinessType.INSERT) @@ -98,7 +98,7 @@ public class SysDictDataController extends BaseController { } /** - * 修改保存字典类型 + * 修改保存字典数据 */ @SaCheckPermission("system:dict:edit") @Log(title = "字典数据", businessType = BusinessType.UPDATE) @@ -113,12 +113,12 @@ public class SysDictDataController extends BaseController { } /** - * 删除字典类型 + * 删除字典数据 * * @param dictCodes 字典code串 */ @SaCheckPermission("system:dict:remove") - @Log(title = "字典类型", businessType = BusinessType.DELETE) + @Log(title = "字典数据", businessType = BusinessType.DELETE) @DeleteMapping("/{dictCodes}") public R remove(@PathVariable Long[] dictCodes) { dictDataService.deleteDictDataByIds(Arrays.asList(dictCodes)); From 1452ae9685e6ad12c6b4f951aa6627c61efa35a6 Mon Sep 17 00:00:00 2001 From: AprilWind <2100166581@qq.com> Date: Thu, 5 Mar 2026 09:06:58 +0000 Subject: [PATCH 02/14] =?UTF-8?q?!835=20update=20Sa-Token=20=E6=9D=83?= =?UTF-8?q?=E9=99=90=E7=A0=81=E5=B1=95=E7=A4=BA=EF=BC=8C=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E8=AF=A6=E6=83=85=E6=98=BE=E7=A4=BA=E6=9D=83=E9=99=90=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E6=84=9F=E8=B0=A2nextdoc4j=20*=20update=20=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA=E6=8E=A5=E5=8F=A3=E6=8F=8F=E8=BF=B0=EF=BC=8C=E5=90=88?= =?UTF-8?q?=E5=B9=B6JavaDoc=E6=9D=83=E9=99=90=E4=BF=A1=E6=81=AF=E5=88=B0?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E6=8F=8F=E8=BF=B0=E4=B8=AD=20*=20update=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96satoken=E4=BE=9D=E8=B5=96=E5=BC=95=E7=94=A8?= =?UTF-8?q?=EF=BC=8C=E5=87=8F=E5=B0=91=E8=80=A6=E5=90=88=E6=80=A7=20*=20up?= =?UTF-8?q?date=20=E4=BC=98=E5=8C=96=E6=8E=A5=E5=8F=A3=E6=8F=8F=E8=BF=B0?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E5=B1=95=E7=A4=BA=20*=20update=20Sa-Token=20?= =?UTF-8?q?=E6=9D=83=E9=99=90=E7=A0=81=E5=B1=95=E7=A4=BA=EF=BC=8C=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E8=AF=A6=E6=83=85=E6=98=BE=E7=A4=BA=E6=9D=83=E9=99=90?= =?UTF-8?q?=E7=A0=81=EF=BC=8C=E6=84=9F=E8=B0=A2nextdoc4j?= 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 | 15 +- .../core/enhancer/SaTokenJavadocResolver.java | 200 ++++++++++++++++++ .../enhancer/SaTokenMetadataResolver.java | 38 ++++ .../core/model/SaTokenSecurityMetadata.java | 175 +++++++++++++++ .../common/doc/handler/OpenApiHandler.java | 27 ++- .../controller/SaTokenTestController.java | 198 +++++++++++++++++ 7 files changed, 654 insertions(+), 4 deletions(-) create mode 100644 ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/enhancer/SaTokenJavadocResolver.java create 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/model/SaTokenSecurityMetadata.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SaTokenTestController.java diff --git a/ruoyi-common/ruoyi-common-doc/pom.xml b/ruoyi-common/ruoyi-common-doc/pom.xml index c6199a17c..390d34f01 100644 --- a/ruoyi-common/ruoyi-common-doc/pom.xml +++ b/ruoyi-common/ruoyi-common-doc/pom.xml @@ -21,6 +21,11 @@ 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 35b6ce9ea..b22d91139 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,6 +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.handler.OpenApiHandler; import org.springdoc.core.configuration.SpringDocConfiguration; import org.springdoc.core.customizers.OpenApiBuilderCustomizer; @@ -84,8 +86,9 @@ public class SpringDocConfig { SecurityService securityParser, SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, Optional> openApiBuilderCustomisers, - Optional> serverBaseUrlCustomisers, Optional javadocProvider) { - return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider); + Optional> serverBaseUrlCustomisers, Optional javadocProvider, + SaTokenMetadataResolver saTokenMetadataResolver) { + return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider, saTokenMetadataResolver); } /** @@ -112,6 +115,14 @@ public class SpringDocConfig { }; } + /** + * 注册JavaDoc权限解析器 + */ + @Bean + public SaTokenMetadataResolver saTokenJavadocResolver() { + return new SaTokenJavadocResolver(); + } + /** * 单独使用一个类便于判断 解决springdoc路径拼接重复问题 * 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 new file mode 100644 index 000000000..426f26a1e --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/enhancer/SaTokenJavadocResolver.java @@ -0,0 +1,200 @@ +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 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 = convertToStringArray(value); + String modeStr = mode != null ? mode.toString() : "AND"; + String typeStr = type != null ? type.toString() : ""; + String[] orRoles = convertToStringArray(orRole); + + metadata.addPermission(values, modeStr, typeStr, orRoles); + } catch (Exception e) { + // 忽略解析错误 + } + } + + /** + * 解析角色校验 + */ + 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 = convertToStringArray(value); + String modeStr = mode != null ? mode.toString() : "AND"; + String typeStr = type != null ? type.toString() : ""; + + metadata.addRole(values, modeStr, typeStr); + } catch (Exception e) { + // 忽略解析错误 + } + } + + /** + * 检查注解是否存在 + */ + 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; + } + } + + /** + * 转换为字符串数组 + */ + private String[] convertToStringArray(Object value) { + if (value == null) { + return new String[0]; + } + if (value instanceof String[]) { + return (String[])value; + } + if (value instanceof String) { + return new String[] {(String)value}; + } + return new String[0]; + } + +} 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 new file mode 100644 index 000000000..0b42b23c7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/enhancer/SaTokenMetadataResolver.java @@ -0,0 +1,38 @@ +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/model/SaTokenSecurityMetadata.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/model/SaTokenSecurityMetadata.java new file mode 100644 index 000000000..e0782a20c --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/model/SaTokenSecurityMetadata.java @@ -0,0 +1,175 @@ +package org.dromara.common.doc.core.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import lombok.Data; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 存储权限框架注解解析后的权限和角色信息 + * + * @author AprilWind + */ +@Data +@JsonInclude(Include.NON_EMPTY) +public class SaTokenSecurityMetadata { + + /** + * 权限校验信息列表(对应 @SaCheckPermission 注解) + */ + private List permissions = new ArrayList<>(); + + /** + * 角色校验信息列表(对应 @SaCheckRole 注解) + */ + private List roles = new ArrayList<>(); + + /** + * 是否忽略校验(对应 @SaIgnore 注解) + */ + private boolean ignore = false; + + /** + * 添加权限信息 + * + * @param values 权限值数组 + * @param mode 校验模式(AND/OR) + * @param type 权限类型 + * @param orRoles 或角色数组 + */ + public void addPermission(String[] values, String mode, String type, String[] orRoles) { + if (values != null && values.length > 0) { + AuthInfo authInfo = new AuthInfo(); + authInfo.setValues(values); + authInfo.setMode(mode); + authInfo.setType(type); + if (orRoles != null && orRoles.length > 0) { + authInfo.setOrValues(orRoles); + authInfo.setOrType("role"); + } + this.permissions.add(authInfo); + } + } + + /** + * 添加角色信息 + * + * @param values 角色值数组 + * @param mode 校验模式(AND/OR) + * @param type 角色类型 + */ + public void addRole(String[] values, String mode, String type) { + if (values != null && values.length > 0) { + AuthInfo authInfo = new AuthInfo(); + authInfo.setValues(values); + authInfo.setMode(mode); + authInfo.setType(type); + this.roles.add(authInfo); + } + } + + /** + * 生成 Markdown 结构的权限说明 + * + * @return Markdown 文本 + */ + public String toMarkdownString() { + StringBuilder sb = new StringBuilder(); + sb.append("

访问权限


"); + + if (ignore) { + sb.append("> **权限策略**:忽略权限检查
"); + return sb.toString(); + } + + if (!ignore && permissions.isEmpty() && roles.isEmpty()){ + sb.append("> **权限策略**:需要登录

"); + return sb.toString(); + } + + if (!permissions.isEmpty()) { + sb.append("**权限校验:**

"); + + permissions.forEach(p -> { + String permTags = Arrays.stream(p.getValues()) + .map(v -> "`" + v + "`") + .collect(Collectors.joining(p.getModeSymbol())); + + sb.append("- ").append(permTags).append("
"); + + if (p.getOrValues() != null && p.getOrValues().length > 0) { + String orTags = Arrays.stream(p.getOrValues()) + .map(v -> "`" + v + "`") + .collect(Collectors.joining(p.getModeSymbol())); + sb.append(" - 或角色:").append(orTags).append("
"); + } + }); + + sb.append("
"); + } + + if (!roles.isEmpty()) { + sb.append("**角色校验:**

"); + + roles.forEach(r -> { + + String roleTags = Arrays.stream(r.getValues()) + .map(v -> "`" + v + "`") + .collect(Collectors.joining(r.getModeSymbol())); + + sb.append("- ").append(roleTags).append("
"); + }); + } + + return sb.toString().trim(); + } + + /** + * 认证信息 + */ + @Data + @JsonInclude(Include.NON_EMPTY) + public static class AuthInfo { + + /** + * 权限或角色值数组 + */ + private String[] values; + + /** + * 校验模式(AND/OR) + */ + private String mode; + + /** + * 类型说明 + */ + private String type; + + /** + * 或权限/角色值数组(用于权限校验时的或角色校验) + */ + private String[] orValues; + + /** + * 或值的类型(role/permission) + */ + private String orType; + + /** + * 重写mode的获取方法,返回符号而非文字 + * @return AND→&,OR→|,默认→& + */ + public String getModeSymbol() { + if (mode == null) { + return " & "; // 默认AND,返回& + } + return "AND".equalsIgnoreCase(mode) ? " & " : " | "; + } + + } +} 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 56b73694d..830665942 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,6 +12,8 @@ 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.springdoc.core.customizers.OpenApiBuilderCustomizer; import org.springdoc.core.customizers.ServerBaseUrlCustomizer; import org.springdoc.core.properties.SpringDocConfigProperties; @@ -83,6 +85,11 @@ public class OpenApiHandler extends OpenAPIService { */ private final PropertyResolverUtils propertyResolverUtils; + /** + * 权限元数据解析器接口 + */ + private final SaTokenMetadataResolver saTokenJavadocResolver; + /** * The javadoc provider. */ @@ -123,7 +130,8 @@ public class OpenApiHandler extends OpenAPIService { SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, Optional> openApiBuilderCustomizers, Optional> serverBaseUrlCustomizers, - Optional javadocProvider) { + Optional javadocProvider, + SaTokenMetadataResolver saTokenJavadocResolver) { super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider); if (openAPI.isPresent()) { this.openAPI = openAPI.get(); @@ -140,6 +148,7 @@ public class OpenApiHandler extends OpenAPIService { this.openApiBuilderCustomisers = openApiBuilderCustomizers; this.serverBaseUrlCustomizers = serverBaseUrlCustomizers; this.javadocProvider = javadocProvider; + this.saTokenJavadocResolver = saTokenJavadocResolver; if (springDocConfigProperties.isUseFqn()) TypeNameResolver.std.setUseFqn(true); } @@ -219,7 +228,21 @@ public class OpenApiHandler extends OpenAPIService { else securityParser.buildSecurityRequirement(securityRequirements, operation); } - + String description = javadocProvider.get().getMethodJavadocDescription(handlerMethod.getMethod()); + String summary = javadocProvider.get().getFirstSentence(description); + 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; + } + } + operation.setDescription(description); return operation; } diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SaTokenTestController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SaTokenTestController.java new file mode 100644 index 000000000..c9dada111 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SaTokenTestController.java @@ -0,0 +1,198 @@ +package org.dromara.demo.controller; + +import cn.dev33.satoken.annotation.*; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * SaToken 权限测试 + * + * @author AprilWind + */ +@Slf4j +@RestController +@RequestMapping("/demo/SaToken") +public class SaTokenTestController { + + // ====================== 基础场景:单一校验规则 ====================== + + /** + * 场景1:仅登录校验(无角色/权限限制,只需登录态) + */ + @SaCheckLogin + @GetMapping("/basic/loginOnly") + public R loginOnly() { + log.info("【场景1】仅登录校验通过"); + return R.ok("仅登录校验通过,无需角色/权限"); + } + + /** + * 场景2:单一角色校验(AND模式,默认) + */ + @SaCheckRole("admin") + @GetMapping("/basic/singleRole") + public R singleRole() { + log.info("【场景2】单一角色(admin)校验通过"); + return R.ok("拥有admin角色,校验通过"); + } + + /** + * 场景3:单一权限校验(AND模式,默认) + */ + @SaCheckPermission("system:user:view") + @GetMapping("/basic/singlePermission") + public R singlePermission() { + log.info("【场景3】单一权限(system:user:view)校验通过"); + return R.ok("拥有system:user:view权限,校验通过"); + } + + /** + * 场景4:忽略所有权限校验(SaIgnore优先级最高) + */ + @SaIgnore + @SaCheckRole("none_exist") // 该注解会被忽略 + @GetMapping("/basic/ignoreAll") + public R ignoreAll() { + log.info("【场景4】SaIgnore忽略所有权限校验"); + return R.ok("SaIgnore生效,所有权限校验被忽略"); + } + + // ====================== 进阶场景:多条件组合(AND/OR) ====================== + + /** + * 场景5:多角色AND模式(必须同时拥有所有角色) + */ + @SaCheckRole(value = {"admin", "operator"}, mode = SaMode.AND) + @GetMapping("/advance/multiRoleAnd") + public R multiRoleAnd() { + log.info("【场景5】多角色AND模式(admin+operator)校验通过"); + return R.ok("同时拥有admin和operator角色,校验通过"); + } + + /** + * 场景6:多角色OR模式(拥有任一角色即可) + */ + @SaCheckRole(value = {"admin", "test"}, mode = SaMode.OR) + @GetMapping("/advance/multiRoleOr") + public R multiRoleOr() { + log.info("【场景6】多角色OR模式(admin|test)校验通过"); + return R.ok("拥有admin或test角色,校验通过"); + } + + /** + * 场景7:多权限AND模式(必须同时拥有所有权限) + */ + @SaCheckPermission(value = {"system:user:edit", "system:log:view"}, mode = SaMode.AND) + @GetMapping("/advance/multiPermAnd") + public R multiPermAnd() { + log.info("【场景7】多权限AND模式(system:user:edit+system:log:view)校验通过"); + return R.ok("同时拥有system:user:edit和system:log:view权限,校验通过"); + } + + /** + * 场景8:多权限OR模式(拥有任一权限即可) + */ + @SaCheckPermission(value = {"system:user:add", "system:user:delete"}, mode = SaMode.OR) + @GetMapping("/advance/multiPermOr") + public R multiPermOr() { + log.info("【场景8】多权限OR模式(system:user:add|system:user:delete)校验通过"); + return R.ok("拥有system:user:add或system:user:delete权限,校验通过"); + } + + // ====================== 高级场景:通配符/混合组合 ====================== + + /** + * 场景9:权限通配符匹配(前缀匹配) + * 拥有system:user:* 即可匹配所有用户模块权限 + */ + @SaCheckPermission("system:user:*") + @GetMapping("/advanced/permWildcardPrefix") + public R permWildcardPrefix() { + log.info("【场景9】权限通配符(system:user:*)校验通过"); + return R.ok("拥有system:user:*前缀权限,校验通过"); + } + + /** + * 场景10:角色通配符匹配(前缀匹配) + * 拥有admin_* 即可匹配所有admin开头的角色 + */ + @SaCheckRole("admin_*") + @GetMapping("/advanced/roleWildcardPrefix") + public R roleWildcardPrefix() { + log.info("【场景10】角色通配符(admin_*)校验通过"); + return R.ok("拥有admin_*前缀角色,校验通过"); + } + + /** + * 场景11:权限+角色混合AND模式(所有条件必须满足) + * 需同时满足:拥有admin角色 + 拥有system:user:all权限 + */ + @SaCheckRole("admin") + @SaCheckPermission("system:user:all") + @GetMapping("/advanced/mixRolePermAnd") + public R mixRolePermAnd() { + log.info("【场景11】角色+权限混合AND(admin+system:user:all)校验通过"); + return R.ok("拥有admin角色且拥有system:user:all权限,校验通过"); + } + + /** + * 场景12:权限+角色混合OR模式(任一条件满足即可) + * 满足任一:拥有super_admin角色 | 拥有system:manage权限 + */ + @SaCheckRole(value = {"super_admin"}, mode = SaMode.OR) + @SaCheckPermission(value = {"system:manage"}, mode = SaMode.OR) + @GetMapping("/advanced/mixRolePermOr") + public R mixRolePermOr() { + log.info("【场景12】角色+权限混合OR(super_admin|system:manage)校验通过"); + return R.ok("拥有super_admin角色或system:manage权限,校验通过"); + } + + /** + * 场景13:orRole参数(权限校验失败时,兜底角色校验) + * 核心逻辑:无system:user:export权限时,检查是否有admin/operator角色 + */ + @SaCheckPermission(value = "system:user:export", orRole = {"admin", "operator"}) + @GetMapping("/advanced/permWithOrRole") + public R permWithOrRole() { + log.info("【场景13】权限+orRole兜底校验通过"); + return R.ok("拥有system:user:export权限,或拥有admin/operator角色,校验通过"); + } + + // ====================== 特殊场景:临时权限/注解覆盖 ====================== + + /** + * 场景14:SaIgnore局部覆盖(方法注解覆盖类注解,若有) + * 假设类上有@SaCheckLogin,方法上@SaIgnore会覆盖 + */ + @SaIgnore + @GetMapping("/special/ignoreOverride") + public R ignoreOverride() { + log.info("【场景14】SaIgnore覆盖类级别权限注解"); + return R.ok("方法级SaIgnore覆盖类级别权限校验"); + } + + /** + * 场景15:临时权限校验(SaCheckPermission逻辑:临时权限>永久权限) + * 注:临时权限需通过SaToken API手动设置,如 SaHolder.getStpLogic().setTempPermission("system:temp:test") + */ + @SaCheckPermission("system:temp:test") + @GetMapping("/special/tempPermission") + public R tempPermission() { + log.info("【场景15】临时权限(system:temp:test)校验通过"); + return R.ok("临时权限校验通过(需先通过API设置临时权限)"); + } + + /** + * 场景16:登录类型指定(多端登录场景,如PC/APP/小程序) + * 注:需配合SaToken多账号体系配置 + */ + @SaCheckLogin(type = "PC") // 仅校验PC端的登录态 + @GetMapping("/special/loginTypeSpecify") + public R loginTypeSpecify() { + log.info("【场景16】指定登录类型(PC)校验通过"); + return R.ok("仅PC端登录态校验通过"); + } +} From d89e09b94e8712f202d81ec6e62abf0dd61fafc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Thu, 5 Mar 2026 17:32:51 +0800 Subject: [PATCH 03/14] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96=20!pr835=20?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/enhancer/SaTokenJavadocResolver.java | 27 ++++------------- .../common/doc/handler/OpenApiHandler.java | 30 +++++++++++-------- .../controller/SaTokenTestController.java | 4 +-- 3 files changed, 25 insertions(+), 36 deletions(-) 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 index 426f26a1e..f7c12525c 100644 --- 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 @@ -4,6 +4,7 @@ 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; @@ -113,13 +114,13 @@ public class SaTokenJavadocResolver implements SaTokenMetadataResolver { Object type = getAnnotationValue(annotation, "type"); Object orRole = getAnnotationValue(annotation, "orRole"); - String[] values = convertToStringArray(value); + String[] values = Convert.toStrArray(value); String modeStr = mode != null ? mode.toString() : "AND"; String typeStr = type != null ? type.toString() : ""; - String[] orRoles = convertToStringArray(orRole); + String[] orRoles = Convert.toStrArray(orRole); metadata.addPermission(values, modeStr, typeStr, orRoles); - } catch (Exception e) { + } catch (Exception ignore) { // 忽略解析错误 } } @@ -153,12 +154,12 @@ public class SaTokenJavadocResolver implements SaTokenMetadataResolver { Object mode = getAnnotationValue(annotation, "mode"); Object type = getAnnotationValue(annotation, "type"); - String[] values = convertToStringArray(value); + 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 e) { + } catch (Exception ignore) { // 忽略解析错误 } } @@ -181,20 +182,4 @@ public class SaTokenJavadocResolver implements SaTokenMetadataResolver { } } - /** - * 转换为字符串数组 - */ - private String[] convertToStringArray(Object value) { - if (value == null) { - return new String[0]; - } - if (value instanceof String[]) { - return (String[])value; - } - if (value instanceof String) { - return new String[] {(String)value}; - } - return new String[0]; - } - } 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 830665942..b6e0195d3 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 @@ -228,21 +228,25 @@ public class OpenApiHandler extends OpenAPIService { else securityParser.buildSecurityRequirement(securityRequirements, operation); } - String description = javadocProvider.get().getMethodJavadocDescription(handlerMethod.getMethod()); - String summary = javadocProvider.get().getFirstSentence(description); - 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; + + if (javadocProvider.isPresent()) { + String description = javadocProvider.get().getMethodJavadocDescription(handlerMethod.getMethod()); + String summary = javadocProvider.get().getFirstSentence(description); + 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; + } + } + operation.setDescription(description); } - operation.setDescription(description); + return operation; } diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SaTokenTestController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SaTokenTestController.java index c9dada111..66fd3cd84 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SaTokenTestController.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SaTokenTestController.java @@ -8,13 +8,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** - * SaToken 权限测试 + * SaToken 权限测试 接口文档输出测试 * * @author AprilWind */ @Slf4j @RestController -@RequestMapping("/demo/SaToken") +@RequestMapping("/demo/saTokenDoc") public class SaTokenTestController { // ====================== 基础场景:单一校验规则 ====================== From d190b8968122fad37fec0d779943bcf2eb9ed735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Fri, 6 Mar 2026 11:28:27 +0800 Subject: [PATCH 04/14] update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6557b21cd..96dc4ca5e 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Topiam IAM/IDaaS身份管理平台 - https://www.topiam.cn/
| 权限注解 | 采用 Sa-Token 支持注解 登录校验、角色校验、权限校验、二级认证校验、HttpBasic校验、忽略校验
角色与权限校验支持多种条件 如 `AND` `OR` 或 `权限 OR 角色` 等复杂表达式 | 只支持是否存在匹配 | | 三方鉴权 | 采用 JustAuth 第三方登录组件 支持微信、钉钉等数十种三方认证 | 无 | | 关系数据库支持 | 原生支持 MySQL、Oracle、PostgreSQL、SQLServer
可同时使用异构切换(支持其他 mybatis-plus 支持的所有数据库 只需要增加jdbc依赖即可使用 达梦金仓等均有成功案例) | 支持 Mysql、Oracle 不支持同时使用、不支持异构切换 | -| 缓存数据库 | 支持 Redis 5-7 支持大部分新功能特性 如 分布式限流、分布式队列 | Redis 简单 get set 支持 | +| 缓存数据库 | 支持 Redis >= 6 支持大部分新功能特性 如 分布式限流、分布式队列 | Redis 简单 get set 支持 | | Redis客户端 | 采用 Redisson Redis官方推荐 基于Netty的客户端工具
支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如: keys被转换为scan
支持单机、哨兵、单主集群、多主集群等模式 | Lettuce + RedisTemplate 支持模式少 工具使用繁琐
连接池采用 common-pool Bug多经常性出问题 | | 缓存注解 | 采用 Spring-Cache 注解 对其扩展了实现支持了更多功能
例如 过期时间 最大空闲时间 组最大长度等 只需一个注解即可完成数据自动缓存 | 需手动编写Redis代码逻辑 | | ORM框架 | 采用 Mybatis-Plus 基于对象几乎不用写SQL全java操作 功能强大插件众多
例如多租户插件 分页插件 乐观锁插件等等 | 采用 Mybatis 基于XML需要手写SQL | From 9bf8ae5583a2197c9cfda0599c1252396a722aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Fri, 6 Mar 2026 13:08:05 +0800 Subject: [PATCH 05/14] =?UTF-8?q?fix=20=E4=BF=AE=E5=A4=8D=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E8=B6=85=E7=BA=A7=E7=AE=A1=E7=90=86=E5=91=98=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E5=90=8E=E6=96=B0=E5=A2=9E=E8=A7=92=E8=89=B2=E5=88=86?= =?UTF-8?q?=E9=85=8D=E6=A0=A1=E9=AA=8C=EF=BC=8C=E9=81=BF=E5=85=8D=E6=97=A0?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E5=88=86=E9=85=8D=E6=97=B6=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/dromara/system/service/impl/SysUserServiceImpl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java index 39ad4cb91..a75e9bbc6 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java @@ -497,6 +497,11 @@ public class SysUserServiceImpl implements ISysUserService, UserService { roleList.remove(SystemConstants.SUPER_ADMIN_ID); } + // 移除超管角色后若无剩余角色,说明仅选了超管角色且不允许分配,显式报错 + if (roleList.isEmpty()) { + throw new ServiceException("不允许为普通用户分配超级管理员角色,请至少选择一个其他角色"); + } + // 校验是否有权限访问这些角色(含数据权限控制) if (roleMapper.selectRoleCount(roleList) != roleList.size()) { throw new ServiceException("没有权限访问角色的数据"); From f773818642017fb45e598c7da2e98e2f7d151305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Fri, 6 Mar 2026 16:49:36 +0800 Subject: [PATCH 06/14] =?UTF-8?q?fix=20=E4=BF=AE=E5=A4=8D=20jackson=20crea?= =?UTF-8?q?teContextual=20=E7=94=A8=E6=B3=95=E4=B8=8D=E6=A0=87=E5=87=86?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E5=8F=AF=E8=83=BD=E5=87=BA=E7=8E=B0=E7=9A=84?= =?UTF-8?q?=E5=B9=B6=E5=8F=91=E9=97=AE=E9=A2=98(https://gitee.com/dromara/?= =?UTF-8?q?RuoYi-Cloud-Plus/issues/IFAM5Z)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sensitive/handler/SensitiveHandler.java | 17 ++++++++++------- .../core/handler/TranslationHandler.java | 9 ++++++--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java index d454724d7..e4a31dada 100644 --- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java +++ b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java @@ -25,9 +25,15 @@ import java.util.Objects; @Slf4j public class SensitiveHandler extends JsonSerializer implements ContextualSerializer { - private SensitiveStrategy strategy; - private String[] roleKey; - private String[] perms; + private final SensitiveStrategy strategy; + private final String[] roleKey; + private final String[] perms; + + public SensitiveHandler(SensitiveStrategy strategy, String[] strings, String[] perms) { + this.strategy = strategy; + this.roleKey = strings; + this.perms = perms; + } @Override public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { @@ -48,10 +54,7 @@ public class SensitiveHandler extends JsonSerializer implements Contextu public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { Sensitive annotation = property.getAnnotation(Sensitive.class); if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) { - this.strategy = annotation.strategy(); - this.roleKey = annotation.roleKey(); - this.perms = annotation.perms(); - return this; + return new SensitiveHandler(annotation.strategy(), annotation.roleKey(), annotation.perms()); } return prov.findValueSerializer(property.getType(), property); } diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java index e8c03acdc..95a7ded9f 100644 --- a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java @@ -31,7 +31,11 @@ public class TranslationHandler extends JsonSerializer implements Contex */ public static final Map> TRANSLATION_MAPPER = new ConcurrentHashMap<>(); - private Translation translation; + private final Translation translation; + + public TranslationHandler(Translation translation) { + this.translation = translation; + } @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { @@ -63,8 +67,7 @@ public class TranslationHandler extends JsonSerializer implements Contex public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { Translation translation = property.getAnnotation(Translation.class); if (Objects.nonNull(translation)) { - this.translation = translation; - return this; + return new TranslationHandler(translation); } return prov.findValueSerializer(property.getType(), property); } From 337c2f717078cb4c0b29dd466058371fb1f32cb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Fri, 6 Mar 2026 16:54:50 +0800 Subject: [PATCH 07/14] =?UTF-8?q?fix=20=E4=BF=AE=E5=A4=8D=20jackson=20crea?= =?UTF-8?q?teContextual=20=E7=94=A8=E6=B3=95=E4=B8=8D=E6=A0=87=E5=87=86?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E5=8F=AF=E8=83=BD=E5=87=BA=E7=8E=B0=E7=9A=84?= =?UTF-8?q?=E5=B9=B6=E5=8F=91=E9=97=AE=E9=A2=98(https://gitee.com/dromara/?= =?UTF-8?q?RuoYi-Cloud-Plus/issues/IFAM5Z)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/sensitive/handler/SensitiveHandler.java | 9 +++++++++ .../translation/core/handler/TranslationHandler.java | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java index e4a31dada..e5eed76c0 100644 --- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java +++ b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java @@ -29,6 +29,15 @@ public class SensitiveHandler extends JsonSerializer implements Contextu private final String[] roleKey; private final String[] perms; + /** + * 提供给 jackson 创建上下文序列化器时使用 不然会报错 + */ + public SensitiveHandler() { + this.strategy = null; + this.roleKey = null; + this.perms = null; + } + public SensitiveHandler(SensitiveStrategy strategy, String[] strings, String[] perms) { this.strategy = strategy; this.roleKey = strings; diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java index 95a7ded9f..2322cdf5d 100644 --- a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java @@ -33,6 +33,13 @@ public class TranslationHandler extends JsonSerializer implements Contex private final Translation translation; + /** + * 提供给 jackson 创建上下文序列化器时使用 不然会报错 + */ + public TranslationHandler() { + this.translation = null; + } + public TranslationHandler(Translation translation) { this.translation = translation; } 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 08/14] =?UTF-8?q?update=20=E9=80=9A=E8=BF=87=E7=B1=BB?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E7=9A=84=E6=96=B9=E5=BC=8F=E4=BC=98=E5=8C=96?= =?UTF-8?q?=20Javadoc=20=E8=A7=A3=E6=9E=90=E5=99=A8=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=89=A7=E8=A1=8C=E5=A4=9A=E4=B8=AA=20Javadoc=20?= =?UTF-8?q?=E8=A7=A3=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; From 53121316355a14fe7dbeea5e994913e3b42c04a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Fri, 6 Mar 2026 17:57:05 +0800 Subject: [PATCH 09/14] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SaTokenAnnotationMetadataJavadocResolver.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) 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 index 4fe8933c7..9e09619de 100644 --- 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 @@ -27,10 +27,11 @@ public class SaTokenAnnotationMetadataJavadocResolver extends AbstractMetadataJa */ 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 String BASE_CLASS_NAME = "cn.dev33.satoken.annotation"; + private static final String SA_CHECK_ROLE_CLASS_NAME = BASE_CLASS_NAME + ".SaCheckRole"; + private static final String SA_CHECK_PERMISSION_CLASS_NAME = BASE_CLASS_NAME + ".SaCheckPermission"; + private static final String SA_IGNORE_CLASS_NAME = BASE_CLASS_NAME + ".SaIgnore"; + private static final String SA_CHECK_LOGIN_NAME = BASE_CLASS_NAME + ".SaCheckLogin"; private static final Class SA_CHECK_ROLE_CLASS; private static final Class SA_CHECK_PERMISSION_CLASS; @@ -44,8 +45,8 @@ public class SaTokenAnnotationMetadataJavadocResolver extends AbstractMetadataJa 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)); + if (log.isDebugEnabled()) { + log.debug("SaTokenAnnotationJavadocResolver init success, load annotation class: {}", List.of(SA_CHECK_ROLE_CLASS, SA_CHECK_PERMISSION_CLASS, SA_IGNORE_CLASS, SA_CHECK_LOGIN_CLASS)); } } From 3cbbd0698d7291eb2d9626d6a7fbbe2753a198e2 Mon Sep 17 00:00:00 2001 From: gssong <1742057357@qq.com> Date: Fri, 6 Mar 2026 18:35:47 +0800 Subject: [PATCH 10/14] =?UTF-8?q?add=20=E5=A2=9E=E5=8A=A0=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E8=BD=AC=E5=8A=9E=E7=AD=89=E6=B6=88=E6=81=AF=E6=8F=90?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/FlowConstant.java | 20 ------- .../common/enums/TaskOperationEnum.java | 53 +++++++++++++++++++ .../workflow/domain/bo/TaskOperationBo.java | 5 ++ .../service/impl/FlwTaskServiceImpl.java | 46 ++++++++++------ 4 files changed, 89 insertions(+), 35 deletions(-) create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskOperationEnum.java diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java index 88372f0b7..203f3f667 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java @@ -23,26 +23,6 @@ public interface FlowConstant { */ String INITIATOR_DEPT_ID = "initiatorDeptId"; - /** - * 委托 - */ - String DELEGATE_TASK = "delegateTask"; - - /** - * 转办 - */ - String TRANSFER_TASK = "transferTask"; - - /** - * 加签 - */ - String ADD_SIGNATURE = "addSignature"; - - /** - * 减签 - */ - String REDUCTION_SIGNATURE = "reductionSignature"; - /** * 流程分类Id转名称 */ diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskOperationEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskOperationEnum.java new file mode 100644 index 000000000..8c050a28f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskOperationEnum.java @@ -0,0 +1,53 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 任务操作类型枚举 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum TaskOperationEnum { + + /** + * 委派 + */ + DELEGATE_TASK("delegateTask", "委派"), + + /** + * 转办 + */ + TRANSFER_TASK("transferTask", "转办"), + + /** + * 加签 + */ + ADD_SIGNATURE("addSignature", "加签"), + + /** + * 减签 + */ + REDUCTION_SIGNATURE("reductionSignature", "减签"); + + private final String code; + private final String desc; + + private static final Map CODE_MAP = Arrays.stream(values()) + .collect(Collectors.toConcurrentMap(TaskOperationEnum::getCode, Function.identity())); + + /** + * 根据 code 获取枚举 + */ + public static TaskOperationEnum getByCode(String code) { + return CODE_MAP.get(code); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java index 4348e310c..0846e73b4 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java @@ -40,6 +40,11 @@ public class TaskOperationBo implements Serializable { @NotNull(message = "任务id不能为空") private Long taskId; + /** + * 消息类型 + */ + private List messageType; + /** * 意见或备注信息(可选) */ diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java index 0a8bdc72d..3624f8240 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java @@ -46,6 +46,7 @@ import org.dromara.warm.flow.orm.mapper.FlowTaskMapper; import org.dromara.workflow.common.ConditionalOnEnable; import org.dromara.workflow.common.constant.FlowConstant; import org.dromara.workflow.common.enums.TaskAssigneeType; +import org.dromara.workflow.common.enums.TaskOperationEnum; import org.dromara.workflow.common.enums.TaskStatusEnum; import org.dromara.workflow.domain.FlowInstanceBizExt; import org.dromara.workflow.domain.bo.*; @@ -719,13 +720,19 @@ public class FlwTaskServiceImpl implements IFlwTaskService { @Override @Transactional(rollbackFor = Exception.class) public boolean taskOperation(TaskOperationBo bo, String taskOperation) { + TaskOperationEnum op = TaskOperationEnum.getByCode(taskOperation); + if (op == null) { + log.error("Invalid operation type:{} ", taskOperation); + throw new ServiceException("Invalid operation type " + taskOperation); + } + FlowParams flowParams = FlowParams.build().message(bo.getMessage()); if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) { flowParams.ignore(true); } // 根据操作类型构建 FlowParams - switch (taskOperation) { + switch (op) { case DELEGATE_TASK, TRANSFER_TASK -> { ValidatorUtils.validate(bo, AddGroup.class); flowParams.addHandlers(Collections.singletonList(bo.getUserId())); @@ -738,47 +745,56 @@ public class FlwTaskServiceImpl implements IFlwTaskService { ValidatorUtils.validate(bo, EditGroup.class); flowParams.reductionHandlers(bo.getUserIds()); } - default -> { - log.error("Invalid operation type:{} ", taskOperation); - throw new ServiceException("Invalid operation type " + taskOperation); - } } Long taskId = bo.getTaskId(); Task task = taskService.getById(taskId); FlowNode flowNode = getByNodeCode(task.getNodeCode(), task.getDefinitionId()); - if (ADD_SIGNATURE.equals(taskOperation) || REDUCTION_SIGNATURE.equals(taskOperation)) { + if (op == TaskOperationEnum.ADD_SIGNATURE || op == TaskOperationEnum.REDUCTION_SIGNATURE) { if (CooperateType.isOrSign(flowNode.getNodeRatio())) { throw new ServiceException(task.getNodeName() + "不是会签或票签节点!"); } } + + // 发送消息给相关用户 + List messageType = bo.getMessageType(); + if (CollUtil.isNotEmpty(messageType)) { + List userIdList = new ArrayList<>(); + if (StrUtil.isNotBlank(bo.getUserId())) { + userIdList.add(Convert.toLong(bo.getUserId())); + } + if (CollUtil.isNotEmpty(bo.getUserIds())) { + userIdList.addAll(StreamUtils.toList(bo.getUserIds(), Convert::toLong)); + } + if (CollUtil.isNotEmpty(userIdList)) { + flwCommonService.sendMessage( + messageType, + StringUtils.isNotBlank(bo.getMessage()) ? bo.getMessage() : "单据「" + op.getDesc() + "」通知", + "单据「" + op.getDesc() + "」提醒", + userService.selectListByIds(userIdList) + ); + } + } // 设置任务状态并执行对应的任务操作 - switch (taskOperation) { - //委派任务 + switch (op) { case DELEGATE_TASK -> { flowParams.hisStatus(TaskStatusEnum.DEPUTE.getStatus()); return taskService.depute(taskId, flowParams); } - //转办任务 case TRANSFER_TASK -> { flowParams.hisStatus(TaskStatusEnum.TRANSFER.getStatus()); return taskService.transfer(taskId, flowParams); } - //加签,增加办理人 case ADD_SIGNATURE -> { flowParams.hisStatus(TaskStatusEnum.SIGN.getStatus()); return taskService.addSignature(taskId, flowParams); } - //减签,减少办理人 case REDUCTION_SIGNATURE -> { flowParams.hisStatus(TaskStatusEnum.SIGN_OFF.getStatus()); return taskService.reductionSignature(taskId, flowParams); } - default -> { - log.error("Invalid operation type:{} ", taskOperation); - throw new ServiceException("Invalid operation type " + taskOperation); - } } + return false; } /** From 07b29e06cfdd3d49b53157e186b7e46b0dd43fd3 Mon Sep 17 00:00:00 2001 From: gssong <1742057357@qq.com> Date: Mon, 9 Mar 2026 10:12:02 +0800 Subject: [PATCH 11/14] =?UTF-8?q?update=20=E8=B0=83=E6=95=B4=E8=BD=AC?= =?UTF-8?q?=E5=8A=9E=E7=AD=89=E6=B6=88=E6=81=AF=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/FlwTaskServiceImpl.java | 73 ++++++++++--------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java index 3624f8240..acbc9a75c 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java @@ -144,9 +144,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { throw new ServiceException("流程【" + startProcessBo.getFlowCode() + "】未发布,请先在流程设计器中发布流程定义"); } Dict dict = JsonUtils.parseMap(definition.getExt()); - boolean autoPass = !ObjectUtil.isNull(dict) && dict.getBool(FlowConstant.AUTO_PASS); - variables.put(FlowConstant.AUTO_PASS, autoPass); - variables.put(FlowConstant.BUSINESS_CODE, this.generateBusinessCode(bizExt)); + boolean autoPass = !ObjectUtil.isNull(dict) && dict.getBool(AUTO_PASS); + variables.put(AUTO_PASS, autoPass); + variables.put(BUSINESS_CODE, this.generateBusinessCode(bizExt)); FlowParams flowParams = FlowParams.build() .handler(startProcessBo.getHandler()) .flowCode(startProcessBo.getFlowCode()) @@ -208,11 +208,11 @@ public class FlwTaskServiceImpl implements IFlwTaskService { List flowCopyList = completeTaskBo.getFlowCopyList(); // 设置抄送人 Map variables = completeTaskBo.getVariables(); - variables.put(FlowConstant.FLOW_COPY_LIST, flowCopyList); + variables.put(FLOW_COPY_LIST, flowCopyList); // 消息类型 - variables.put(FlowConstant.MESSAGE_TYPE, messageType); + variables.put(MESSAGE_TYPE, messageType); // 消息通知 - variables.put(FlowConstant.MESSAGE_NOTICE, notice); + variables.put(MESSAGE_NOTICE, notice); FlowTask flowTask = flowTaskMapper.selectById(taskId); @@ -222,7 +222,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService { Instance ins = insService.getById(flowTask.getInstanceId()); // 检查流程状态是否为草稿、已撤销或已退回状态,若是则执行流程提交监听 if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) { - variables.put(FlowConstant.SUBMIT, true); + variables.put(SUBMIT, true); } // 设置弹窗处理人 Map assigneeMap = setPopAssigneeMap(completeTaskBo.getAssigneeMap(), ins.getVariableMap()); @@ -275,9 +275,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { flowParams. message("流程引擎自动审批!"). variable(Map.of( - FlowConstant.SUBMIT, false, - FlowConstant.FLOW_COPY_LIST, Collections.emptyList(), - FlowConstant.MESSAGE_NOTICE, StringUtils.EMPTY)); + SUBMIT, false, + FLOW_COPY_LIST, Collections.emptyList(), + MESSAGE_NOTICE, StringUtils.EMPTY)); skipTask(task.getId(), flowParams, instanceId, true); } } @@ -489,9 +489,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { Map variable = new HashMap<>(); // 消息类型 - variable.put(FlowConstant.MESSAGE_TYPE, messageType); + variable.put(MESSAGE_TYPE, messageType); // 消息通知 - variable.put(FlowConstant.MESSAGE_NOTICE, notice); + variable.put(MESSAGE_NOTICE, notice); FlowParams flowParams = FlowParams.build() .nodeCode(bo.getNodeCode()) @@ -756,9 +756,29 @@ public class FlwTaskServiceImpl implements IFlwTaskService { } } - // 发送消息给相关用户 - List messageType = bo.getMessageType(); - if (CollUtil.isNotEmpty(messageType)) { + // 设置任务状态并执行对应的任务操作 + boolean result = false; + switch (op) { + case DELEGATE_TASK -> { + flowParams.hisStatus(TaskStatusEnum.DEPUTE.getStatus()); + result = taskService.depute(taskId, flowParams); + } + case TRANSFER_TASK -> { + flowParams.hisStatus(TaskStatusEnum.TRANSFER.getStatus()); + result = taskService.transfer(taskId, flowParams); + } + case ADD_SIGNATURE -> { + flowParams.hisStatus(TaskStatusEnum.SIGN.getStatus()); + result = taskService.addSignature(taskId, flowParams); + } + case REDUCTION_SIGNATURE -> { + flowParams.hisStatus(TaskStatusEnum.SIGN_OFF.getStatus()); + result = taskService.reductionSignature(taskId, flowParams); + } + } + + // 操作执行成功后再发送消息 + if (result && CollUtil.isNotEmpty(bo.getMessageType())) { List userIdList = new ArrayList<>(); if (StrUtil.isNotBlank(bo.getUserId())) { userIdList.add(Convert.toLong(bo.getUserId())); @@ -768,33 +788,14 @@ public class FlwTaskServiceImpl implements IFlwTaskService { } if (CollUtil.isNotEmpty(userIdList)) { flwCommonService.sendMessage( - messageType, + bo.getMessageType(), StringUtils.isNotBlank(bo.getMessage()) ? bo.getMessage() : "单据「" + op.getDesc() + "」通知", "单据「" + op.getDesc() + "」提醒", userService.selectListByIds(userIdList) ); } } - // 设置任务状态并执行对应的任务操作 - switch (op) { - case DELEGATE_TASK -> { - flowParams.hisStatus(TaskStatusEnum.DEPUTE.getStatus()); - return taskService.depute(taskId, flowParams); - } - case TRANSFER_TASK -> { - flowParams.hisStatus(TaskStatusEnum.TRANSFER.getStatus()); - return taskService.transfer(taskId, flowParams); - } - case ADD_SIGNATURE -> { - flowParams.hisStatus(TaskStatusEnum.SIGN.getStatus()); - return taskService.addSignature(taskId, flowParams); - } - case REDUCTION_SIGNATURE -> { - flowParams.hisStatus(TaskStatusEnum.SIGN_OFF.getStatus()); - return taskService.reductionSignature(taskId, flowParams); - } - } - return false; + return result; } /** From 75d8d374bc08e489031811a1f736d0b81a8e702e Mon Sep 17 00:00:00 2001 From: AprilWind <2100166581@qq.com> Date: Tue, 10 Mar 2026 14:08:44 +0800 Subject: [PATCH 12/14] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E7=94=A8=E6=88=B7=E6=98=B5=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/dromara/common/core/service/UserService.java | 12 ++++++------ .../system/service/impl/SysUserServiceImpl.java | 12 ++++++------ .../org/dromara/workflow/domain/bo/FlowCopyBo.java | 4 ++-- .../org/dromara/workflow/domain/vo/FlowCopyVo.java | 4 ++-- .../workflow/listener/WorkflowGlobalListener.java | 4 ++-- .../workflow/service/impl/FlwTaskServiceImpl.java | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java index eefeef011..204b21412 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java @@ -21,18 +21,18 @@ public interface UserService { String selectUserNameById(Long userId); /** - * 通过用户ID查询用户账户 + * 通过用户ID查询用户昵称 * * @param userId 用户ID - * @return 用户名称 + * @return 用户昵称 */ String selectNicknameById(Long userId); /** - * 通过用户ID查询用户账户 + * 通过用户ID查询用户昵称 * * @param userIds 用户ID 多个用逗号隔开 - * @return 用户名称 + * @return 用户昵称 */ String selectNicknameByIds(String userIds); @@ -93,10 +93,10 @@ public interface UserService { List selectUsersByPostIds(List postIds); /** - * 根据用户 ID 列表查询用户名称映射关系 + * 根据用户 ID 列表查询用户昵称映射关系 * * @param userIds 用户 ID 列表 - * @return Map,其中 key 为用户 ID,value 为对应的用户名称 + * @return Map,其中 key 为用户 ID,value 为对应的用户昵称 */ Map selectUserNamesByIds(List userIds); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java index a75e9bbc6..62a3d543a 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java @@ -599,10 +599,10 @@ public class SysUserServiceImpl implements ISysUserService, UserService { } /** - * 通过用户ID查询用户账户 + * 通过用户ID查询用户昵称 * * @param userId 用户ID - * @return 用户账户 + * @return 用户昵称 */ @Override @Cacheable(cacheNames = CacheNames.SYS_NICKNAME, key = "#userId") @@ -613,10 +613,10 @@ public class SysUserServiceImpl implements ISysUserService, UserService { } /** - * 通过用户ID查询用户账户 + * 通过用户ID查询用户昵称 * * @param userIds 用户ID 多个用逗号隔开 - * @return 用户账户 + * @return 用户昵称 */ @Override public String selectNicknameByIds(String userIds) { @@ -756,10 +756,10 @@ public class SysUserServiceImpl implements ISysUserService, UserService { } /** - * 根据用户 ID 列表查询用户名称映射关系 + * 根据用户 ID 列表查询用户昵称映射关系 * * @param userIds 用户 ID 列表 - * @return Map,其中 key 为用户 ID,value 为对应的用户名称 + * @return Map,其中 key 为用户 ID,value 为对应的用户昵称 */ @Override public Map selectUserNamesByIds(List userIds) { diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java index a45e52109..894174929 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java @@ -23,8 +23,8 @@ public class FlowCopyBo implements Serializable { private Long userId; /** - * 用户名称 + * 用户昵称 */ - private String userName; + private String nickName; } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCopyVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCopyVo.java index 67ef9e2c3..c58071570 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCopyVo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCopyVo.java @@ -24,10 +24,10 @@ public class FlowCopyVo implements Serializable { private Long userId; /** - * 用户名称 + * 用户昵称 */ @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "userId") - private String userName; + private String nickName; public FlowCopyVo(Long userId) { this.userId = userId; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java index efd24ffd6..c21523f18 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java @@ -84,7 +84,7 @@ public class WorkflowGlobalListener implements GlobalListener { FlowCopyBo bo = new FlowCopyBo(); Long id = Convert.toLong(x); bo.setUserId(id); - bo.setUserName(userService.selectUserNameById(id)); + bo.setNickName(userService.selectNicknameById(id)); return bo; }); variable.put(FlowConstant.FLOW_COPY_LIST, list); @@ -159,7 +159,7 @@ public class WorkflowGlobalListener implements GlobalListener { flowTask.setPermissionList(List.of(userIdArray)); // 移除已处理的状态变量 variable.remove(nodeKey); - FlowEngine.insService().removeVariables(flowTask.getInstanceId(),nodeKey); + FlowEngine.insService().removeVariables(flowTask.getInstanceId(), nodeKey); } } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java index acbc9a75c..71170ba6e 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java @@ -342,7 +342,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService { FlowParams flowParams = FlowParams.build() .skipType(SkipType.NONE.getKey()) .hisStatus(TaskStatusEnum.COPY.getStatus()) - .message("【抄送给】" + StreamUtils.join(flowCopyList, FlowCopyBo::getUserName)); + .message("【抄送给】" + StreamUtils.join(flowCopyList, FlowCopyBo::getNickName)); HisTask hisTask = hisTaskService.setSkipHisTask(task, flowNode, flowParams); hisTask.setCreateTime(updateTime); hisTask.setUpdateTime(updateTime); From aaede419bc252158204d32f98cdb03b7b713541b Mon Sep 17 00:00:00 2001 From: AprilWind <2100166581@qq.com> Date: Tue, 10 Mar 2026 14:25:29 +0800 Subject: [PATCH 13/14] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E7=94=A8=E6=88=B7=E6=98=B5=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dromara/common/core/constant/CacheNames.java | 2 +- .../java/org/dromara/common/core/domain/dto/FlowCopyDTO.java | 4 ++-- .../org/dromara/common/core/domain/dto/UserOnlineDTO.java | 2 +- .../java/org/dromara/common/core/service/UserService.java | 2 +- .../dromara/common/translation/constant/TransConstant.java | 2 +- .../common/translation/core/impl/NicknameTranslationImpl.java | 2 +- .../main/java/org/dromara/demo/domain/vo/ExportDemoVo.java | 4 ++-- .../main/java/org/dromara/system/domain/SysUserOnline.java | 2 +- .../java/org/dromara/system/domain/vo/SysUserExportVo.java | 4 ++-- .../java/org/dromara/system/domain/vo/SysUserImportVo.java | 4 ++-- .../main/java/org/dromara/system/service/ISysUserService.java | 2 +- .../org/dromara/system/service/impl/SysMenuServiceImpl.java | 2 +- .../org/dromara/system/service/impl/SysUserServiceImpl.java | 4 ++-- .../workflow/service/impl/FlwTaskAssigneeServiceImpl.java | 2 +- 14 files changed, 19 insertions(+), 19 deletions(-) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java index c38f39b47..89d6ebd0b 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java @@ -52,7 +52,7 @@ public interface CacheNames { String SYS_USER_NAME = "sys_user_name#30d"; /** - * 用户名称 + * 用户昵称 */ String SYS_NICKNAME = "sys_nickname#30d"; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java index 2f20b21f7..6001331d5 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java @@ -23,8 +23,8 @@ public class FlowCopyDTO implements Serializable { private Long userId; /** - * 用户名称 + * 用户昵称 */ - private String userName; + private String nickName; } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java index 43d8c3c11..4f6534ffa 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java @@ -30,7 +30,7 @@ public class UserOnlineDTO implements Serializable { private String deptName; /** - * 用户名称 + * 用户账号 */ private String userName; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java index 204b21412..c61b1ed90 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java @@ -98,6 +98,6 @@ public interface UserService { * @param userIds 用户 ID 列表 * @return Map,其中 key 为用户 ID,value 为对应的用户昵称 */ - Map selectUserNamesByIds(List userIds); + Map selectUserNicksByIds(List userIds); } diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java index c084ea1a0..50dce798a 100644 --- a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java @@ -13,7 +13,7 @@ public interface TransConstant { String USER_ID_TO_NAME = "user_id_to_name"; /** - * 用户id转用户名称 + * 用户id转用户昵称 */ String USER_ID_TO_NICKNAME = "user_id_to_nickname"; diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java index d1720f714..06be37fcc 100644 --- a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java @@ -7,7 +7,7 @@ import org.dromara.common.translation.constant.TransConstant; import org.dromara.common.translation.core.TranslationInterface; /** - * 用户名称翻译实现 + * 用户昵称翻译实现 * * @author may */ diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java index b42ce7679..4a6b0dfba 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java @@ -35,8 +35,8 @@ public class ExportDemoVo implements Serializable { /** * 用户昵称 */ - @ExcelProperty(value = "用户名", index = 0) - @NotEmpty(message = "用户名不能为空", groups = AddGroup.class) + @ExcelProperty(value = "用户昵称", index = 0) + @NotEmpty(message = "用户昵称不能为空", groups = AddGroup.class) private String nickName; /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java index ba30eb609..f3b5f87a3 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java @@ -21,7 +21,7 @@ public class SysUserOnline { private String deptName; /** - * 用户名称 + * 用户账号 */ private String userName; diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java index c60087202..ea9751bd0 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java @@ -34,13 +34,13 @@ public class SysUserExportVo implements Serializable { /** * 用户账号 */ - @ExcelProperty(value = "登录名称") + @ExcelProperty(value = "用户账号") private String userName; /** * 用户昵称 */ - @ExcelProperty(value = "用户名称") + @ExcelProperty(value = "用户昵称") private String nickName; /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java index 4507f631e..f4289cba0 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java @@ -38,13 +38,13 @@ public class SysUserImportVo implements Serializable { /** * 用户账号 */ - @ExcelProperty(value = "登录名称") + @ExcelProperty(value = "用户账号") private String userName; /** * 用户昵称 */ - @ExcelProperty(value = "用户名称") + @ExcelProperty(value = "用户昵称") private String nickName; /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java index 9e255f992..c1f77ae8d 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java @@ -101,7 +101,7 @@ public interface ISysUserService { String selectUserPostGroup(Long userId); /** - * 校验用户名称是否唯一 + * 校验用户账号是否唯一 * * @param user 用户信息 * @return 结果 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java index 0c69b1f3f..fe2f3577e 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java @@ -112,7 +112,7 @@ public class SysMenuServiceImpl implements ISysMenuService { /** * 根据用户ID查询菜单 * - * @param userId 用户名称 + * @param userId 用户ID * @return 菜单列表 */ @Override diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java index 62a3d543a..a6a301fed 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java @@ -232,7 +232,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService { } /** - * 校验用户名称是否唯一 + * 校验用户账号是否唯一 * * @param user 用户信息 * @return 结果 @@ -762,7 +762,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService { * @return Map,其中 key 为用户 ID,value 为对应的用户昵称 */ @Override - public Map selectUserNamesByIds(List userIds) { + public Map selectUserNicksByIds(List userIds) { if (CollUtil.isEmpty(userIds)) { return Collections.emptyMap(); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java index 9e9c091ad..8edccd03e 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java @@ -244,7 +244,7 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand List longIds = StreamUtils.toList(ids, Convert::toLong); Map rawMap = switch (type) { - case USER -> userService.selectUserNamesByIds(longIds); + case USER -> userService.selectUserNicksByIds(longIds); case ROLE -> roleService.selectRoleNamesByIds(longIds); case DEPT -> deptService.selectDeptNamesByIds(longIds); case POST -> postService.selectPostNamesByIds(longIds); From 2d7195c61df64fb172255e0834606f296cccab58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Tue, 10 Mar 2026 17:20:37 +0800 Subject: [PATCH 14/14] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=A2=9E=E5=8A=A0=E7=A9=BA=E5=88=A4=E6=96=AD=E4=B8=8E?= =?UTF-8?q?=E5=85=B6=E4=BB=96=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/dto/StartProcessDTO.java | 3 +- .../MybatisEncryptInterceptor.java | 19 ++++----- .../service/GenTableServiceImpl.java | 3 ++ .../service/impl/SysDictTypeServiceImpl.java | 15 +++++++ .../workflow/domain/bo/BackProcessBo.java | 3 +- .../workflow/domain/bo/FlowNextNodeBo.java | 3 +- .../workflow/domain/bo/StartProcessBo.java | 3 +- .../listener/WorkflowGlobalListener.java | 4 +- .../service/impl/FlwCommonServiceImpl.java | 4 ++ .../service/impl/FlwInstanceServiceImpl.java | 9 +++++ .../service/impl/FlwSpelServiceImpl.java | 13 +++++- .../service/impl/FlwTaskServiceImpl.java | 40 ++++++++++++++++++- 12 files changed, 100 insertions(+), 19 deletions(-) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java index fa3565789..115b42f68 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java @@ -48,7 +48,8 @@ public class StartProcessDTO implements Serializable { public Map getVariables() { if (variables == null) { - return new HashMap<>(16); + variables = new HashMap<>(16); + return variables; } variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); return variables; diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java index bcc2f4c9f..617fb7979 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java @@ -6,10 +6,7 @@ import cn.hutool.core.util.ObjectUtil; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.executor.parameter.ParameterHandler; -import org.apache.ibatis.plugin.Interceptor; -import org.apache.ibatis.plugin.Intercepts; -import org.apache.ibatis.plugin.Invocation; -import org.apache.ibatis.plugin.Signature; +import org.apache.ibatis.plugin.*; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.encrypt.annotation.EncryptField; import org.dromara.common.encrypt.core.EncryptContext; @@ -42,19 +39,19 @@ public class MybatisEncryptInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { - return invocation; - } - - @Override - public Object plugin(Object target) { + Object target = invocation.getTarget(); if (target instanceof ParameterHandler parameterHandler) { - // 进行加密操作 Object parameterObject = parameterHandler.getParameterObject(); if (ObjectUtil.isNotNull(parameterObject) && !(parameterObject instanceof String)) { this.encryptHandler(parameterObject); } } - return target; + return invocation.proceed(); + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); } /** diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java index 3e7bdf7bb..455f8d9e6 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java @@ -523,6 +523,9 @@ public class GenTableServiceImpl implements IGenTableService { * @param table 业务表信息 */ public void setPkColumn(GenTable table) { + if (CollUtil.isEmpty(table.getColumns())) { + throw new ServiceException("表【" + table.getTableName() + "】字段为空,请检查表结构"); + } for (GenTableColumn column : table.getColumns()) { if (column.isPk()) { table.setPkColumn(column); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java index 6d4d9fea9..a7bc06949 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java @@ -229,6 +229,9 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService @Override public String getDictLabel(String dictType, String dictValue, String separator) { List datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + if (CollUtil.isEmpty(datas)) { + return StringUtils.EMPTY; + } Map map = StreamUtils.toMap(datas, SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel); if (StringUtils.containsAny(dictValue, separator)) { return Arrays.stream(dictValue.split(separator)) @@ -250,6 +253,9 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService @Override public String getDictValue(String dictType, String dictLabel, String separator) { List datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + if (CollUtil.isEmpty(datas)) { + return StringUtils.EMPTY; + } Map map = StreamUtils.toMap(datas, SysDictDataVo::getDictLabel, SysDictDataVo::getDictValue); if (StringUtils.containsAny(dictLabel, separator)) { return Arrays.stream(dictLabel.split(separator)) @@ -269,6 +275,9 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService @Override public Map getAllDictByDictType(String dictType) { List list = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + if (CollUtil.isEmpty(list)) { + return new HashMap<>(); + } // 保证顺序 LinkedHashMap map = new LinkedHashMap<>(); for (SysDictDataVo vo : list) { @@ -286,6 +295,9 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService @Override public DictTypeDTO getDictType(String dictType) { SysDictTypeVo vo = SpringUtils.getAopProxy(this).selectDictTypeByType(dictType); + if (ObjectUtil.isNull(vo)) { + return null; + } return BeanUtil.toBean(vo, DictTypeDTO.class); } @@ -298,6 +310,9 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService @Override public List getDictData(String dictType) { List list = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + if (CollUtil.isEmpty(list)) { + return new ArrayList<>(); + } return BeanUtil.copyToList(list, DictDataDTO.class); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java index a67a1f78e..a9674b0b3 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java @@ -61,7 +61,8 @@ public class BackProcessBo implements Serializable { public Map getVariables() { if (variables == null) { - return new HashMap<>(16); + variables = new HashMap<>(16); + return variables; } variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); return variables; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java index 12f0653ef..de75ba621 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java @@ -30,7 +30,8 @@ public class FlowNextNodeBo implements Serializable { public Map getVariables() { if (variables == null) { - return new HashMap<>(16); + variables = new HashMap<>(16); + return variables; } variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); return variables; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java index b31f4fa14..98f33a007 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java @@ -53,7 +53,8 @@ public class StartProcessBo implements Serializable { public Map getVariables() { if (variables == null) { - return new HashMap<>(16); + variables = new HashMap<>(16); + return variables; } variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); return variables; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java index c21523f18..d8ba911f2 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java @@ -80,11 +80,13 @@ public class WorkflowGlobalListener implements GlobalListener { NodeExtVo nodeExt = nodeExtService.parseNodeExt(ext, variable); Set copyList = nodeExt.getCopySettings(); if (CollUtil.isNotEmpty(copyList)) { + List userIds = StreamUtils.toList(copyList, Convert::toLong); + Map nickNameMap = userService.selectUserNicksByIds(userIds); List list = StreamUtils.toList(copyList, x -> { FlowCopyBo bo = new FlowCopyBo(); Long id = Convert.toLong(x); bo.setUserId(id); - bo.setNickName(userService.selectNicknameById(id)); + bo.setNickName(nickNameMap.getOrDefault(id, StringUtils.EMPTY)); return bo; }); variable.put(FlowConstant.FLOW_COPY_LIST, list); diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java index 6f9ea3028..77389bcaa 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StringUtils; @@ -126,6 +127,9 @@ public class FlwCommonServiceImpl implements IFlwCommonService { @Override public String applyNodeCode(Long definitionId) { List firstBetweenNode = FlowEngine.nodeService().getFirstBetweenNode(definitionId, new HashMap<>()); + if (CollUtil.isEmpty(firstBetweenNode)) { + throw new ServiceException("流程定义缺少申请人节点,请检查流程定义配置"); + } return firstBetweenNode.get(0).getNodeCode(); } } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java index 4de669da7..897d8a6e2 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java @@ -111,8 +111,14 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { @Override public FlowInstanceVo queryByBusinessId(Long businessId) { FlowInstance instance = this.selectInstByBusinessId(Convert.toStr(businessId)); + if (ObjectUtil.isNull(instance)) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); + } FlowInstanceVo instanceVo = BeanUtil.toBean(instance, FlowInstanceVo.class); Definition definition = defService.getById(instanceVo.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_DEF); + } instanceVo.setFlowName(definition.getFlowName()); instanceVo.setFlowCode(definition.getFlowCode()); instanceVo.setVersion(definition.getVersion()); @@ -383,6 +389,9 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { @Override public Map instanceVariable(Long instanceId) { FlowInstance flowInstance = flowInstanceMapper.selectById(instanceId); + if (ObjectUtil.isNull(flowInstance)) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); + } Map variableMap = Optional.ofNullable(flowInstance.getVariableMap()).orElse(Collections.emptyMap()); List> variableList = variableMap.entrySet().stream() .map(entry -> Map.of("key", entry.getKey(), "value", entry.getValue())) diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwSpelServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwSpelServiceImpl.java index 3790cdfd4..090ac81db 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwSpelServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwSpelServiceImpl.java @@ -1,6 +1,7 @@ package org.dromara.workflow.service.impl; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -9,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.domain.dto.TaskAssigneeDTO; import org.dromara.common.core.domain.model.TaskAssigneeBody; +import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StringUtils; @@ -125,7 +127,14 @@ public class FlwSpelServiceImpl implements IFlwSpelService { * 保存前的数据校验 */ private void validEntityBeforeSave(FlowSpel entity){ - //TODO 做一些数据校验,如唯一约束 + if (StringUtils.isNotBlank(entity.getViewSpel())) { + boolean exists = baseMapper.exists(new LambdaQueryWrapper() + .eq(FlowSpel::getViewSpel, entity.getViewSpel()) + .ne(ObjectUtil.isNotNull(entity.getId()), FlowSpel::getId, entity.getId())); + if (exists) { + throw new ServiceException("SpEL表达式已存在,请勿重复添加"); + } + } } /** @@ -137,7 +146,7 @@ public class FlwSpelServiceImpl implements IFlwSpelService { */ @Override public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { - if(isValid){ + if (isValid){ //TODO 做一些业务上的校验,判断是否需要校验 } return baseMapper.deleteByIds(ids) > 0; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java index 71170ba6e..af693e6e1 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java @@ -44,7 +44,6 @@ import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper; import org.dromara.warm.flow.orm.mapper.FlowNodeMapper; import org.dromara.warm.flow.orm.mapper.FlowTaskMapper; import org.dromara.workflow.common.ConditionalOnEnable; -import org.dromara.workflow.common.constant.FlowConstant; import org.dromara.workflow.common.enums.TaskAssigneeType; import org.dromara.workflow.common.enums.TaskOperationEnum; import org.dromara.workflow.common.enums.TaskStatusEnum; @@ -128,6 +127,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { // 已存在流程 BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus()); List taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId())); + if (CollUtil.isEmpty(taskList)) { + throw new ServiceException("流程实例缺少任务,请检查流程定义配置"); + } taskService.mergeVariable(flowInstance, variables); insService.updateById(flowInstance); StartProcessReturnDTO dto = new StartProcessReturnDTO(); @@ -157,6 +159,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { this.buildFlowInstanceBizExt(instance, bizExt); // 申请人执行流程 List taskList = taskService.list(new FlowTask().setInstanceId(instance.getId())); + if (CollUtil.isEmpty(taskList)) { + throw new ServiceException("流程启动失败,未生成任务"); + } if (taskList.size() > 1) { throw new ServiceException("请检查流程第一个环节是否为申请人!"); } @@ -220,6 +225,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { throw new ServiceException("流程任务不存在或任务已审批!"); } Instance ins = insService.getById(flowTask.getInstanceId()); + if (ObjectUtil.isNull(ins)) { + throw new ServiceException("流程实例不存在"); + } // 检查流程状态是否为草稿、已撤销或已退回状态,若是则执行流程提交监听 if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) { variables.put(SUBMIT, true); @@ -483,6 +491,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { throw new ServiceException("任务不存在!"); } Instance inst = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNull(inst)) { + throw new ServiceException("流程实例不存在"); + } BusinessStatusEnum.checkBackStatus(inst.getFlowStatus()); Long definitionId = task.getDefinitionId(); String applyNodeCode = flwCommonService.applyNodeCode(definitionId); @@ -514,6 +525,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { @Override public List getBackTaskNode(Long taskId, String nowNodeCode) { FlowTask task = flowTaskMapper.selectById(taskId); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("任务不存在!"); + } List nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), task.getDefinitionId()); if (!CollUtil.isNotEmpty(nodeCodes)) { return nodeCodes; @@ -598,7 +612,13 @@ public class FlwTaskServiceImpl implements IFlwTaskService { } FlowTaskVo flowTaskVo = BeanUtil.toBean(task, FlowTaskVo.class); Instance instance = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNull(instance)) { + throw new ServiceException("流程实例不存在"); + } Definition definition = defService.getById(task.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + throw new ServiceException("流程定义不存在"); + } flowTaskVo.setFlowStatus(instance.getFlowStatus()); flowTaskVo.setVersion(definition.getVersion()); flowTaskVo.setFlowCode(definition.getFlowCode()); @@ -641,11 +661,23 @@ public class FlwTaskServiceImpl implements IFlwTaskService { Long taskId = bo.getTaskId(); Map variables = bo.getVariables(); Task task = taskService.getById(taskId); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("任务不存在!"); + } Instance instance = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNull(instance)) { + throw new ServiceException("流程实例不存在"); + } Definition definition = defService.getById(task.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + throw new ServiceException("流程定义不存在"); + } Map mergeVariable = MapUtil.mergeAll(instance.getVariableMap(), variables); // 获取下一节点列表 List nextNodeList = nodeService.getNextNodeList(task.getDefinitionId(), task.getNodeCode(), null, SkipType.PASS.getKey(), mergeVariable); + if (CollUtil.isEmpty(nextNodeList)) { + return new ArrayList<>(); + } List nextFlowNodes = BeanUtil.copyToList(nextNodeList, FlowNode.class); // 只获取中间节点 nextFlowNodes = StreamUtils.filter(nextFlowNodes, node -> NodeType.BETWEEN.getKey().equals(node.getNodeType())); @@ -749,7 +781,13 @@ public class FlwTaskServiceImpl implements IFlwTaskService { Long taskId = bo.getTaskId(); Task task = taskService.getById(taskId); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("任务不存在!"); + } FlowNode flowNode = getByNodeCode(task.getNodeCode(), task.getDefinitionId()); + if (ObjectUtil.isNull(flowNode)) { + throw new ServiceException("流程节点不存在"); + } if (op == TaskOperationEnum.ADD_SIGNATURE || op == TaskOperationEnum.REDUCTION_SIGNATURE) { if (CooperateType.isOrSign(flowNode.getNodeRatio())) { throw new ServiceException(task.getNodeName() + "不是会签或票签节点!");