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

Merge branch 'refs/heads/5.X' into gogs-5.X

Xu, Hixon H 4 месяцев назад
Родитель
Сommit
cf48db2ee4
79 измененных файлов с 605 добавлено и 387 удалено
  1. 0 49
      .gitee/ISSUE_TEMPLATE.zh-CN.md
  2. 3 2
      .gitee/ISSUE_TEMPLATE/bug.yml
  3. 1 1
      .run/ruoyi-monitor-admin.run.xml
  4. 1 1
      .run/ruoyi-server.run.xml
  5. 1 1
      .run/ruoyi-snailjob-server.run.xml
  6. 2 2
      README.md
  7. 1 1
      pom.xml
  8. 4 2
      ruoyi-admin/Dockerfile
  9. 21 5
      ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java
  10. 1 2
      ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
  11. 2 1
      ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java
  12. 3 3
      ruoyi-admin/src/main/resources/application-dev.yml
  13. 4 4
      ruoyi-admin/src/main/resources/application-prod.yml
  14. 1 1
      ruoyi-common/ruoyi-common-bom/pom.xml
  15. 29 0
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java
  16. 2 1
      ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java
  17. 9 4
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java
  18. 6 1
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java
  19. 0 1
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java
  20. 148 14
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java
  21. 4 2
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java
  22. 9 1
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java
  23. 10 1
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataBaseType.java
  24. 27 10
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
  25. 22 8
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
  26. 2 3
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java
  27. 49 6
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
  28. 2 3
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java
  29. 21 1
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java
  30. 64 6
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java
  31. 1 1
      ruoyi-common/ruoyi-common-mybatis/src/main/resources/spy.properties
  32. 2 0
      ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
  33. 4 3
      ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/QueueUtils.java
  34. 16 8
      ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java
  35. 1 5
      ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java
  36. 20 15
      ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/interceptor/PlusWebSocketInterceptor.java
  37. 4 2
      ruoyi-extend/ruoyi-monitor-admin/Dockerfile
  38. 5 3
      ruoyi-extend/ruoyi-snailjob-server/Dockerfile
  39. 1 1
      ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml
  40. 1 1
      ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml
  41. 7 2
      ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/DelayedQueueController.java
  42. 1 1
      ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java
  43. 1 1
      ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java
  44. 1 1
      ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java
  45. 2 2
      ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java
  46. 1 1
      ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
  47. 0 4
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
  48. 0 7
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java
  49. 0 8
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java
  50. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java
  51. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java
  52. 15 3
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
  53. 0 14
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
  54. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java
  55. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java
  56. 8 4
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java
  57. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java
  58. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java
  59. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java
  60. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
  61. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
  62. 7 8
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
  63. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
  64. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java
  65. 2 2
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
  66. 9 24
      ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
  67. 1 3
      ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml
  68. 2 1
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java
  69. 14 15
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java
  70. 3 15
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
  71. 1 1
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java
  72. 1 1
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java
  73. 1 1
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java
  74. 1 1
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java
  75. 1 1
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java
  76. 3 2
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java
  77. 5 5
      script/docker/docker-compose.yml
  78. 1 1
      script/docker/nginx/conf/nginx.conf
  79. 2 71
      script/sql/postgres/flowable.sql

+ 0 - 49
.gitee/ISSUE_TEMPLATE.zh-CN.md

@@ -1,49 +0,0 @@
-### 使用版本(未按照模板填写直接删除)
-
-- jdk版本(带上尾号): 例如 1.8.0_202
-- 框架版本(项目启动时输出的版本号): 例如 4.4.0
-- 其他依赖版本(你觉得有必要的):
-
-### 问题前提
-
-> 功能不好用 不会用 是否已经看过项目文档
-> 项目运行报错 是否已经拿着报错信息去百度 常见报错百度百度足以
-> 是否搜索过其他issue 一些已经解决的问题 会在issue内留下解决方法
-> 无法线上解决或者与框架无关的问题的欢迎加VIP群跟作者一对一谈
-
-### 异常模块
-
-> 此报错都涉及到那些系统模块
-
-例如 ruoyi-system ruoyi-auth 等等
-
-### 问题描述
-
-> 越详细越容易直击问题所在
-
-已知: XXX功能不好用 或 XXX数据不正常 等等
-
-### 希望结果
-
-> 想知道你觉得怎么样是正常或者合理的
-
-希望功能可以有XXX结果 或者 XXX现象
-
-### 重现步骤
-
-> 作者并不知道这个问题是如何出现的
-
-- 1
-- 2
-- 3
-
-### 相关代码与报错信息(请勿发混乱格式)
-
-> 代码可按照如下形式提供或者截图均可 越详细越好
-> 大多数问题都是 代码编写错误问题 逻辑问题 或者用法错误等问题
-
-```java
-public class XXX {
-
-}
-```

+ 3 - 2
.gitee/ISSUE_TEMPLATE/bug.yml

@@ -9,8 +9,9 @@ body:
       label: 版本
       description: 你当前正在使用我们软件的哪个版本(pom文件内的版本号)?
       value: |
-        jdk版本(带上尾号): 例如 17.0.8
-        框架版本(项目启动时输出的版本号): 例如 5.1.1
+        注意: 未填写版本号不予处理直接关闭或删除
+        jdk版本(带上尾号):
+        框架版本(项目启动时输出的版本号):
         其他依赖版本(你觉得有必要的):
     validations:
       required: true

+ 1 - 1
.run/ruoyi-monitor-admin.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.2.0" />
+        <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.2.1" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-server.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-server:5.2.0" />
+        <option name="imageTag" value="ruoyi/ruoyi-server:5.2.1" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-snailjob-server.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.2.0" />
+        <option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.2.1" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" />
       </settings>

+ 2 - 2
README.md

@@ -9,7 +9,7 @@
 [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
 [![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
 <br>
-[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.0-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
+[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.1-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
 [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg)]()
 [![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]()
 [![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]()
@@ -56,7 +56,7 @@ CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow <br>
 | 数据加解密       | 采用 注解 + mybatis 拦截器 对存取数据期间自动加解密<br/>支持多种策略 如BASE64、AES、RSA、SM2、SM4等                                              | 无                                                                                  |
 | 接口传输加密      | 采用 动态 AES + RSA 加密请求 body 每一次请求秘钥都不同大幅度降低可破解性                                                                     | 无                                                                                  |
 | 数据翻译        | 采用 注解 + jackson 序列化期间动态修改数据 数据进行翻译<br/>支持多种模式: `映射翻译` `直接翻译` `其他扩展条件翻译` 接口化两步即可完成自定义扩展 内置多种翻译实现                   | 无                                                                                  |
-| 多数据源框架      | 采用 dynamic-datasource 支持面大部分数据库<br/>通过yml配置即可动态管理异构不同种类的数据库 也可通过前端页面添加数据源<br/>支持spel表达式从请求头参数等条件切换数据源            | 基于 druid 手动编写代码配置数据源 配置繁琐 支持性差                                                     |
+| 多数据源框架      | 采用 dynamic-datasource 支持面大部分数据库<br/>通过yml配置即可动态管理异构不同种类的数据库 也可通过前端页面添加数据源<br/>支持spel表达式从请求头参数等条件切换数据源            | 基于 druid 手动编写代码配置数据源 配置繁琐 支持性差                                                     |
 | 多数据源事务      | 采用 dynamic-datasource 支持多数据源不同种类的数据库事务回滚                                                                          | 不支持                                                                                |
 | 数据库连接池      | 采用 HikariCP Spring官方内置连接池 配置简单 以性能与稳定性闻名天下                                                                        | 采用 druid bug众多 社区维护差 活跃度低 配置众多繁琐性能一般                                               |
 | 数据库主键       | 采用 雪花ID 基于时间戳的 有序增长 唯一ID 再也不用为分库分表 数据合并主键冲突重复而发愁                                                                  | 采用 数据库自增ID 支持数据量有限 不支持多数据源主键唯一                                                     |

+ 1 - 1
pom.xml

@@ -13,7 +13,7 @@
     <description>RuoYi-Vue-Plus多租户管理系统</description>
 
     <properties>
-        <revision>5.2.0</revision>
+        <revision>5.2.1</revision>
         <spring-boot.version>3.2.6</spring-boot.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

+ 4 - 2
ruoyi-admin/Dockerfile

@@ -1,7 +1,9 @@
+# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
+FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
+#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds
 #FROM findepi/graalvm:java17-native
-FROM openjdk:17.0.2-oraclelinux8
 
-MAINTAINER Lion Li
+LABEL maintainer="Lion Li"
 
 RUN mkdir -p /ruoyi/server/logs \
     /ruoyi/server/temp \

+ 21 - 5
ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java

@@ -1,6 +1,7 @@
 package org.dromara.web.controller;
 
 import cn.dev33.satoken.annotation.SaIgnore;
+import cn.dev33.satoken.exception.NotLoginException;
 import cn.hutool.core.codec.Base64;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
@@ -194,8 +195,26 @@ public class AuthController {
      */
     @GetMapping("/tenant/list")
     public R<LoginTenantVo> tenantList(HttpServletRequest request) throws Exception {
+        // 返回对象
+        LoginTenantVo result = new LoginTenantVo();
+        boolean enable = TenantHelper.isEnable();
+        result.setTenantEnabled(enable);
+        // 如果未开启租户这直接返回
+        if (!enable) {
+            return R.ok(result);
+        }
+
         List<SysTenantVo> tenantList = tenantService.queryList(new SysTenantBo());
         List<TenantListVo> voList = MapstructUtils.convert(tenantList, TenantListVo.class);
+        try {
+            // 如果只超管返回所有租户
+            if (LoginHelper.isSuperAdmin()) {
+                result.setVoList(voList);
+                return R.ok(result);
+            }
+        } catch (NotLoginException ignored) {
+        }
+
         // 获取域名
         String host;
         String referer = request.getHeader("referer");
@@ -208,11 +227,8 @@ public class AuthController {
         // 根据域名进行筛选
         List<TenantListVo> list = StreamUtils.filter(voList, vo ->
                 StringUtils.equals(vo.getDomain(), host));
-        // 返回对象
-        LoginTenantVo vo = new LoginTenantVo();
-        vo.setVoList(CollUtil.isNotEmpty(list) ? list : voList);
-        vo.setTenantEnabled(TenantHelper.isEnable());
-        return R.ok(vo);
+        result.setVoList(CollUtil.isNotEmpty(list) ? list : voList);
+        return R.ok(result);
     }
 
 }

+ 1 - 2
ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java

@@ -24,7 +24,6 @@ import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.tenant.helper.TenantHelper;
 import org.dromara.common.web.config.properties.CaptchaProperties;
-import org.dromara.system.domain.SysClient;
 import org.dromara.system.domain.SysUser;
 import org.dromara.system.domain.vo.SysClientVo;
 import org.dromara.system.domain.vo.SysUserVo;
@@ -95,7 +94,7 @@ public class PasswordAuthStrategy implements IAuthStrategy {
      * @param uuid     唯一标识
      */
     private void validateCaptcha(String tenantId, String username, String code, String uuid) {
-        String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, "");
+        String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, "");
         String captcha = RedisUtils.getCacheObject(verifyKey);
         RedisUtils.deleteObject(verifyKey);
         if (captcha == null) {

+ 2 - 1
ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java

@@ -16,6 +16,7 @@ import org.dromara.common.core.domain.model.SocialLoginBody;
 import org.dromara.common.core.enums.UserStatus;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.exception.user.UserException;
+import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.core.utils.ValidatorUtils;
 import org.dromara.common.json.utils.JsonUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
@@ -83,7 +84,7 @@ public class SocialAuthStrategy implements IAuthStrategy {
         }
         SysSocialVo social;
         if (TenantHelper.isEnable()) {
-            Optional<SysSocialVo> opt = list.stream().filter(x -> x.getTenantId().equals(loginBody.getTenantId())).findAny();
+            Optional<SysSocialVo> opt = StreamUtils.findAny(list, x -> x.getTenantId().equals(loginBody.getTenantId()));
             if (opt.isEmpty()) {
                 throw new ServiceException("对不起,你没有权限登录当前租户!");
             }

+ 3 - 3
ruoyi-admin/src/main/resources/application-dev.yml

@@ -17,7 +17,7 @@ snail-job:
   token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
   server:
     host: 127.0.0.1
-    port: 1788
+    port: 17888
   # 详见 script/sql/snail_job.sql `sj_namespace` 表
   namespace: ${spring.profiles.active}
   # 随主应用端口飘逸
@@ -96,8 +96,8 @@ spring.data:
     port: 6379
     # 数据库索引
     database: 0
-    # 密码(如没有密码请注释掉)
-    # password:
+    # redis 密码必须配置
+    password: ruoyi123
     # 连接超时时间
     timeout: 10s
     # 是否开启ssl

+ 4 - 4
ruoyi-admin/src/main/resources/application-prod.yml

@@ -13,14 +13,14 @@ spring.boot.admin.client:
 
 --- # snail-job 配置
 snail-job:
-  enabled: false
+  enabled: true
   # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
   group: "ruoyi_group"
   # SnailJob 接入验证令牌 详见 script/sql/snail_job.sql `sj_group_config` 表
   token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
   server:
     host: 127.0.0.1
-    port: 1788
+    port: 17888
   # 详见 script/sql/snail_job.sql `sj_namespace` 表
   namespace: ${spring.profiles.active}
   # 随主应用端口飘逸
@@ -99,8 +99,8 @@ spring.data:
     port: 6379
     # 数据库索引
     database: 0
-    # 密码(如没有密码请注释掉)
-    # password:
+    # redis 密码必须配置
+    password: ruoyi123
     # 连接超时时间
     timeout: 10s
     # 是否开启ssl

+ 1 - 1
ruoyi-common/ruoyi-common-bom/pom.xml

@@ -14,7 +14,7 @@
     </description>
 
     <properties>
-        <revision>5.2.0</revision>
+        <revision>5.2.1</revision>
     </properties>
 
     <dependencyManagement>

+ 29 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java

@@ -7,6 +7,7 @@ import lombok.NoArgsConstructor;
 
 import java.util.*;
 import java.util.function.BiFunction;
+import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
@@ -34,6 +35,34 @@ public class StreamUtils {
         return collection.stream().filter(function).collect(Collectors.toList());
     }
 
+    /**
+     * 找到流中满足条件的第一个元素
+     *
+     * @param collection 需要查询的集合
+     * @param function   过滤方法
+     * @return 找到符合条件的第一个元素,没有则返回null
+     */
+    public static <E> E findFirst(Collection<E> collection, Predicate<E> function) {
+        if (CollUtil.isEmpty(collection)) {
+            return null;
+        }
+        return collection.stream().filter(function).findFirst().orElse(null);
+    }
+
+    /**
+     * 找到流中任意一个满足条件的元素
+     *
+     * @param collection 需要查询的集合
+     * @param function   过滤方法
+     * @return 找到符合条件的任意一个元素,没有则返回null
+     */
+    public static <E> Optional<E> findAny(Collection<E> collection, Predicate<E> function) {
+        if (CollUtil.isEmpty(collection)) {
+            return Optional.empty();
+        }
+        return collection.stream().filter(function).findAny();
+    }
+
     /**
      * 将collection拼接
      *

+ 2 - 1
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java

@@ -11,6 +11,7 @@ import io.swagger.v3.oas.models.Paths;
 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.springdoc.core.customizers.OpenApiBuilderCustomizer;
 import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
 import org.springdoc.core.properties.SpringDocConfigProperties;
@@ -230,7 +231,7 @@ public class OpenApiHandler extends OpenAPIService {
             .flatMap(x -> Stream.of(x.value())).collect(Collectors.toSet());
         methodTags.addAll(AnnotatedElementUtils.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.tags.Tag.class));
         if (!CollectionUtils.isEmpty(methodTags)) {
-            tagsStr.addAll(methodTags.stream().map(tag -> propertyResolverUtils.resolve(tag.name(), locale)).collect(Collectors.toSet()));
+            tagsStr.addAll(StreamUtils.toSet(methodTags, tag -> propertyResolverUtils.resolve(tag.name(), locale)));
             List<io.swagger.v3.oas.annotations.tags.Tag> allTags = new ArrayList<>(methodTags);
             addTags(allTags, tags, locale);
         }

+ 9 - 4
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java

@@ -3,9 +3,10 @@ package org.dromara.common.mybatis.annotation;
 import java.lang.annotation.*;
 
 /**
- * 数据权限
- *
+ * 数据权限注解,用于标记数据权限的占位符关键字和替换值
+ * <p>
  * 一个注解只能对应一个模板
+ * </p>
  *
  * @author Lion Li
  * @version 3.5.0
@@ -16,12 +17,16 @@ import java.lang.annotation.*;
 public @interface DataColumn {
 
     /**
-     * 占位符关键字
+     * 数据权限模板的占位符关键字,默认为 "deptName"
+     *
+     * @return 占位符关键字数组
      */
     String[] key() default "deptName";
 
     /**
-     * 占位符替换值
+     * 数据权限模板的占位符替换值,默认为 "dept_id"
+     *
+     * @return 占位符替换值数组
      */
     String[] value() default "dept_id";
 

+ 6 - 1
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java

@@ -3,7 +3,7 @@ package org.dromara.common.mybatis.annotation;
 import java.lang.annotation.*;
 
 /**
- * 数据权限组
+ * 数据权限组注解,用于标记数据权限配置数组
  *
  * @author Lion Li
  * @version 3.5.0
@@ -13,6 +13,11 @@ import java.lang.annotation.*;
 @Documented
 public @interface DataPermission {
 
+    /**
+     * 数据权限配置数组,用于指定数据权限的占位符关键字和替换值
+     *
+     * @return 数据权限配置数组
+     */
     DataColumn[] value();
 
 }

+ 0 - 1
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java

@@ -17,7 +17,6 @@ import java.util.Map;
  *
  * @author Lion Li
  */
-
 @Data
 public class BaseEntity implements Serializable {
 

+ 148 - 14
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java

@@ -12,6 +12,7 @@ import com.baomidou.mybatisplus.extension.toolkit.Db;
 import org.apache.ibatis.logging.Log;
 import org.apache.ibatis.logging.LogFactory;
 import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StreamUtils;
 
 import java.io.Serializable;
 import java.util.Collection;
@@ -34,20 +35,38 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
 
     Log log = LogFactory.getLog(BaseMapperPlus.class);
 
+    /**
+     * 获取当前实例对象关联的泛型类型 V 的 Class 对象
+     *
+     * @return 返回当前实例对象关联的泛型类型 V 的 Class 对象
+     */
     default Class<V> currentVoClass() {
         return (Class<V>) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[1];
     }
 
+    /**
+     * 获取当前实例对象关联的泛型类型 T 的 Class 对象
+     *
+     * @return 返回当前实例对象关联的泛型类型 T 的 Class 对象
+     */
     default Class<T> currentModelClass() {
         return (Class<T>) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[0];
     }
 
+    /**
+     * 使用默认的查询条件查询并返回结果列表
+     *
+     * @return 返回查询结果的列表
+     */
     default List<T> selectList() {
         return this.selectList(new QueryWrapper<>());
     }
 
     /**
-     * 批量插入
+     * 批量插入实体对象集合
+     *
+     * @param entityList 实体对象集合
+     * @return 插入操作是否成功的布尔值
      */
     default boolean insertBatch(Collection<T> entityList) {
         Db.saveBatch(entityList);
@@ -56,7 +75,10 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
     }
 
     /**
-     * 批量更新
+     * 批量根据ID更新实体对象集合
+     *
+     * @param entityList 实体对象集合
+     * @return 更新操作是否成功的布尔值
      */
     default boolean updateBatchById(Collection<T> entityList) {
         Db.updateBatchById(entityList);
@@ -65,7 +87,10 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
     }
 
     /**
-     * 批量插入或更新
+     * 批量插入或更新实体对象集合
+     *
+     * @param entityList 实体对象集合
+     * @return 插入或更新操作是否成功的布尔值
      */
     default boolean insertOrUpdateBatch(Collection<T> entityList) {
         Db.saveOrUpdateBatch(entityList);
@@ -74,7 +99,11 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
     }
 
     /**
-     * 批量插入(包含限制条数)
+     * 批量插入实体对象集合并指定批处理大小
+     *
+     * @param entityList 实体对象集合
+     * @param batchSize  批处理大小
+     * @return 插入操作是否成功的布尔值
      */
     default boolean insertBatch(Collection<T> entityList, int batchSize) {
         Db.saveBatch(entityList, batchSize);
@@ -83,7 +112,11 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
     }
 
     /**
-     * 批量更新(包含限制条数)
+     * 批量根据ID更新实体对象集合并指定批处理大小
+     *
+     * @param entityList 实体对象集合
+     * @param batchSize  批处理大小
+     * @return 更新操作是否成功的布尔值
      */
     default boolean updateBatchById(Collection<T> entityList, int batchSize) {
         Db.updateBatchById(entityList, batchSize);
@@ -92,7 +125,11 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
     }
 
     /**
-     * 批量插入或更新(包含限制条数)
+     * 批量插入或更新实体对象集合并指定批处理大小
+     *
+     * @param entityList 实体对象集合
+     * @param batchSize  批处理大小
+     * @return 插入或更新操作是否成功的布尔值
      */
     default boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) {
         Db.saveOrUpdateBatch(entityList, batchSize);
@@ -100,12 +137,23 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
         return true;
     }
 
+    /**
+     * 根据ID查询单个VO对象
+     *
+     * @param id 主键ID
+     * @return 查询到的单个VO对象
+     */
     default V selectVoById(Serializable id) {
         return selectVoById(id, this.currentVoClass());
     }
 
     /**
-     * 根据 ID 查询
+     * 根据ID查询单个VO对象并将其转换为指定的VO类
+     *
+     * @param id      主键ID
+     * @param voClass 要转换的VO类的Class对象
+     * @param <C>     VO类的类型
+     * @return 查询到的单个VO对象,经过转换为指定的VO类后返回
      */
     default <C> C selectVoById(Serializable id, Class<C> voClass) {
         T obj = this.selectById(id);
@@ -115,12 +163,23 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
         return MapstructUtils.convert(obj, voClass);
     }
 
+    /**
+     * 根据ID集合批量查询VO对象列表
+     *
+     * @param idList 主键ID集合
+     * @return 查询到的VO对象列表
+     */
     default List<V> selectVoBatchIds(Collection<? extends Serializable> idList) {
         return selectVoBatchIds(idList, this.currentVoClass());
     }
 
     /**
-     * 查询(根据ID 批量查询)
+     * 根据ID集合批量查询实体对象列表,并将其转换为指定的VO对象列表
+     *
+     * @param idList  主键ID集合
+     * @param voClass 要转换的VO类的Class对象
+     * @param <C>     VO类的类型
+     * @return 查询到的VO对象列表,经过转换为指定的VO类后返回
      */
     default <C> List<C> selectVoBatchIds(Collection<? extends Serializable> idList, Class<C> voClass) {
         List<T> list = this.selectBatchIds(idList);
@@ -130,12 +189,23 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
         return MapstructUtils.convert(list, voClass);
     }
 
+    /**
+     * 根据查询条件Map查询VO对象列表
+     *
+     * @param map 查询条件Map
+     * @return 查询到的VO对象列表
+     */
     default List<V> selectVoByMap(Map<String, Object> map) {
         return selectVoByMap(map, this.currentVoClass());
     }
 
     /**
-     * 查询(根据 columnMap 条件)
+     * 根据查询条件Map查询实体对象列表,并将其转换为指定的VO对象列表
+     *
+     * @param map     查询条件Map
+     * @param voClass 要转换的VO类的Class对象
+     * @param <C>     VO类的类型
+     * @return 查询到的VO对象列表,经过转换为指定的VO类后返回
      */
     default <C> List<C> selectVoByMap(Map<String, Object> map, Class<C> voClass) {
         List<T> list = this.selectByMap(map);
@@ -145,23 +215,47 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
         return MapstructUtils.convert(list, voClass);
     }
 
+    /**
+     * 根据条件查询单个VO对象
+     *
+     * @param wrapper 查询条件Wrapper
+     * @return 查询到的单个VO对象
+     */
     default V selectVoOne(Wrapper<T> wrapper) {
         return selectVoOne(wrapper, this.currentVoClass());
     }
 
+    /**
+     * 根据条件查询单个VO对象,并根据需要决定是否抛出异常
+     *
+     * @param wrapper 查询条件Wrapper
+     * @param throwEx 是否抛出异常的标志
+     * @return 查询到的单个VO对象
+     */
     default V selectVoOne(Wrapper<T> wrapper, boolean throwEx) {
         return selectVoOne(wrapper, this.currentVoClass(), throwEx);
     }
 
     /**
-     * 根据 entity 条件,查询一条记录
+     * 根据条件查询单个VO对象,并指定返回的VO对象的类型
+     *
+     * @param wrapper 查询条件Wrapper
+     * @param voClass 返回的VO对象的Class对象
+     * @param <C>     返回的VO对象的类型
+     * @return 查询到的单个VO对象,经过类型转换为指定的VO类后返回
      */
     default <C> C selectVoOne(Wrapper<T> wrapper, Class<C> voClass) {
         return selectVoOne(wrapper, voClass, true);
     }
 
     /**
-     * 根据 entity 条件,查询一条记录
+     * 根据条件查询单个实体对象,并将其转换为指定的VO对象
+     *
+     * @param wrapper 查询条件Wrapper
+     * @param voClass 要转换的VO类的Class对象
+     * @param throwEx 是否抛出异常的标志
+     * @param <C>     VO类的类型
+     * @return 查询到的单个VO对象,经过转换为指定的VO类后返回
      */
     default <C> C selectVoOne(Wrapper<T> wrapper, Class<C> voClass, boolean throwEx) {
         T obj = this.selectOne(wrapper, throwEx);
@@ -171,16 +265,32 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
         return MapstructUtils.convert(obj, voClass);
     }
 
+    /**
+     * 查询所有VO对象列表
+     *
+     * @return 查询到的VO对象列表
+     */
     default List<V> selectVoList() {
         return selectVoList(new QueryWrapper<>(), this.currentVoClass());
     }
 
+    /**
+     * 根据条件查询VO对象列表
+     *
+     * @param wrapper 查询条件Wrapper
+     * @return 查询到的VO对象列表
+     */
     default List<V> selectVoList(Wrapper<T> wrapper) {
         return selectVoList(wrapper, this.currentVoClass());
     }
 
     /**
-     * 根据 entity 条件,查询全部记录
+     * 根据条件查询实体对象列表,并将其转换为指定的VO对象列表
+     *
+     * @param wrapper 查询条件Wrapper
+     * @param voClass 要转换的VO类的Class对象
+     * @param <C>     VO类的类型
+     * @return 查询到的VO对象列表,经过转换为指定的VO类后返回
      */
     default <C> List<C> selectVoList(Wrapper<T> wrapper, Class<C> voClass) {
         List<T> list = this.selectList(wrapper);
@@ -190,15 +300,31 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
         return MapstructUtils.convert(list, voClass);
     }
 
+    /**
+     * 根据条件分页查询VO对象列表
+     *
+     * @param page    分页信息
+     * @param wrapper 查询条件Wrapper
+     * @return 查询到的VO对象分页列表
+     */
     default <P extends IPage<V>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper) {
         return selectVoPage(page, wrapper, this.currentVoClass());
     }
 
     /**
-     * 分页查询VO
+     * 根据条件分页查询实体对象列表,并将其转换为指定的VO对象分页列表
+     *
+     * @param page    分页信息
+     * @param wrapper 查询条件Wrapper
+     * @param voClass 要转换的VO类的Class对象
+     * @param <C>     VO类的类型
+     * @param <P>     VO对象分页列表的类型
+     * @return 查询到的VO对象分页列表,经过转换为指定的VO类后返回
      */
     default <C, P extends IPage<C>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper, Class<C> voClass) {
+        // 根据条件分页查询实体对象列表
         List<T> list = this.selectList(page, wrapper);
+        // 创建一个新的VO对象分页列表,并设置分页信息
         IPage<C> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
         if (CollUtil.isEmpty(list)) {
             return (P) voPage;
@@ -207,8 +333,16 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
         return (P) voPage;
     }
 
+    /**
+     * 根据条件查询符合条件的对象,并将其转换为指定类型的对象列表
+     *
+     * @param wrapper 查询条件Wrapper
+     * @param mapper  转换函数,用于将查询到的对象转换为指定类型的对象
+     * @param <C>     要转换的对象的类型
+     * @return 查询到的符合条件的对象列表,经过转换为指定类型的对象后返回
+     */
     default <C> List<C> selectObjs(Wrapper<T> wrapper, Function<? super Object, C> mapper) {
-        return this.selectObjs(wrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
+        return StreamUtils.toList(this.selectObjs(wrapper), mapper);
     }
 
 }

+ 4 - 2
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java

@@ -4,10 +4,10 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.metadata.OrderItem;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.Data;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.core.utils.sql.SqlUtil;
-import lombok.Data;
 
 import java.io.Serial;
 import java.io.Serializable;
@@ -19,7 +19,6 @@ import java.util.List;
  *
  * @author Lion Li
  */
-
 @Data
 public class PageQuery implements Serializable {
 
@@ -56,6 +55,9 @@ public class PageQuery implements Serializable {
      */
     public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
 
+    /**
+     * 构建分页对象
+     */
     public <T> Page<T> build() {
         Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM);
         Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE);

+ 9 - 1
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java

@@ -14,7 +14,6 @@ import java.util.List;
  *
  * @author Lion Li
  */
-
 @Data
 @NoArgsConstructor
 public class TableDataInfo<T> implements Serializable {
@@ -53,6 +52,9 @@ public class TableDataInfo<T> implements Serializable {
         this.total = total;
     }
 
+    /**
+     * 根据分页对象构建表格分页数据对象
+     */
     public static <T> TableDataInfo<T> build(IPage<T> page) {
         TableDataInfo<T> rspData = new TableDataInfo<>();
         rspData.setCode(HttpStatus.HTTP_OK);
@@ -62,6 +64,9 @@ public class TableDataInfo<T> implements Serializable {
         return rspData;
     }
 
+    /**
+     * 根据数据列表构建表格分页数据对象
+     */
     public static <T> TableDataInfo<T> build(List<T> list) {
         TableDataInfo<T> rspData = new TableDataInfo<>();
         rspData.setCode(HttpStatus.HTTP_OK);
@@ -71,6 +76,9 @@ public class TableDataInfo<T> implements Serializable {
         return rspData;
     }
 
+    /**
+     * 构建表格分页数据对象
+     */
     public static <T> TableDataInfo<T> build() {
         TableDataInfo<T> rspData = new TableDataInfo<>();
         rspData.setCode(HttpStatus.HTTP_OK);

+ 10 - 1
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataBaseType.java

@@ -1,8 +1,8 @@
 package org.dromara.common.mybatis.enums;
 
-import org.dromara.common.core.utils.StringUtils;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
+import org.dromara.common.core.utils.StringUtils;
 
 /**
  * 数据库类型
@@ -33,8 +33,17 @@ public enum DataBaseType {
      */
     SQL_SERVER("Microsoft SQL Server");
 
+    /**
+     * 数据库类型
+     */
     private final String type;
 
+    /**
+     * 根据数据库产品名称查找对应的数据库类型
+     *
+     * @param databaseProductName 数据库产品名称
+     * @return 对应的数据库类型枚举值,如果未找到则返回 null
+     */
     public static DataBaseType find(String databaseProductName) {
         if (StringUtils.isBlank(databaseProductName)) {
             return null;

+ 27 - 10
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java

@@ -1,19 +1,22 @@
 package org.dromara.common.mybatis.enums;
 
-import org.dromara.common.core.utils.StringUtils;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.helper.DataPermissionHelper;
 
 /**
- * 数据权限类型
- * <p>
- * 语法支持 spel 模板表达式
+ * 数据权限类型枚举
  * <p>
- * 内置数据 user 当前用户 内容参考 LoginUser
- * 如需扩展数据 可使用 {@link DataPermissionHelper} 操作
- * 内置服务 sdss 系统数据权限服务 内容参考 SysDataScopeService
- * 如需扩展更多自定义服务 可以参考 sdss 自行编写
+ * 支持使用 SpEL 模板表达式定义 SQL 查询条件
+ * 内置数据:
+ * - {@code user}: 当前登录用户信息,参考 {@link LoginUser}
+ * 内置服务:
+ * - {@code sdss}: 系统数据权限服务,参考 {@link ISysDataScopeService}
+ * 如需扩展数据,可以通过 {@link DataPermissionHelper} 进行操作
+ * 如需扩展服务,可以通过 {@link ISysDataScopeService} 自行编写
+ * </p>
  *
  * @author Lion Li
  * @version 3.5.0
@@ -29,36 +32,50 @@ public enum DataScopeType {
 
     /**
      * 自定数据权限
+     * 使用 SpEL 表达式:`#{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} )`
+     * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
      */
     CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", " 1 = 0 "),
 
     /**
      * 部门数据权限
+     * 使用 SpEL 表达式:`#{#deptName} = #{#user.deptId}`
+     * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
      */
     DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "),
 
     /**
      * 部门及以下数据权限
+     * 使用 SpEL 表达式:`#{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )}`
+     * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
      */
     DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", " 1 = 0 "),
 
     /**
      * 仅本人数据权限
+     * 使用 SpEL 表达式:`#{#userName} = #{#user.userId}`
+     * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
      */
     SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 ");
 
     private final String code;
 
     /**
-     * 语法 采用 spel 模板表达式
+     * SpEL 模板表达式,用于构建 SQL 查询条件
      */
     private final String sqlTemplate;
 
     /**
-     * 不满足 sqlTemplate 则填充
+     * 如果不满足 {@code sqlTemplate} 的条件,则使用此默认 SQL 表达式
      */
     private final String elseSql;
 
+    /**
+     * 根据枚举代码查找对应的枚举值
+     *
+     * @param code 枚举代码
+     * @return 对应的枚举值,如果未找到则返回 null
+     */
     public static DataScopeType findCode(String code) {
         if (StringUtils.isBlank(code)) {
             return null;

+ 22 - 8
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java

@@ -3,12 +3,12 @@ package org.dromara.common.mybatis.handler;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.http.HttpStatus;
 import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.reflection.MetaObject;
 import org.dromara.common.core.domain.model.LoginUser;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.mybatis.core.domain.BaseEntity;
 import org.dromara.common.satoken.utils.LoginHelper;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.ibatis.reflection.MetaObject;
 
 import java.util.Date;
 
@@ -21,21 +21,28 @@ import java.util.Date;
 @Slf4j
 public class InjectionMetaObjectHandler implements MetaObjectHandler {
 
+    /**
+     * 插入填充方法,用于在插入数据时自动填充实体对象中的创建时间、更新时间、创建人、更新人等信息
+     *
+     * @param metaObject 元对象,用于获取原始对象并进行填充
+     */
     @Override
     public void insertFill(MetaObject metaObject) {
         try {
             if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
+                // 获取当前时间作为创建时间和更新时间,如果创建时间不为空,则使用创建时间,否则使用当前时间
                 Date current = ObjectUtil.isNotNull(baseEntity.getCreateTime())
                     ? baseEntity.getCreateTime() : new Date();
                 baseEntity.setCreateTime(current);
                 baseEntity.setUpdateTime(current);
+
+                // 如果创建人为空,则填充当前登录用户的信息
                 if (ObjectUtil.isNull(baseEntity.getCreateBy())) {
                     LoginUser loginUser = getLoginUser();
                     if (ObjectUtil.isNotNull(loginUser)) {
                         Long userId = loginUser.getUserId();
-                        // 当前已登录 且 创建人为空 则填充
+                        // 填充创建人、更新人和创建部门信息
                         baseEntity.setCreateBy(userId);
-                        // 当前已登录 且 更新人为空 则填充
                         baseEntity.setUpdateBy(userId);
                         baseEntity.setCreateDept(ObjectUtil.isNotNull(baseEntity.getCreateDept())
                             ? baseEntity.getCreateDept() : loginUser.getDeptId());
@@ -47,19 +54,24 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
         }
     }
 
+    /**
+     * 更新填充方法,用于在更新数据时自动填充实体对象中的更新时间和更新人信息
+     *
+     * @param metaObject 元对象,用于获取原始对象并进行填充
+     */
     @Override
     public void updateFill(MetaObject metaObject) {
         try {
             if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
+                // 获取当前时间作为更新时间,无论原始对象中的更新时间是否为空都填充
                 Date current = new Date();
-                // 更新时间填充(不管为不为空)
                 baseEntity.setUpdateTime(current);
-                // 当前已登录 更新人填充(不管为不为空)
+
+                // 获取当前登录用户的ID,并填充更新人信息
                 Long userId = LoginHelper.getUserId();
                 if (ObjectUtil.isNotNull(userId)) {
                     baseEntity.setUpdateBy(userId);
                 }
-
             }
         } catch (Exception e) {
             throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
@@ -67,7 +79,9 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
     }
 
     /**
-     * 获取登录用户名
+     * 获取当前登录用户信息
+     *
+     * @return 当前登录用户的信息,如果用户未登录则返回 null
      */
     private LoginUser getLoginUser() {
         LoginUser loginUser;

+ 2 - 3
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java

@@ -1,15 +1,14 @@
 package org.dromara.common.mybatis.handler;
 
-import org.dromara.common.core.domain.R;
+import jakarta.servlet.http.HttpServletRequest;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
 import org.dromara.common.core.utils.StringUtils;
 import org.mybatis.spring.MyBatisSystemException;
 import org.springframework.dao.DuplicateKeyException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
 
-import jakarta.servlet.http.HttpServletRequest;
-
 /**
  * Mybatis异常处理器
  *

+ 49 - 6
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java

@@ -68,13 +68,27 @@ public class PlusDataPermissionHandler {
      */
     private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory());
 
+    /**
+     * 构造方法,扫描指定包下的 Mapper 类并初始化缓存
+     *
+     * @param mapperPackage Mapper 类所在的包路径
+     */
     public PlusDataPermissionHandler(String mapperPackage) {
         scanMapperClasses(mapperPackage);
     }
 
-
+    /**
+     * 获取数据过滤条件的 SQL 片段
+     *
+     * @param where             原始的查询条件表达式
+     * @param mappedStatementId Mapper 方法的 ID
+     * @param isSelect          是否为查询语句
+     * @return 数据过滤条件的 SQL 片段
+     */
     public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
+        // 获取数据权限配置
         DataPermission dataPermission = getDataPermission(mappedStatementId);
+        // 获取当前登录用户信息
         LoginUser currentUser = DataPermissionHelper.getVariable("user");
         if (ObjectUtil.isNull(currentUser)) {
             currentUser = LoginHelper.getLoginUser();
@@ -84,6 +98,7 @@ public class PlusDataPermissionHandler {
         if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
             return where;
         }
+        // 构造数据过滤条件的 SQL 片段
         String dataFilterSql = buildDataFilter(dataPermission.value(), isSelect);
         if (StringUtils.isBlank(dataFilterSql)) {
             return where;
@@ -103,7 +118,12 @@ public class PlusDataPermissionHandler {
     }
 
     /**
-     * 构造数据过滤sql
+     * 构建数据过滤条件的 SQL 语句
+     *
+     * @param dataColumns 数据权限注解中的列信息
+     * @param isSelect    标志当前操作是否为查询操作,查询操作和更新或删除操作在处理过滤条件时会有不同的处理方式
+     * @return 构建的数据过滤条件的 SQL 语句
+     * @throws ServiceException 如果角色的数据范围异常或者 key 与 value 的长度不匹配,则抛出 ServiceException 异常
      */
     private String buildDataFilter(DataColumn[] dataColumns, boolean isSelect) {
         // 更新或删除需满足所有条件
@@ -159,20 +179,29 @@ public class PlusDataPermissionHandler {
     }
 
     /**
-     * 通过 mapperPackage 设置的扫描包 扫描缓存有注解的方法与类
+     * 扫描指定包下的 Mapper 类,并查找其中带有特定注解的方法或类
+     *
+     * @param mapperPackage Mapper 类所在的包路径
      */
     private void scanMapperClasses(String mapperPackage) {
+        // 创建资源解析器和元数据读取工厂
         PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
         CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
+        // 将 Mapper 包路径按分隔符拆分为数组
         String[] packagePatternArray = StringUtils.splitPreserveAllTokens(mapperPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
         String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
         try {
             for (String packagePattern : packagePatternArray) {
+                // 将包路径转换为资源路径
                 String path = ClassUtils.convertClassNameToResourcePath(packagePattern);
+                // 获取指定路径下的所有 .class 文件资源
                 Resource[] resources = resolver.getResources(classpath + path + "/*.class");
                 for (Resource resource : resources) {
+                    // 获取资源的类元数据
                     ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata();
+                    // 获取资源对应的类对象
                     Class<?> clazz = Resources.classForName(classMetadata.getClassName());
+                    // 查找类中的特定注解
                     findAnnotation(clazz);
                 }
             }
@@ -181,9 +210,13 @@ public class PlusDataPermissionHandler {
         }
     }
 
+    /**
+     * 在指定的类中查找特定的注解 DataPermission,并将带有这个注解的方法或类存储到 dataPermissionCacheMap 中
+     *
+     * @param clazz 要查找的类
+     */
     private void findAnnotation(Class<?> clazz) {
         DataPermission dataPermission;
-        // 获取方法注解
         for (Method method : clazz.getMethods()) {
             if (method.isDefault() || method.isVarArgs()) {
                 continue;
@@ -194,17 +227,24 @@ public class PlusDataPermissionHandler {
                 dataPermissionCacheMap.put(mappedStatementId, dataPermission);
             }
         }
-        // 获取类注解
         if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) {
             dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class);
             dataPermissionCacheMap.put(clazz.getName(), dataPermission);
         }
     }
 
+    /**
+     * 根据映射语句 ID 或类名获取对应的 DataPermission 注解对象
+     *
+     * @param mapperId 映射语句 ID
+     * @return DataPermission 注解对象,如果不存在则返回 null
+     */
     public DataPermission getDataPermission(String mapperId) {
+        // 检查缓存中是否包含映射语句 ID 对应的 DataPermission 注解对象
         if (dataPermissionCacheMap.containsKey(mapperId)) {
             return dataPermissionCacheMap.get(mapperId);
         }
+        // 如果缓存中不包含映射语句 ID 对应的 DataPermission 注解对象,则尝试使用类名作为键查找
         String clazzName = mapperId.substring(0, mapperId.lastIndexOf("."));
         if (dataPermissionCacheMap.containsKey(clazzName)) {
             return dataPermissionCacheMap.get(clazzName);
@@ -213,7 +253,10 @@ public class PlusDataPermissionHandler {
     }
 
     /**
-     * 是否无效
+     * 检查给定的映射语句 ID 是否有效,即是否能够找到对应的 DataPermission 注解对象
+     *
+     * @param mapperId 映射语句 ID
+     * @return 如果找到对应的 DataPermission 注解对象,则返回 false;否则返回 true
      */
     public boolean invalid(String mapperId) {
         return getDataPermission(mapperId) == null;

+ 2 - 3
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java

@@ -2,11 +2,11 @@ package org.dromara.common.mybatis.helper;
 
 import cn.hutool.core.convert.Convert;
 import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.mybatis.enums.DataBaseType;
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
 
 import javax.sql.DataSource;
 import java.sql.Connection;
@@ -14,7 +14,6 @@ import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 
 /**
  * 数据库助手

+ 21 - 1
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java

@@ -24,17 +24,35 @@ public class DataPermissionHelper {
 
     private static final String DATA_PERMISSION_KEY = "data:permission";
 
+    /**
+     * 从上下文中获取指定键的变量值,并将其转换为指定的类型
+     *
+     * @param key 变量的键
+     * @param <T> 变量值的类型
+     * @return 指定键的变量值,如果不存在则返回 null
+     */
     public static <T> T getVariable(String key) {
         Map<String, Object> context = getContext();
         return (T) context.get(key);
     }
 
-
+    /**
+     * 向上下文中设置指定键的变量值
+     *
+     * @param key   要设置的变量的键
+     * @param value 要设置的变量值
+     */
     public static void setVariable(String key, Object value) {
         Map<String, Object> context = getContext();
         context.put(key, value);
     }
 
+    /**
+     * 获取数据权限上下文
+     *
+     * @return 存储在SaStorage中的Map对象,用于存储数据权限相关的上下文信息
+     * @throws NullPointerException 如果数据权限上下文类型异常,则抛出NullPointerException
+     */
     public static Map<String, Object> getContext() {
         SaStorage saStorage = SaHolder.getStorage();
         Object attribute = saStorage.get(DATA_PERMISSION_KEY);
@@ -64,6 +82,7 @@ public class DataPermissionHelper {
 
     /**
      * 在忽略数据权限中执行
+     * <p>禁止在忽略数据权限中执行忽略数据权限</p>
      *
      * @param handle 处理执行方法
      */
@@ -78,6 +97,7 @@ public class DataPermissionHelper {
 
     /**
      * 在忽略数据权限中执行
+     * <p>禁止在忽略数据权限中执行忽略数据权限</p>
      *
      * @param handle 处理执行方法
      */

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

@@ -37,17 +37,33 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
 
     private final PlusDataPermissionHandler dataPermissionHandler;
 
+    /**
+     * 构造函数,初始化 PlusDataPermissionHandler 实例
+     *
+     * @param mapperPackage 扫描的映射器包
+     */
     public PlusDataPermissionInterceptor(String mapperPackage) {
         this.dataPermissionHandler = new PlusDataPermissionHandler(mapperPackage);
     }
 
+    /**
+     * 在执行查询之前,检查并处理数据权限相关逻辑
+     *
+     * @param executor      MyBatis 执行器对象
+     * @param ms            映射语句对象
+     * @param parameter     方法参数
+     * @param rowBounds     分页对象
+     * @param resultHandler 结果处理器
+     * @param boundSql      绑定的 SQL 对象
+     * @throws SQLException 如果发生 SQL 异常
+     */
     @Override
     public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
-        // 检查忽略注解
+        // 检查是否需要忽略数据权限处理
         if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
             return;
         }
-        // 检查是否无效 无数据权限注解
+        // 检查是否缺少有效的数据权限注解
         if (dataPermissionHandler.invalid(ms.getId())) {
             return;
         }
@@ -56,16 +72,26 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
         mpBs.sql(parserSingle(mpBs.sql(), ms.getId()));
     }
 
+    /**
+     * 在准备 SQL 语句之前,检查并处理更新和删除操作的数据权限相关逻辑
+     *
+     * @param sh                 MyBatis StatementHandler 对象
+     * @param connection         数据库连接对象
+     * @param transactionTimeout 事务超时时间
+     */
     @Override
     public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
         PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
         MappedStatement ms = mpSh.mappedStatement();
+        // 获取 SQL 命令类型(增、删、改、查)
         SqlCommandType sct = ms.getSqlCommandType();
+
+        // 只处理更新和删除操作的 SQL 语句
         if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
             if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
                 return;
             }
-            // 检查是否无效 无数据权限注解
+            // 检查是否缺少有效的数据权限注解
             if (dataPermissionHandler.invalid(ms.getId())) {
                 return;
             }
@@ -74,6 +100,14 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
         }
     }
 
+    /**
+     * 处理 SELECT 查询语句中的 WHERE 条件
+     *
+     * @param select SELECT 查询对象
+     * @param index  查询语句的索引
+     * @param sql    查询语句
+     * @param obj    WHERE 条件参数
+     */
     @Override
     protected void processSelect(Select select, int index, String sql, Object obj) {
         if (select instanceof PlainSelect) {
@@ -84,6 +118,14 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
         }
     }
 
+    /**
+     * 处理 UPDATE 语句中的 WHERE 条件
+     *
+     * @param update UPDATE 查询对象
+     * @param index  查询语句的索引
+     * @param sql    查询语句
+     * @param obj    WHERE 条件参数
+     */
     @Override
     protected void processUpdate(Update update, int index, String sql, Object obj) {
         Expression sqlSegment = dataPermissionHandler.getSqlSegment(update.getWhere(), (String) obj, false);
@@ -92,6 +134,14 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
         }
     }
 
+    /**
+     * 处理 DELETE 语句中的 WHERE 条件
+     *
+     * @param delete DELETE 查询对象
+     * @param index  查询语句的索引
+     * @param sql    查询语句
+     * @param obj    WHERE 条件参数
+     */
     @Override
     protected void processDelete(Delete delete, int index, String sql, Object obj) {
         Expression sqlSegment = dataPermissionHandler.getSqlSegment(delete.getWhere(), (String) obj, false);
@@ -101,10 +151,10 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
     }
 
     /**
-     * 设置 where 条件
+     * 设置 SELECT 语句的 WHERE 条件
      *
-     * @param plainSelect       查询对象
-     * @param mappedStatementId 执行方法id
+     * @param plainSelect       SELECT 查询对象
+     * @param mappedStatementId 映射语句的 ID
      */
     protected void setWhere(PlainSelect plainSelect, String mappedStatementId) {
         Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), mappedStatementId, true);
@@ -113,6 +163,14 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
         }
     }
 
+    /**
+     * 构建表达式,用于处理表的数据权限
+     *
+     * @param table        表对象
+     * @param where        WHERE 条件表达式
+     * @param whereSegment WHERE 条件片段
+     * @return 构建的表达式
+     */
     @Override
     public Expression buildTableExpression(Table table, Expression where, String whereSegment) {
         // 只有新版数据权限处理器才会执行到这里

+ 1 - 1
ruoyi-common/ruoyi-common-mybatis/src/main/resources/spy.properties

@@ -17,4 +17,4 @@ databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss
 # 是否过滤 Log
 filter=true
 # 过滤 Log 时所排除的 sql 关键字,以逗号分隔
-exclude=SELECT 1
+exclude=

+ 2 - 0
ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java

@@ -178,6 +178,7 @@ public class OssClient {
                             .key(key)
                             .contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null)
                             .contentType(contentType)
+                            .acl(getAccessPolicy().getObjectCannedACL())
                             .build())
                     .addTransferListener(LoggingTransferListener.create())
                     .source(filePath).build());
@@ -223,6 +224,7 @@ public class OssClient {
                         y -> y.bucket(properties.getBucketName())
                             .key(key)
                             .contentType(contentType)
+                            .acl(getAccessPolicy().getObjectCannedACL())
                             .build())
                     .build());
 

+ 4 - 3
ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/QueueUtils.java

@@ -1,12 +1,13 @@
 package org.dromara.common.redis.utils;
 
-import org.dromara.common.core.utils.SpringUtils;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.SpringUtils;
 import org.redisson.api.*;
 
+import java.util.concurrent.CompletionStage;
 import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
+import java.util.function.Function;
 
 /**
  * 分布式队列工具
@@ -224,7 +225,7 @@ public class QueueUtils {
     /**
      * 订阅阻塞队列(可订阅所有实现类 例如: 延迟 优先 有界 等)
      */
-    public static <T> void subscribeBlockingQueue(String queueName, Consumer<T> consumer, boolean isDelayed) {
+    public static <T> void subscribeBlockingQueue(String queueName, Function<T, CompletionStage<Void>> consumer, boolean isDelayed) {
         RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
         if (isDelayed) {
             // 订阅延迟队列

+ 16 - 8
ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java

@@ -3,6 +3,7 @@ package org.dromara.common.satoken.utils;
 import cn.dev33.satoken.session.SaSession;
 import cn.dev33.satoken.stp.SaLoginModel;
 import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.convert.Convert;
 import cn.hutool.core.util.ObjectUtil;
 import lombok.AccessLevel;
@@ -87,6 +88,13 @@ public class LoginHelper {
         return Convert.toLong(getExtra(USER_KEY));
     }
 
+    /**
+     * 获取用户账户
+     */
+    public static String getUsername() {
+        return Convert.toStr(getExtra(USER_NAME_KEY));
+    }
+
     /**
      * 获取租户ID
      */
@@ -129,13 +137,6 @@ public class LoginHelper {
         }
     }
 
-    /**
-     * 获取用户账户
-     */
-    public static String getUsername() {
-        return getLoginUser().getUsername();
-    }
-
     /**
      * 获取用户类型
      */
@@ -170,6 +171,9 @@ public class LoginHelper {
      * @return 结果
      */
     public static boolean isTenantAdmin(Set<String> rolePermission) {
+        if (CollUtil.isEmpty(rolePermission)) {
+            return false;
+        }
         return rolePermission.contains(TenantConstants.TENANT_ADMIN_ROLE_KEY);
     }
 
@@ -188,7 +192,11 @@ public class LoginHelper {
      * @return 结果
      */
     public static boolean isLogin() {
-        return getLoginUser() != null;
+        try {
+            return getLoginUser() != null;
+        } catch (Exception e) {
+            return false;
+        }
     }
 
 }

+ 1 - 5
ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java

@@ -16,15 +16,11 @@ import org.springframework.core.task.VirtualThreadTaskExecutor;
 @AutoConfiguration
 public class UndertowConfig implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
 
-    /**
-     * 设置 Undertow 的 websocket 缓冲池
-     */
     @Override
     public void customize(UndertowServletWebServerFactory factory) {
-        // 默认不直接分配内存 如果项目中使用了 websocket 建议直接分配
         factory.addDeploymentInfoCustomizers(deploymentInfo -> {
             WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo();
-            webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(false, 512));
+            webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(true, 1024));
             deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo);
             // 使用虚拟线程
             if (SpringUtils.isVirtual()) {

+ 20 - 15
ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/interceptor/PlusWebSocketInterceptor.java

@@ -35,23 +35,28 @@ public class PlusWebSocketInterceptor implements HandshakeInterceptor {
      */
     @Override
     public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) {
-        // 检查是否登录 是否有token
-        LoginUser loginUser = LoginHelper.getLoginUser();
+        try {
+            // 检查是否登录 是否有token
+            LoginUser loginUser = LoginHelper.getLoginUser();
 
-        // 解决 ws 不走 mvc 拦截器问题(cloud 版本不受影响)
-        // 检查 header 与 param 里的 clientid 与 token 里的是否一致
-        String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY);
-        String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY);
-        String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString();
-        if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {
-            // token 无效
-            throw NotLoginException.newInstance(StpUtil.getLoginType(),
-                "-100", "客户端ID与Token不匹配",
-                StpUtil.getTokenValue());
-        }
+            // 解决 ws 不走 mvc 拦截器问题(cloud 版本不受影响)
+            // 检查 header 与 param 里的 clientid 与 token 里的是否一致
+            String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY);
+            String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY);
+            String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString();
+            if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {
+                // token 无效
+                throw NotLoginException.newInstance(StpUtil.getLoginType(),
+                    "-100", "客户端ID与Token不匹配",
+                    StpUtil.getTokenValue());
+            }
 
-        attributes.put(LOGIN_USER_KEY, loginUser);
-        return true;
+            attributes.put(LOGIN_USER_KEY, loginUser);
+            return true;
+        } catch (NotLoginException e) {
+            log.error("WebSocket 认证失败'{}',无法访问系统资源", e.getMessage());
+            return false;
+        }
     }
 
     /**

+ 4 - 2
ruoyi-extend/ruoyi-monitor-admin/Dockerfile

@@ -1,7 +1,9 @@
+# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
+FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
+#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds
 #FROM findepi/graalvm:java17-native
-FROM openjdk:17.0.2-oraclelinux8
 
-MAINTAINER Lion Li
+LABEL maintainer="Lion Li"
 
 RUN mkdir -p /ruoyi/monitor/logs
 

+ 5 - 3
ruoyi-extend/ruoyi-snailjob-server/Dockerfile

@@ -1,7 +1,9 @@
+# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
+FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
+#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds
 #FROM findepi/graalvm:java17-native
-FROM openjdk:17.0.2-oraclelinux8
 
-MAINTAINER Lion Li
+LABEL maintainer="Lion Li"
 
 RUN mkdir -p /ruoyi/snailjob/logs
 
@@ -10,7 +12,7 @@ WORKDIR /ruoyi/snailjob
 ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="-Xms512m -Xmx1024m"
 
 EXPOSE 8800
-EXPOSE 1788
+EXPOSE 17888
 
 ADD ./target/ruoyi-snailjob-server.jar ./app.jar
 

+ 1 - 1
ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml

@@ -21,7 +21,7 @@ snail-job:
   # 拉取重试数据的每批次的大小
   job-pull-page-size: 1000
   # 服务端netty端口
-  netty-port: 1788
+  netty-port: 17888
   # 一个客户端每秒最多接收的重试数量指令
   limiter: 1000
   # 号段模式下步长配置

+ 1 - 1
ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml

@@ -21,7 +21,7 @@ snail-job:
   # 拉取重试数据的每批次的大小
   job-pull-page-size: 1000
   # 服务端 netty 端口
-  netty-port: 1788
+  netty-port: 17888
   # 一个客户端每秒最多接收的重试数量指令
   limiter: 1000
   # 号段模式下步长配置

+ 7 - 2
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/DelayedQueueController.java

@@ -1,14 +1,15 @@
 package org.dromara.demo.controller.queue;
 
 import cn.dev33.satoken.annotation.SaIgnore;
-import org.dromara.common.core.domain.R;
-import org.dromara.common.redis.utils.QueueUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.redis.utils.QueueUtils;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -42,6 +43,10 @@ public class DelayedQueueController {
         QueueUtils.subscribeBlockingQueue(queueName, (String orderNum) -> {
             // 观察接收时间
             log.info("通道: {}, 收到数据: {}", queueName, orderNum);
+            return CompletableFuture.runAsync(() -> {
+                // 异步处理数据逻辑 不要在上方处理业务逻辑
+                log.info("数据处理: {}", orderNum);
+            });
         }, true);
         return R.ok("操作成功");
     }

+ 1 - 1
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java

@@ -55,5 +55,5 @@ public interface TestDemoMapper extends BaseMapperPlus<TestDemo, TestDemoVo> {
         @DataColumn(key = "deptName", value = "dept_id"),
         @DataColumn(key = "userName", value = "user_id")
     })
-    int deleteBatchIds(@Param(Constants.COLL) Collection<?> idList);
+    int deleteByIds(@Param(Constants.COLL) Collection<?> idList);
 }

+ 1 - 1
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java

@@ -101,7 +101,7 @@ public class TestDemoServiceImpl implements ITestDemoService {
         if (isValid) {
             //TODO 做一些业务上的校验,判断是否需要校验
         }
-        return baseMapper.deleteBatchIds(ids) > 0;
+        return baseMapper.deleteByIds(ids) > 0;
     }
 
     @Override

+ 1 - 1
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java

@@ -83,6 +83,6 @@ public class TestTreeServiceImpl implements ITestTreeService {
         if (isValid) {
             //TODO 做一些业务上的校验,判断是否需要校验
         }
-        return baseMapper.deleteBatchIds(ids) > 0;
+        return baseMapper.deleteByIds(ids) > 0;
     }
 }

+ 2 - 2
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java

@@ -165,7 +165,7 @@ public class GenTableServiceImpl implements IGenTableService {
     @Override
     public void deleteGenTableByIds(Long[] tableIds) {
         List<Long> ids = Arrays.asList(tableIds);
-        baseMapper.deleteBatchIds(ids);
+        baseMapper.deleteByIds(ids);
         genTableColumnMapper.delete(new LambdaQueryWrapper<GenTableColumn>().in(GenTableColumn::getTableId, ids));
     }
 
@@ -332,7 +332,7 @@ public class GenTableServiceImpl implements IGenTableService {
         if (CollUtil.isNotEmpty(delColumns)) {
             List<Long> ids = StreamUtils.toList(delColumns, GenTableColumn::getColumnId);
             if (CollUtil.isNotEmpty(ids)) {
-                genTableColumnMapper.deleteBatchIds(ids);
+                genTableColumnMapper.deleteByIds(ids);
             }
         }
     }

+ 1 - 1
ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm

@@ -149,6 +149,6 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
         if(isValid){
             //TODO 做一些业务上的校验,判断是否需要校验
         }
-        return baseMapper.deleteBatchIds(ids) > 0;
+        return baseMapper.deleteByIds(ids) > 0;
     }
 }

+ 0 - 4
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java

@@ -75,8 +75,6 @@ public class SysDeptController extends BaseController {
     public R<Void> add(@Validated @RequestBody SysDeptBo dept) {
         if (!deptService.checkDeptNameUnique(dept)) {
             return R.fail("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
-        } else if (StringUtils.isNotBlank(dept.getDeptCategory()) && !deptService.checkDeptCategoryUnique(dept)) {
-            return R.fail("新增部门'" + dept.getDeptName() + "'失败,部门类别编码已存在");
         }
         return toAjax(deptService.insertDept(dept));
     }
@@ -92,8 +90,6 @@ public class SysDeptController extends BaseController {
         deptService.checkDeptDataScope(deptId);
         if (!deptService.checkDeptNameUnique(dept)) {
             return R.fail("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
-        } else if (StringUtils.isNotBlank(dept.getDeptCategory()) && !deptService.checkDeptCategoryUnique(dept)) {
-            return R.fail("修改部门'" + dept.getDeptName() + "'失败,部门类别编码已存在");
         } else if (dept.getParentId().equals(deptId)) {
             return R.fail("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
         } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus())) {

+ 0 - 7
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java

@@ -18,13 +18,6 @@ import java.util.List;
  */
 public interface SysMenuMapper extends BaseMapperPlus<SysMenu, SysMenuVo> {
 
-    /**
-     * 根据用户所有权限
-     *
-     * @return 权限列表
-     */
-    List<String> selectMenuPerms();
-
     /**
      * 根据用户查询系统菜单列表
      *

+ 0 - 8
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java

@@ -92,14 +92,6 @@ public interface ISysDeptService {
      */
     boolean checkDeptNameUnique(SysDeptBo dept);
 
-    /**
-     * 校验部门类别编码是否唯一
-     *
-     * @param dept 部门信息
-     * @return 结果
-     */
-    boolean checkDeptCategoryUnique(SysDeptBo dept);
-
     /**
      * 校验部门是否有数据权限
      *

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java

@@ -146,6 +146,6 @@ public class SysClientServiceImpl implements ISysClientService {
         if (isValid) {
             //TODO 做一些业务上的校验,判断是否需要校验
         }
-        return baseMapper.deleteBatchIds(ids) > 0;
+        return baseMapper.deleteByIds(ids) > 0;
     }
 }

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java

@@ -178,7 +178,7 @@ public class SysConfigServiceImpl implements ISysConfigService, ConfigService {
             }
             CacheUtils.evict(CacheNames.SYS_CONFIG, config.getConfigKey());
         }
-        baseMapper.deleteBatchIds(Arrays.asList(configIds));
+        baseMapper.deleteByIds(Arrays.asList(configIds));
     }
 
     /**

+ 15 - 3
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java

@@ -3,14 +3,14 @@ package org.dromara.system.service.impl;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.convert.Convert;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import org.dromara.system.domain.SysDept;
-import org.dromara.common.mybatis.helper.DataBaseHelper;
+import lombok.RequiredArgsConstructor;
 import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.system.domain.SysDept;
 import org.dromara.system.domain.SysRoleDept;
 import org.dromara.system.mapper.SysDeptMapper;
 import org.dromara.system.mapper.SysRoleDeptMapper;
 import org.dromara.system.service.ISysDataScopeService;
-import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
@@ -30,6 +30,12 @@ public class SysDataScopeServiceImpl implements ISysDataScopeService {
     private final SysRoleDeptMapper roleDeptMapper;
     private final SysDeptMapper deptMapper;
 
+    /**
+     * 获取角色自定义权限
+     *
+     * @param roleId 角色Id
+     * @return 部门Id组
+     */
     @Override
     public String getRoleCustom(Long roleId) {
         List<SysRoleDept> list = roleDeptMapper.selectList(
@@ -42,6 +48,12 @@ public class SysDataScopeServiceImpl implements ISysDataScopeService {
         return null;
     }
 
+    /**
+     * 获取部门及以下权限
+     *
+     * @param deptId 部门Id
+     * @return 部门Id组
+     */
     @Override
     public String getDeptAndChild(Long deptId) {
         List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()

+ 0 - 14
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java

@@ -218,20 +218,6 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
         return !exist;
     }
 
-    /**
-     * 校验部门类别编码是否唯一
-     *
-     * @param dept 部门信息
-     * @return 结果
-     */
-    @Override
-    public boolean checkDeptCategoryUnique(SysDeptBo dept) {
-        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysDept>()
-            .eq(SysDept::getDeptCategory, dept.getDeptCategory())
-            .ne(ObjectUtil.isNotNull(dept.getDeptId()), SysDept::getDeptId, dept.getDeptId()));
-        return !exist;
-    }
-
     /**
      * 校验部门是否有数据权限
      *

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java

@@ -141,7 +141,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService
             }
             CacheUtils.evict(CacheNames.SYS_DICT, dictType.getDictType());
         }
-        baseMapper.deleteBatchIds(Arrays.asList(dictIds));
+        baseMapper.deleteByIds(Arrays.asList(dictIds));
     }
 
     /**

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java

@@ -163,7 +163,7 @@ public class SysLogininforServiceImpl implements ISysLogininforService {
      */
     @Override
     public int deleteLogininforByIds(Long[] infoIds) {
-        return baseMapper.deleteBatchIds(Arrays.asList(infoIds));
+        return baseMapper.deleteByIds(Arrays.asList(infoIds));
     }
 
     /**

+ 8 - 4
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java

@@ -75,7 +75,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
                 .orderByAsc(SysMenu::getOrderNum));
         } else {
             QueryWrapper<SysMenu> wrapper = Wrappers.query();
-            wrapper.eq("sur.user_id", userId)
+            wrapper.inSql("r.role_id", "select role_id from sys_user_role where user_id = " + userId)
                 .like(StringUtils.isNotBlank(menu.getMenuName()), "m.menu_name", menu.getMenuName())
                 .eq(StringUtils.isNotBlank(menu.getVisible()), "m.visible", menu.getVisible())
                 .eq(StringUtils.isNotBlank(menu.getStatus()), "m.status", menu.getStatus())
@@ -178,6 +178,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
 
     /**
      * 构建前端路由所需要的菜单
+     * 路由name命名规则 path首字母转大写 + id
      *
      * @param menus 菜单列表
      * @return 路由列表
@@ -186,9 +187,10 @@ public class SysMenuServiceImpl implements ISysMenuService {
     public List<RouterVo> buildMenus(List<SysMenu> menus) {
         List<RouterVo> routers = new LinkedList<>();
         for (SysMenu menu : menus) {
+            String name = menu.getRouteName() + menu.getMenuId();
             RouterVo router = new RouterVo();
             router.setHidden("1".equals(menu.getVisible()));
-            router.setName(menu.getRouteName());
+            router.setName(name);
             router.setPath(menu.getRouterPath());
             router.setComponent(menu.getComponentInfo());
             router.setQuery(menu.getQueryParam());
@@ -199,12 +201,13 @@ public class SysMenuServiceImpl implements ISysMenuService {
                 router.setRedirect("noRedirect");
                 router.setChildren(buildMenus(cMenus));
             } else if (menu.isMenuFrame()) {
+                String frameName = StringUtils.capitalize(menu.getPath()) + menu.getMenuId();
                 router.setMeta(null);
                 List<RouterVo> childrenList = new ArrayList<>();
                 RouterVo children = new RouterVo();
                 children.setPath(menu.getPath());
                 children.setComponent(menu.getComponent());
-                children.setName(StringUtils.capitalize(menu.getPath()));
+                children.setName(frameName);
                 children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
                 children.setQuery(menu.getQueryParam());
                 childrenList.add(children);
@@ -215,9 +218,10 @@ public class SysMenuServiceImpl implements ISysMenuService {
                 List<RouterVo> childrenList = new ArrayList<>();
                 RouterVo children = new RouterVo();
                 String routerPath = SysMenu.innerLinkReplaceEach(menu.getPath());
+                String innerLinkName = StringUtils.capitalize(routerPath) + menu.getMenuId();
                 children.setPath(routerPath);
                 children.setComponent(UserConstants.INNER_LINK);
-                children.setName(StringUtils.capitalize(routerPath));
+                children.setName(innerLinkName);
                 children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
                 childrenList.add(children);
                 router.setChildren(childrenList);

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java

@@ -119,6 +119,6 @@ public class SysNoticeServiceImpl implements ISysNoticeService {
      */
     @Override
     public int deleteNoticeByIds(Long[] noticeIds) {
-        return baseMapper.deleteBatchIds(Arrays.asList(noticeIds));
+        return baseMapper.deleteByIds(Arrays.asList(noticeIds));
     }
 }

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java

@@ -122,7 +122,7 @@ public class SysOperLogServiceImpl implements ISysOperLogService {
      */
     @Override
     public int deleteOperLogByIds(Long[] operIds) {
-        return baseMapper.deleteBatchIds(Arrays.asList(operIds));
+        return baseMapper.deleteByIds(Arrays.asList(operIds));
     }
 
     /**

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java

@@ -135,7 +135,7 @@ public class SysOssConfigServiceImpl implements ISysOssConfigService {
             SysOssConfig config = baseMapper.selectById(configId);
             list.add(config);
         }
-        boolean flag = baseMapper.deleteBatchIds(ids) > 0;
+        boolean flag = baseMapper.deleteByIds(ids) > 0;
         if (flag) {
             list.forEach(sysOssConfig ->
                 CacheUtils.evict(CacheNames.SYS_OSS_CONFIG, sysOssConfig.getConfigKey()));

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java

@@ -247,7 +247,7 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
             OssClient storage = OssFactory.instance(sysOss.getService());
             storage.delete(sysOss.getUrl());
         }
-        return baseMapper.deleteBatchIds(ids) > 0;
+        return baseMapper.deleteByIds(ids) > 0;
     }
 
     /**

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java

@@ -202,7 +202,7 @@ public class SysPostServiceImpl implements ISysPostService {
                 throw new ServiceException(String.format("%1$s已分配,不能删除!", post.getPostName()));
             }
         }
-        return baseMapper.deleteBatchIds(Arrays.asList(postIds));
+        return baseMapper.deleteByIds(Arrays.asList(postIds));
     }
 
     /**

+ 7 - 8
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java

@@ -102,14 +102,13 @@ public class SysRoleServiceImpl implements ISysRoleService {
      */
     @Override
     public List<SysRoleVo> selectRolesAuthByUserId(Long userId) {
-        List<SysRoleVo> userRoles = baseMapper.selectRolePermissionByUserId(userId);
+        List<SysRoleVo> userRoles = baseMapper.selectRolesByUserId(userId);
         List<SysRoleVo> roles = selectRoleAll();
+        // 使用HashSet提高查找效率
+        Set<Long> userRoleIds = StreamUtils.toSet(userRoles, SysRoleVo::getRoleId);
         for (SysRoleVo role : roles) {
-            for (SysRoleVo userRole : userRoles) {
-                if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) {
-                    role.setFlag(true);
-                    break;
-                }
+            if (userRoleIds.contains(role.getRoleId())) {
+                role.setFlag(true);
             }
         }
         return roles;
@@ -123,7 +122,7 @@ public class SysRoleServiceImpl implements ISysRoleService {
      */
     @Override
     public Set<String> selectRolePermissionByUserId(Long userId) {
-        List<SysRoleVo> perms = baseMapper.selectRolePermissionByUserId(userId);
+        List<SysRoleVo> perms = baseMapper.selectRolesByUserId(userId);
         Set<String> permsSet = new HashSet<>();
         for (SysRoleVo perm : perms) {
             if (ObjectUtil.isNotNull(perm)) {
@@ -417,7 +416,7 @@ public class SysRoleServiceImpl implements ISysRoleService {
         roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().in(SysRoleMenu::getRoleId, ids));
         // 删除角色与部门关联
         roleDeptMapper.delete(new LambdaQueryWrapper<SysRoleDept>().in(SysRoleDept::getRoleId, ids));
-        return baseMapper.deleteBatchIds(ids);
+        return baseMapper.deleteByIds(ids);
     }
 
     /**

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java

@@ -140,6 +140,6 @@ public class SysTenantPackageServiceImpl implements ISysTenantPackageService {
                 throw new ServiceException("租户套餐已被使用");
             }
         }
-        return baseMapper.deleteBatchIds(ids) > 0;
+        return baseMapper.deleteByIds(ids) > 0;
     }
 }

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java

@@ -294,7 +294,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
                 throw new ServiceException("超管租户不能删除");
             }
         }
-        return baseMapper.deleteBatchIds(ids) > 0;
+        return baseMapper.deleteByIds(ids) > 0;
     }
 
     /**

+ 2 - 2
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java

@@ -99,7 +99,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
                 w.in("u.dept_id", ids);
             }).orderByAsc("u.user_id");
         if (StringUtils.isNotBlank(user.getExcludeUserIds())) {
-            wrapper.notIn("u.user_id", StringUtils.splitList(user.getExcludeUserIds()));
+            wrapper.notIn("u.user_id", StringUtils.splitTo(user.getExcludeUserIds(), Convert::toLong));
         }
         return wrapper;
     }
@@ -541,7 +541,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
         // 删除用户与岗位表
         userPostMapper.delete(new LambdaQueryWrapper<SysUserPost>().in(SysUserPost::getUserId, ids));
         // 防止更新失败导致的数据删除
-        int flag = baseMapper.deleteBatchIds(ids);
+        int flag = baseMapper.deleteByIds(ids);
         if (flag < 1) {
             throw new ServiceException("删除用户失败!");
         }

+ 9 - 24
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml

@@ -11,9 +11,8 @@
         select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.query_param, m.visible, m.status,
         m.perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
         from sys_menu m
-        left join sys_role_menu rm on m.menu_id = rm.menu_id
-        left join sys_user_role sur on rm.role_id = sur.role_id
-        left join sys_role ro on sur.role_id = ro.role_id
+            left join sys_role_menu rm on m.menu_id = rm.menu_id
+            left join sys_role r on rm.role_id = r.role_id
         ${ew.getCustomSqlSegment}
     </select>
 
@@ -34,14 +33,10 @@
                         m.order_num,
                         m.create_time
         from sys_menu m
-                 left join sys_role_menu rm on m.menu_id = rm.menu_id
-                 left join sys_user_role sur on rm.role_id = sur.role_id
-                 left join sys_role ro on sur.role_id = ro.role_id
-                 left join sys_user u on sur.user_id = u.user_id
-        where u.user_id = #{userId}
-          and m.menu_type in ('M', 'C')
-          and m.status = '0'
-          and ro.status = '0'
+                 left join sys_role_menu rm on m.menu_id = rm.menu_id and m.status = '0'
+                 left join sys_role r on rm.role_id = r.role_id and r.status = '0'
+        where m.menu_type in ('M', 'C')
+          and r.role_id in (select role_id from sys_user_role where user_id = #{userId})
         order by m.parent_id, m.order_num
     </select>
 
@@ -57,22 +52,12 @@
         order by m.parent_id, m.order_num
     </select>
 
-    <select id="selectMenuPerms" resultType="String">
-        select distinct m.perms
-        from sys_menu m
-                 left join sys_role_menu rm on m.menu_id = rm.menu_id
-                 left join sys_user_role sur on rm.role_id = sur.role_id
-    </select>
-
     <select id="selectMenuPermsByUserId" parameterType="Long" resultType="String">
         select distinct m.perms
         from sys_menu m
-                 left join sys_role_menu rm on m.menu_id = rm.menu_id
-                 left join sys_user_role sur on rm.role_id = sur.role_id
-                 left join sys_role r on r.role_id = sur.role_id
-        where m.status = '0'
-          and r.status = '0'
-          and sur.user_id = #{userId}
+                 left join sys_role_menu rm on m.menu_id = rm.menu_id and m.status = '0'
+                 left join sys_role r on r.role_id = rm.role_id and r.status = '0'
+        where r.role_id in (select role_id from sys_user_role where user_id = #{userId})
     </select>
 
     <select id="selectMenuPermsByRoleId" parameterType="Long" resultType="String">

+ 1 - 3
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml

@@ -48,9 +48,7 @@
                r.data_scope,
                r.status
         from sys_role r
-                 left join sys_user_role sur on sur.role_id = r.role_id
-                 left join sys_user u on u.user_id = sur.user_id
-        WHERE r.del_flag = '0' and sur.user_id = #{userId}
+        WHERE r.del_flag = '0' and r.role_id in (select role_id from sys_user_role where user_id = #{userId})
     </select>
 
     <select id="selectRoleById" resultMap="SysRoleResult">

+ 2 - 1
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java

@@ -2,6 +2,7 @@ package org.dromara.workflow.flowable.cmd;
 
 import cn.hutool.core.util.ObjectUtil;
 import lombok.AllArgsConstructor;
+import org.dromara.common.core.utils.StreamUtils;
 import org.flowable.common.engine.impl.interceptor.Command;
 import org.flowable.common.engine.impl.interceptor.CommandContext;
 import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
@@ -59,7 +60,7 @@ public class DeleteSequenceMultiInstanceCmd implements Command<Void> {
         }
         List<Long> userIdList = new ArrayList<>();
         userIds.forEach(e -> {
-            Long userId = assignees.stream().filter(id -> ObjectUtil.equals(id, e)).findFirst().orElse(null);
+            Long userId = StreamUtils.findFirst(assignees, id -> ObjectUtil.equals(id, e));
             if (userId == null) {
                 userIdList.add(e);
             }

+ 14 - 15
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java

@@ -9,6 +9,7 @@ import cn.hutool.core.util.ObjectUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.enums.BusinessStatusEnum;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.service.UserService;
 import org.dromara.common.core.utils.StreamUtils;
@@ -17,7 +18,6 @@ import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.workflow.common.constant.FlowConstant;
-import org.dromara.common.core.enums.BusinessStatusEnum;
 import org.dromara.workflow.common.enums.TaskStatusEnum;
 import org.dromara.workflow.domain.ActHiProcinst;
 import org.dromara.workflow.domain.bo.ProcessInstanceBo;
@@ -34,7 +34,7 @@ import org.dromara.workflow.service.IWfNodeConfigService;
 import org.dromara.workflow.service.IWfTaskBackNodeService;
 import org.dromara.workflow.utils.QueryUtils;
 import org.dromara.workflow.utils.WorkflowUtils;
-import org.flowable.bpmn.model.*;
+import org.flowable.bpmn.model.BpmnModel;
 import org.flowable.engine.*;
 import org.flowable.engine.history.HistoricActivityInstance;
 import org.flowable.engine.history.HistoricProcessInstance;
@@ -57,7 +57,6 @@ import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.*;
-import java.util.stream.Collectors;
 
 /**
  * 流程实例 服务层实现
@@ -257,23 +256,23 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
         List<HistoricActivityInstance> highLightedFlowList = QueryUtils.hisActivityInstanceQuery(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
         for (HistoricActivityInstance tempActivity : highLightedFlowList) {
             Map<String, Object> task = new HashMap<>();
-            if (!FlowConstant.SEQUENCE_FLOW.equals(tempActivity.getActivityType()) &&
-                !FlowConstant.PARALLEL_GATEWAY.equals(tempActivity.getActivityType()) &&
-                !FlowConstant.EXCLUSIVE_GATEWAY.equals(tempActivity.getActivityType()) &&
-                !FlowConstant.INCLUSIVE_GATEWAY.equals(tempActivity.getActivityType())
-            ) {
-                task.put("key", tempActivity.getActivityId());
-                task.put("completed", tempActivity.getEndTime() != null);
-                task.put("activityType", tempActivity.getActivityType());
-                taskList.add(task);
+            switch (tempActivity.getActivityType()) {
+                case FlowConstant.SEQUENCE_FLOW, FlowConstant.PARALLEL_GATEWAY,
+                     FlowConstant.EXCLUSIVE_GATEWAY, FlowConstant.INCLUSIVE_GATEWAY -> {}
+                default -> {
+                    task.put("key", tempActivity.getActivityId());
+                    task.put("completed", tempActivity.getEndTime() != null);
+                    task.put("activityType", tempActivity.getActivityType());
+                    taskList.add(task);
+                }
             }
         }
         ProcessInstance processInstance = QueryUtils.instanceQuery(processInstanceId).singleResult();
         if (processInstance != null) {
-            taskList = taskList.stream().filter(e -> !e.get("activityType").equals(FlowConstant.END_EVENT)).collect(Collectors.toList());
+            taskList = StreamUtils.filter(taskList, e -> !e.get("activityType").equals(FlowConstant.END_EVENT));
         }
         //查询出运行中节点
-        List<Map<String, Object>> runtimeNodeList = taskList.stream().filter(e -> !(Boolean) e.get("completed")).collect(Collectors.toList());
+        List<Map<String, Object>> runtimeNodeList = StreamUtils.filter(taskList, e -> !(Boolean) e.get("completed"));
         if (CollUtil.isNotEmpty(runtimeNodeList)) {
             Iterator<Map<String, Object>> iterator = taskList.iterator();
             while (iterator.hasNext()) {
@@ -389,7 +388,7 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
             }
             //附件
             if (CollUtil.isNotEmpty(attachmentList)) {
-                List<Attachment> attachments = attachmentList.stream().filter(e -> e.getTaskId().equals(historicTaskInstance.getId())).collect(Collectors.toList());
+                List<Attachment> attachments = StreamUtils.filter(attachmentList, e -> e.getTaskId().equals(historicTaskInstance.getId()));
                 if (CollUtil.isNotEmpty(attachments)) {
                     actHistoryInfoVo.setAttachmentList(attachments);
                 }

+ 3 - 15
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java

@@ -260,7 +260,8 @@ public class ActTaskServiceImpl implements IActTaskService {
         String userId = String.valueOf(LoginHelper.getUserId());
         queryWrapper.eq("t.business_status_", BusinessStatusEnum.WAITING.getStatus());
         queryWrapper.eq(TenantHelper.isEnable(), "t.tenant_id_", TenantHelper.getTenantId());
-        queryWrapper.and(w1 -> w1.eq("t.assignee_", userId).or(w2 -> w2.isNull("t.assignee_").apply("exists ( select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TASK_ID_ = t.ID_ and LINK.TYPE_ = 'candidate' " + "and (LINK.USER_ID_ = {0} or ( LINK.GROUP_ID_ IN " + getInParam(roleIds) + " ) ))", userId)));
+        String ids = StreamUtils.join(roleIds, x -> "'" + x + "'");
+        queryWrapper.and(w1 -> w1.eq("t.assignee_", userId).or(w2 -> w2.isNull("t.assignee_").apply("exists ( select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TASK_ID_ = t.ID_ and LINK.TYPE_ = 'candidate' and (LINK.USER_ID_ = {0} or ( LINK.GROUP_ID_ IN ({1}) ) ))", userId, ids)));
         if (StringUtils.isNotBlank(taskBo.getName())) {
             queryWrapper.like("t.name_", taskBo.getName());
         }
@@ -289,19 +290,6 @@ public class ActTaskServiceImpl implements IActTaskService {
         return TableDataInfo.build(page);
     }
 
-    private String getInParam(List<String> param) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("(");
-        for (int i = 0; i < param.size(); i++) {
-            sb.append("'").append(param.get(i)).append("'");
-            if (i != param.size() - 1) {
-                sb.append(",");
-            }
-        }
-        sb.append(")");
-        return sb.toString();
-    }
-
     /**
      * 查询当前租户所有待办任务
      *
@@ -696,7 +684,7 @@ public class ActTaskServiceImpl implements IActTaskService {
             if (multiInstance == null && taskList.size() > 1) {
                 List<Task> tasks = StreamUtils.filter(taskList, e -> !e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey()));
                 if (CollUtil.isNotEmpty(tasks)) {
-                    actHiTaskinstMapper.deleteBatchIds(StreamUtils.toList(tasks, Task::getId));
+                    actHiTaskinstMapper.deleteByIds(StreamUtils.toList(tasks, Task::getId));
                 }
             }
 

+ 1 - 1
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java

@@ -111,7 +111,7 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
     public Boolean deleteWithValidByIds(Collection<Long> ids) {
         List<String> idList = StreamUtils.toList(ids, String::valueOf);
         workflowService.deleteRunAndHisInstance(idList);
-        return baseMapper.deleteBatchIds(ids) > 0;
+        return baseMapper.deleteByIds(ids) > 0;
     }
 
     /**

+ 1 - 1
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java

@@ -114,7 +114,7 @@ public class WfCategoryServiceImpl implements IWfCategoryService {
         if (isValid) {
             //TODO 做一些业务上的校验,判断是否需要校验
         }
-        return baseMapper.deleteBatchIds(ids) > 0;
+        return baseMapper.deleteByIds(ids) > 0;
     }
 
     /**

+ 1 - 1
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java

@@ -107,7 +107,7 @@ public class WfDefinitionConfigServiceImpl implements IWfDefinitionConfigService
      */
     @Override
     public Boolean deleteByIds(Collection<Long> ids) {
-        return baseMapper.deleteBatchIds(ids) > 0;
+        return baseMapper.deleteByIds(ids) > 0;
     }
 
     @Override

+ 1 - 1
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java

@@ -106,6 +106,6 @@ public class WfFormManageServiceImpl implements IWfFormManageService {
      */
     @Override
     public Boolean deleteByIds(Collection<Long> ids) {
-        return baseMapper.deleteBatchIds(ids) > 0;
+        return baseMapper.deleteByIds(ids) > 0;
     }
 }

+ 1 - 1
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java

@@ -50,7 +50,7 @@ public class WfNodeConfigServiceImpl implements IWfNodeConfigService {
      */
     @Override
     public Boolean deleteByIds(Collection<Long> ids) {
-        return baseMapper.deleteBatchIds(ids) > 0;
+        return baseMapper.deleteByIds(ids) > 0;
     }
 
 

+ 3 - 2
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.workflow.domain.WfTaskBackNode;
@@ -56,7 +57,7 @@ public class WfTaskBackNodeServiceImpl implements IWfTaskBackNodeService {
             wfTaskBackNode.setOrderNo(0);
             wfTaskBackNodeMapper.insert(wfTaskBackNode);
         } else {
-            WfTaskBackNode taskNode = list.stream().filter(e -> e.getNodeId().equals(wfTaskBackNode.getNodeId()) && e.getOrderNo() == 0).findFirst().orElse(null);
+            WfTaskBackNode taskNode = StreamUtils.findFirst(list, e -> e.getNodeId().equals(wfTaskBackNode.getNodeId()) && e.getOrderNo() == 0);
             if (ObjectUtil.isEmpty(taskNode)) {
                 wfTaskBackNode.setOrderNo(list.get(0).getOrderNo() + 1);
                 WfTaskBackNode node = getListByInstanceIdAndNodeId(wfTaskBackNode.getInstanceId(), wfTaskBackNode.getNodeId());
@@ -106,7 +107,7 @@ public class WfTaskBackNodeServiceImpl implements IWfTaskBackNodeService {
                     }
                 }
                 if (CollUtil.isNotEmpty(ids)) {
-                    wfTaskBackNodeMapper.deleteBatchIds(ids);
+                    wfTaskBackNodeMapper.deleteByIds(ids);
                 }
             }
             return true;

+ 5 - 5
script/docker/docker-compose.yml

@@ -100,7 +100,7 @@ services:
     network_mode: "host"
 
   ruoyi-server1:
-    image: ruoyi/ruoyi-server:5.2.0
+    image: ruoyi/ruoyi-server:5.2.1
     container_name: ruoyi-server1
     environment:
       # 时区上海
@@ -115,7 +115,7 @@ services:
     network_mode: "host"
 
   ruoyi-server2:
-    image: ruoyi/ruoyi-server:5.2.0
+    image: ruoyi/ruoyi-server:5.2.1
     container_name: ruoyi-server2
     environment:
       # 时区上海
@@ -130,7 +130,7 @@ services:
     network_mode: "host"
 
   ruoyi-monitor-admin:
-    image: ruoyi/ruoyi-monitor-admin:5.2.0
+    image: ruoyi/ruoyi-monitor-admin:5.2.1
     container_name: ruoyi-monitor-admin
     environment:
       # 时区上海
@@ -142,14 +142,14 @@ services:
     network_mode: "host"
 
   ruoyi-snailjob-server:
-    image: ruoyi/ruoyi-snailjob-server:5.2.0
+    image: ruoyi/ruoyi-snailjob-server:5.2.1
     container_name: ruoyi-snailjob-server
     environment:
       # 时区上海
       TZ: Asia/Shanghai
     ports:
       - "8800:8800"
-      - "1788:1788"
+      - "17888:17888"
     volumes:
       - /docker/snailjob/logs/:/ruoyi/snailjob/logs
     privileged: true

+ 1 - 1
script/docker/nginx/conf/nginx.conf

@@ -63,7 +63,7 @@ http {
         # }
 
         # 限制外网访问内网 actuator 相关路径
-        location ~ ^(/[^/]*)?/actuator(/.*)?$ {
+        location ~ ^(/[^/]*)?/actuator.*(/.*)?$ {
             return 403;
         }
 

+ 2 - 71
script/sql/postgres/flowable.sql

@@ -39,29 +39,17 @@ create table test_leave
 );
 
 comment on table test_leave is '请假申请表';
-
 comment on column test_leave.id is '主键';
-
 comment on column test_leave.leave_type is '请假类型';
-
 comment on column test_leave.start_date is '开始时间';
-
 comment on column test_leave.end_date is '结束时间';
-
 comment on column test_leave.remark is '请假原因';
-
 comment on column test_leave.status is '状态';
-
 comment on column test_leave.create_dept is '创建部门';
-
 comment on column test_leave.create_by is '创建者';
-
 comment on column test_leave.create_time is '创建时间';
-
 comment on column test_leave.update_by is '更新者';
-
 comment on column test_leave.update_time is '更新时间';
-
 comment on column test_leave.tenant_id is '租户编码';
 
 alter table test_leave
@@ -86,27 +74,16 @@ create table wf_category
 );
 
 comment on table wf_category is '流程分类';
-
 comment on column wf_category.id is '主键';
-
 comment on column wf_category.category_name is '分类名称';
-
 comment on column wf_category.category_code is '分类编码';
-
 comment on column wf_category.parent_id is '父级id';
-
 comment on column wf_category.sort_num is '排序';
-
 comment on column wf_category.tenant_id is '租户id';
-
 comment on column wf_category.create_dept is '创建部门';
-
 comment on column wf_category.create_by is '创建者';
-
 comment on column wf_category.create_time is '创建时间';
-
 comment on column wf_category.update_by is '修改者';
-
 comment on column wf_category.update_time is '修改时间';
 
 alter table wf_category
@@ -137,31 +114,18 @@ create table wf_task_back_node
 );
 
 comment on table wf_task_back_node is '节点审批记录';
-
 comment on column wf_task_back_node.id is '主键';
-
 comment on column wf_task_back_node.node_id is '节点id';
-
 comment on column wf_task_back_node.node_name is '节点名称';
-
 comment on column wf_task_back_node.order_no is '排序';
-
 comment on column wf_task_back_node.instance_id is '流程实例id';
-
 comment on column wf_task_back_node.task_type is '节点类型';
-
 comment on column wf_task_back_node.assignee is '审批人';
-
 comment on column wf_task_back_node.tenant_id is '租户id';
-
 comment on column wf_task_back_node.create_dept is '创建部门';
-
 comment on column wf_task_back_node.create_by is '创建者';
-
 comment on column wf_task_back_node.create_time is '创建时间';
-
 comment on column wf_task_back_node.update_by is '修改者';
-
 comment on column wf_task_back_node.update_time is '修改时间';
 
 alter table wf_task_back_node
@@ -177,6 +141,7 @@ create table wf_definition_config
     process_key   varchar(255) not null,
     version       bigint       not null,
     tenant_id     varchar(20),
+    remark        varchar(500),
     create_dept   bigint,
     create_by     bigint,
     create_time   timestamp,
@@ -185,27 +150,17 @@ create table wf_definition_config
 );
 
 comment on table wf_definition_config is '流程定义配置';
-
 comment on column wf_definition_config.id is '主键';
-
 comment on column wf_definition_config.table_name is '表名';
-
 comment on column wf_definition_config.definition_id is '流程定义ID';
-
 comment on column wf_definition_config.process_key is '流程KEY';
-
 comment on column wf_definition_config.version is '流程版本';
-
 comment on column wf_definition_config.tenant_id is '租户id';
-
+comment on column wf_definition_config.remark is '备注';
 comment on column wf_definition_config.create_dept is '创建部门';
-
 comment on column wf_definition_config.create_by is '创建者';
-
 comment on column wf_definition_config.create_time is '创建时间';
-
 comment on column wf_definition_config.update_by is '修改者';
-
 comment on column wf_definition_config.update_time is '修改时间';
 
 alter table wf_definition_config
@@ -231,27 +186,16 @@ create table wf_form_manage
 );
 
 comment on table wf_form_manage is '表单管理';
-
 comment on column wf_form_manage.id is '主键';
-
 comment on column wf_form_manage.form_name is '表单名称';
-
 comment on column wf_form_manage.form_type is '表单类型';
-
 comment on column wf_form_manage.router is '路由地址/表单ID';
-
 comment on column wf_form_manage.remark is '备注';
-
 comment on column wf_form_manage.tenant_id is '租户id';
-
 comment on column wf_form_manage.create_dept is '创建部门';
-
 comment on column wf_form_manage.create_by is '创建者';
-
 comment on column wf_form_manage.create_time is '创建时间';
-
 comment on column wf_form_manage.update_by is '修改者';
-
 comment on column wf_form_manage.update_time is '修改时间';
 
 insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, now(), 1, now());
@@ -276,31 +220,18 @@ create table wf_node_config
 );
 
 comment on table wf_node_config is '节点配置';
-
 comment on column wf_node_config.id is '主键';
-
 comment on column wf_node_config.form_id is '表单id';
-
 comment on column wf_node_config.form_type is '表单类型';
-
 comment on column wf_node_config.node_id is '节点id';
-
 comment on column wf_node_config.node_name is '节点名称';
-
 comment on column wf_node_config.definition_id is '流程定义id';
-
 comment on column wf_node_config.apply_user_task is '是否为申请人节点 (0是 1否)';
-
 comment on column wf_node_config.tenant_id is '租户id';
-
 comment on column wf_node_config.create_dept is '创建部门';
-
 comment on column wf_node_config.create_by is '创建者';
-
 comment on column wf_node_config.create_time is '创建时间';
-
 comment on column wf_node_config.update_by is '修改者';
-
 comment on column wf_node_config.update_time is '修改时间';
 
 INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, now(), NULL, NULL, '请假申请菜单');