Forráskód Böngészése

Merge branch '5.X' of https://gitee.com/dromara/RuoYi-Vue-Plus into JustAuth

# Conflicts:
#	ruoyi-admin/src/main/resources/application-dev.yml
thiszhc 2 éve
szülő
commit
aec0e22747
34 módosított fájl, 295 hozzáadás és 648 törlés
  1. 1 1
      README.md
  2. 5 12
      pom.xml
  3. 11 15
      ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java
  4. 9 10
      ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
  5. 24 157
      ruoyi-admin/src/main/resources/application-dev.yml
  6. 24 9
      ruoyi-admin/src/main/resources/application-prod.yml
  7. 11 47
      ruoyi-admin/src/main/resources/application.yml
  8. 5 0
      ruoyi-common/ruoyi-common-core/pom.xml
  9. 2 8
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java
  10. 13 12
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java
  11. 31 0
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java
  12. 6 1
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java
  13. 39 4
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java
  14. 8 8
      ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java
  15. 2 2
      ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java
  16. 1 1
      ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  17. 3 0
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
  18. 33 0
      ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml
  19. 3 0
      ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java
  20. 11 0
      ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml
  21. 9 12
      ruoyi-common/ruoyi-common-sms/pom.xml
  22. 1 34
      ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsConfig.java
  23. 19 45
      ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/properties/SmsProperties.java
  24. 0 66
      ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/AliyunSmsTemplate.java
  25. 0 26
      ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/SmsTemplate.java
  26. 0 82
      ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/TencentSmsTemplate.java
  27. 0 31
      ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/entity/SmsResult.java
  28. 0 19
      ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/exception/SmsException.java
  29. 0 10
      ruoyi-modules/ruoyi-demo/pom.xml
  30. 14 30
      ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java
  31. 2 1
      ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java
  32. 3 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
  33. 4 3
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
  34. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java

+ 1 - 1
README.md

@@ -57,7 +57,7 @@
 | 分布式任务调度     | 采用 Xxl-Job 天生支持分布式 统一的管理中心                                                                                        | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造                                                   | 
 | 文件存储        | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储<br/>支持权限管理 安全可靠 文件可加密存储                                                     | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应                                                    |
 | 云存储         | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家                                                                          | 不支持                                                                                |
-| 短信          | 支持 阿里、腾讯 只需在yml配置好厂家密钥即可使用 接口化支持扩展其他厂家                                                                            | 不支持                                                                                |
+| 短信          | 采用 sms4j 短信融合包 支持数十种短信厂家 只需在yml配置好厂家密钥即可使用 可多厂家共用                                                                 | 不支持                                                                                |
 | 邮件          | 采用 mail-api 通用协议支持大部分邮件厂商                                                                                         | 不支持                                                                                |
 | 接口文档        | 采用 SpringDoc、javadoc 无注解零入侵基于java注释<br/>只需把注释写好 无需再写一大堆的文档注解了                                                     | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成                                                | 
 | 校验框架        | 采用 Validation 支持注解与工具类校验 注解支持国际化                                                                                  | 仅支持注解 且注解不支持国际化                                                                    |

+ 5 - 12
pom.xml

@@ -49,8 +49,7 @@
         <!-- OSS 配置 -->
         <aws-java-sdk-s3.version>1.12.400</aws-java-sdk-s3.version>
         <!-- SMS 配置 -->
-        <aliyun.sms.version>2.0.23</aliyun.sms.version>
-        <tencent.sms.version>3.1.687</tencent.sms.version>
+        <sms4j.version>2.1.1</sms4j.version>
 
         <!-- 插件版本 -->
         <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
@@ -242,17 +241,11 @@
                 <artifactId>aws-java-sdk-s3</artifactId>
                 <version>${aws-java-sdk-s3.version}</version>
             </dependency>
-
-            <dependency>
-                <groupId>com.aliyun</groupId>
-                <artifactId>dysmsapi20170525</artifactId>
-                <version>${aliyun.sms.version}</version>
-            </dependency>
-
+            <!--短信sms4j-->
             <dependency>
-                <groupId>com.tencentcloudapi</groupId>
-                <artifactId>tencentcloud-sdk-java-sms</artifactId>
-                <version>${tencent.sms.version}</version>
+                <groupId>org.dromara.sms4j</groupId>
+                <artifactId>sms4j-spring-boot-starter</artifactId>
+                <version>${sms4j.version}</version>
             </dependency>
 
             <dependency>

+ 11 - 15
ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java

@@ -14,11 +14,12 @@ import org.dromara.common.core.utils.reflect.ReflectUtils;
 import org.dromara.common.mail.config.properties.MailProperties;
 import org.dromara.common.mail.utils.MailUtils;
 import org.dromara.common.redis.utils.RedisUtils;
-import org.dromara.common.sms.config.properties.SmsProperties;
-import org.dromara.common.sms.core.SmsTemplate;
-import org.dromara.common.sms.entity.SmsResult;
 import org.dromara.common.web.config.properties.CaptchaProperties;
 import org.dromara.common.web.enums.CaptchaType;
+import org.dromara.sms4j.api.SmsBlend;
+import org.dromara.sms4j.api.entity.SmsResponse;
+import org.dromara.sms4j.core.factory.SmsFactory;
+import org.dromara.sms4j.provider.enumerate.SupplierType;
 import org.dromara.web.domain.vo.CaptchaVo;
 import jakarta.validation.constraints.NotBlank;
 import lombok.RequiredArgsConstructor;
@@ -31,8 +32,7 @@ import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.time.Duration;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.LinkedHashMap;
 
 /**
  * 验证码操作处理
@@ -47,7 +47,6 @@ import java.util.Map;
 public class CaptchaController {
 
     private final CaptchaProperties captchaProperties;
-    private final SmsProperties smsProperties;
     private final MailProperties mailProperties;
 
     /**
@@ -57,21 +56,18 @@ public class CaptchaController {
      */
     @GetMapping("/resource/sms/code")
     public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
-        if (!smsProperties.getEnabled()) {
-            return R.fail("当前系统没有开启短信功能!");
-        }
         String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber;
         String code = RandomUtil.randomNumbers(4);
         RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
         // 验证码模板id 自行处理 (查数据库或写死均可)
         String templateId = "";
-        Map<String, String> map = new HashMap<>(1);
+        LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
         map.put("code", code);
-        SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class);
-        SmsResult result = smsTemplate.send(phonenumber, templateId, map);
-        if (!result.isSuccess()) {
-            log.error("验证码短信发送异常 => {}", result);
-            return R.fail(result.getMessage());
+        SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
+        SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map);
+        if (!"OK".equals(smsResponse.getCode())) {
+            log.error("验证码短信发送异常 => {}", smsResponse);
+            return R.fail(smsResponse.getMessage());
         }
         return R.ok();
     }

+ 9 - 10
ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java

@@ -345,7 +345,7 @@ public class SysLoginService {
 
     private SysUserVo loadUserByEmail(String tenantId, String email) {
         SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
-            .select(SysUser::getPhonenumber, SysUser::getStatus)
+            .select(SysUser::getEmail, SysUser::getStatus)
             .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId)
             .eq(SysUser::getEmail, email));
         if (ObjectUtil.isNull(user)) {
@@ -414,25 +414,24 @@ public class SysLoginService {
         String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username;
         String loginFail = Constants.LOGIN_FAIL;
 
-        // 获取用户登录错误次数(可自定义限制策略 例如: key + username + ip)
-        Integer errorNumber = RedisUtils.getCacheObject(errorKey);
+        // 获取用户登录错误次数,默认为0 (可自定义限制策略 例如: key + username + ip)
+        int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0);
         // 锁定时间内登录 则踢出
-        if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(maxRetryCount)) {
+        if (errorNumber >= maxRetryCount) {
             recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
             throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
         }
 
         if (supplier.get()) {
-            // 是否第一次
-            errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1;
+            // 错误次数递增
+            errorNumber++;
+            RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
             // 达到规定错误次数 则锁定登录
-            if (errorNumber.equals(maxRetryCount)) {
-                RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
+            if (errorNumber >= maxRetryCount) {
                 recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
                 throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
             } else {
-                // 未达到规定错误次数 则递增
-                RedisUtils.setCacheObject(errorKey, errorNumber);
+                // 未达到规定错误次数
                 recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber));
                 throw new UserException(loginType.getRetryLimitCount(), errorNumber);
             }

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

@@ -158,162 +158,29 @@ mail:
   # Socket连接超时值,单位毫秒,缺省值不超时
   connectionTimeout: 0
 
---- # sms 短信
+--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
+# https://wind.kim/doc/start 文档地址 各个厂商可同时使用
 sms:
-  enabled: false
   # 阿里云 dysmsapi.aliyuncs.com
-  # 腾讯云 sms.tencentcloudapi.com
-  endpoint: "dysmsapi.aliyuncs.com"
-  accessKeyId: xxxxxxx
-  accessKeySecret: xxxxxx
-  signName: 测试
-  # 腾讯专用
-  sdkAppId:
-
-justauth:
-  enabled: true
-  type:
-    QQ:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/qq/callback
-      union-id: false
-    WEIBO:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/weibo/callback
-    gitee:
-      client-id: 38eaaa1b77b5e064313057a2f5745ce3a9f3e7686d9bd302c7df2f308ef6db81
-      client-secret: 2e633af8780cb9fe002c4c7291b722db944402e271efb99b062811f52d7da1ff
-      redirect-uri: http://localhost:8888/social-login?source=gitee
-    DINGTALK:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/dingtalk/callback
-    BAIDU:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/baidu/callback
-    CSDN:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/csdn/callback
-    CODING:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/coding/callback
-      coding-group-name: xx
-    OSCHINA:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/oschina/callback
-    ALIPAY:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/alipay/callback
-      alipay-public-key: MIIB**************DAQAB
-    WECHAT_OPEN:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_open/callback
-    WECHAT_MP:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_mp/callback
-    WECHAT_ENTERPRISE:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_enterprise/callback
-      agent-id: 1000002
-    TAOBAO:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/taobao/callback
-    GOOGLE:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/google/callback
-    FACEBOOK:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/facebook/callback
-    DOUYIN:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/douyin/callback
-    LINKEDIN:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/linkedin/callback
-    MICROSOFT:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/microsoft/callback
-    MI:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/mi/callback
-    TOUTIAO:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/toutiao/callback
-    TEAMBITION:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/teambition/callback
-    RENREN:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/renren/callback
-    PINTEREST:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/pinterest/callback
-    STACK_OVERFLOW:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/stack_overflow/callback
-      stack-overflow-key: asd*********asd
-    HUAWEI:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/huawei/callback
-    KUJIALE:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/kujiale/callback
-    GITLAB:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/gitlab/callback
-    MEITUAN:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/meituan/callback
-    ELEME:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/eleme/callback
-    TWITTER:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/twitter/callback
-    XMLY:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/xmly/callback
-      # 设备唯一标识ID
-      device-id: xxxxxxxxxxxxxx
-      # 客户端操作系统类型,1-iOS系统,2-Android系统,3-Web
-      client-os-type: 3
-      # 客户端包名,如果 clientOsType 为1或2时必填。对Android客户端是包名,对IOS客户端是Bundle ID
-      #pack-id: xxxx
-    FEISHU:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/feishu/callback
-    JD:
-      client-id: 10**********6
-      client-secret: 1f7d08**********5b7**********29e
-      redirect-uri: http://oauth.xkcoding.com/demo/oauth/jd/callback
-
+  alibaba:
+    #请求地址 默认为 dysmsapi.aliyuncs.com 如无特殊改变可以不用设置
+    requestUrl: dysmsapi.aliyuncs.com
+    #阿里云的accessKey
+    accessKeyId: xxxxxxx
+    #阿里云的accessKeySecret
+    accessKeySecret: xxxxxxx
+    #短信签名
+    signature: 测试
+  tencent:
+    #请求地址默认为 sms.tencentcloudapi.com 如无特殊改变可不用设置
+    requestUrl: sms.tencentcloudapi.com
+    #腾讯云的accessKey
+    accessKeyId: xxxxxxx
+    #腾讯云的accessKeySecret
+    accessKeySecret: xxxxxxx
+    #短信签名
+    signature: 测试
+    #短信sdkAppId
+    sdkAppId: appid
+    #地域信息默认为 ap-guangzhou 如无特殊改变可不用设置
+    territory: ap-guangzhou

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

@@ -161,14 +161,29 @@ mail:
   # Socket连接超时值,单位毫秒,缺省值不超时
   connectionTimeout: 0
 
---- # sms 短信
+--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
+# https://wind.kim/doc/start 文档地址 各个厂商可同时使用
 sms:
-  enabled: false
   # 阿里云 dysmsapi.aliyuncs.com
-  # 腾讯云 sms.tencentcloudapi.com
-  endpoint: "dysmsapi.aliyuncs.com"
-  accessKeyId: xxxxxxx
-  accessKeySecret: xxxxxx
-  signName: 测试
-  # 腾讯专用
-  sdkAppId:
+  alibaba:
+    #请求地址 默认为 dysmsapi.aliyuncs.com 如无特殊改变可以不用设置
+    requestUrl: dysmsapi.aliyuncs.com
+    #阿里云的accessKey
+    accessKeyId: xxxxxxx
+    #阿里云的accessKeySecret
+    accessKeySecret: xxxxxxx
+    #短信签名
+    signature: 测试
+  tencent:
+    #请求地址默认为 sms.tencentcloudapi.com 如无特殊改变可不用设置
+    requestUrl: sms.tencentcloudapi.com
+    #腾讯云的accessKey
+    accessKeyId: xxxxxxx
+    #腾讯云的accessKeySecret
+    accessKeySecret: xxxxxxx
+    #短信签名
+    signature: 测试
+    #短信sdkAppId
+    sdkAppId: appid
+    #地域信息默认为 ap-guangzhou 如无特殊改变可不用设置
+    territory: ap-guangzhou

+ 11 - 47
ruoyi-admin/src/main/resources/application.yml

@@ -96,20 +96,14 @@ spring:
 sa-token:
   # token名称 (同时也是cookie名称)
   token-name: Authorization
-  # token有效期 设为一天 (必定过期) 单位: 秒
-  timeout: 86400
-  # token临时有效期 (指定时间无操作就过期) 单位: 秒
+  # token固定超时 设为七天 (必定过期) 单位: 秒
+  timeout: 604800
+  # token活跃超时时间 30分钟(指定时间无操作则过期) 单位: 秒
   activity-timeout: 1800
   # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
   is-concurrent: true
   # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
   is-share: false
-  # 是否尝试从header里读取token
-  is-read-header: true
-  # 是否尝试从cookie里读取token
-  is-read-cookie: false
-  # token前缀
-  token-prefix: "Bearer"
   # jwt秘钥
   jwt-secret-key: abcdefghijklmnopqrstuvwxyz
 
@@ -156,39 +150,12 @@ mybatis-plus:
   mapperLocations: classpath*:mapper/**/*Mapper.xml
   # 实体扫描,多个package用逗号或者分号分隔
   typeAliasesPackage: org.dromara.**.domain
-  # 启动时是否检查 MyBatis XML 文件的存在,默认不检查
-  checkConfigLocation: false
-  configuration:
-    # 自动驼峰命名规则(camel case)映射
-    mapUnderscoreToCamelCase: true
-    # MyBatis 自动映射策略
-    # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射
-    autoMappingBehavior: FULL
-    # MyBatis 自动映射时未知列或未知属性处理策
-    # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
-    autoMappingUnknownColumnBehavior: NONE
-    # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl
-    # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl
-    # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
-    logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
   global-config:
-    # 是否打印 Logo banner
-    banner: true
     dbConfig:
       # 主键类型
       # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
+      # 如需改为自增 需要将数据库表全部设置为自增
       idType: ASSIGN_ID
-      # 逻辑已删除值
-      logicDeleteValue: 2
-      # 逻辑未删除值
-      logicNotDeleteValue: 0
-      # 字段验证策略之 insert,在 insert 的时候的字段验证策略
-      # IGNORED 忽略 NOT_NULL 非NULL NOT_EMPTY 非空 DEFAULT 默认 NEVER 不加入 SQL
-      insertStrategy: NOT_NULL
-      # 字段验证策略之 update,在 update 的时候的字段验证策略
-      updateStrategy: NOT_NULL
-      # 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件
-      where-strategy: NOT_NULL
 
 # 数据加密
 mybatis-encryptor:
@@ -204,8 +171,13 @@ mybatis-encryptor:
   publicKey:
   privateKey:
 
-# Swagger配置
-swagger:
+springdoc:
+  api-docs:
+    # 是否开启接口文档
+    enabled: true
+  swagger-ui:
+    # 持久化认证数据
+    persistAuthorization: true
   info:
     # 标题
     title: '标题:${ruoyi.name}多租户管理系统_接口文档'
@@ -225,14 +197,6 @@ swagger:
         type: APIKEY
         in: HEADER
         name: ${sa-token.token-name}
-
-springdoc:
-  api-docs:
-    # 是否开启接口文档
-    enabled: true
-  swagger-ui:
-    # 持久化认证数据
-    persistAuthorization: true
   #这里定义了两个分组,可定义多个,也可以不定义
   group-configs:
     - group: 1.演示模块

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

@@ -34,6 +34,11 @@
             <artifactId>spring-boot-starter-validation</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
         <!--常用工具类 -->
         <dependency>
             <groupId>org.apache.commons</groupId>

+ 2 - 8
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java

@@ -2,16 +2,14 @@ package org.dromara.common.core.config;
 
 import cn.hutool.core.util.ArrayUtil;
 import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.SpringUtils;
 import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
 import org.springframework.scheduling.annotation.AsyncConfigurer;
 import org.springframework.scheduling.annotation.EnableAsync;
 
 import java.util.Arrays;
 import java.util.concurrent.Executor;
-import java.util.concurrent.ScheduledExecutorService;
 
 /**
  * 异步配置
@@ -22,16 +20,12 @@ import java.util.concurrent.ScheduledExecutorService;
 @AutoConfiguration
 public class AsyncConfig implements AsyncConfigurer {
 
-    @Autowired
-    @Qualifier("scheduledExecutorService")
-    private ScheduledExecutorService scheduledExecutorService;
-
     /**
      * 自定义 @Async 注解使用系统线程池
      */
     @Override
     public Executor getAsyncExecutor() {
-        return scheduledExecutorService;
+        return SpringUtils.getBean("scheduledExecutorService");
     }
 
     /**

+ 13 - 12
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java

@@ -22,18 +22,19 @@ public class ValidatorConfig {
      */
     @Bean
     public Validator validator(MessageSource messageSource) {
-        LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
-        // 国际化
-        factoryBean.setValidationMessageSource(messageSource);
-        // 设置使用 HibernateValidator 校验器
-        factoryBean.setProviderClass(HibernateValidator.class);
-        Properties properties = new Properties();
-        // 设置 快速异常返回
-        properties.setProperty("hibernate.validator.fail_fast", "true");
-        factoryBean.setValidationProperties(properties);
-        // 加载配置
-        factoryBean.afterPropertiesSet();
-        return factoryBean.getValidator();
+        try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) {
+            // 国际化
+            factoryBean.setValidationMessageSource(messageSource);
+            // 设置使用 HibernateValidator 校验器
+            factoryBean.setProviderClass(HibernateValidator.class);
+            Properties properties = new Properties();
+            // 设置 快速异常返回
+            properties.setProperty("hibernate.validator.fail_fast", "true");
+            factoryBean.setValidationProperties(properties);
+            // 加载配置
+            factoryBean.afterPropertiesSet();
+            return factoryBean.getValidator();
+        }
     }
 
 }

+ 31 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java

@@ -0,0 +1,31 @@
+package org.dromara.common.core.factory;
+
+import org.dromara.common.core.utils.StringUtils;
+import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
+import org.springframework.core.env.PropertiesPropertySource;
+import org.springframework.core.env.PropertySource;
+import org.springframework.core.io.support.DefaultPropertySourceFactory;
+import org.springframework.core.io.support.EncodedResource;
+
+import java.io.IOException;
+
+/**
+ * yml 配置源工厂
+ *
+ * @author Lion Li
+ */
+public class YmlPropertySourceFactory extends DefaultPropertySourceFactory {
+
+    @Override
+    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
+        String sourceName = resource.getResource().getFilename();
+        if (StringUtils.isNotBlank(sourceName) && StringUtils.endsWithAny(sourceName, ".yml", ".yaml")) {
+            YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
+            factory.setResources(resource.getResource());
+            factory.afterPropertiesSet();
+            return new PropertiesPropertySource(sourceName, factory.getObject());
+        }
+        return super.createPropertySource(name, resource);
+    }
+
+}

+ 6 - 1
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java

@@ -3,6 +3,7 @@ package org.dromara.common.core.utils;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.springframework.context.MessageSource;
+import org.springframework.context.NoSuchMessageException;
 import org.springframework.context.i18n.LocaleContextHolder;
 
 /**
@@ -23,6 +24,10 @@ public class MessageUtils {
      * @return 获取国际化翻译值
      */
     public static String message(String code, Object... args) {
-        return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale());
+        try {
+            return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale());
+        } catch (NoSuchMessageException e) {
+            return code;
+        }
     }
 }

+ 39 - 4
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java

@@ -10,6 +10,7 @@ import jakarta.servlet.http.HttpSession;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.springframework.http.MediaType;
+import org.springframework.util.LinkedCaseInsensitiveMap;
 import org.springframework.web.context.request.RequestAttributes;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
@@ -19,6 +20,7 @@ import java.net.URLDecoder;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 import java.util.Collections;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -101,14 +103,22 @@ public class ServletUtils extends JakartaServletUtil {
      * 获取request
      */
     public static HttpServletRequest getRequest() {
-        return getRequestAttributes().getRequest();
+        try {
+            return getRequestAttributes().getRequest();
+        } catch (Exception e) {
+            return null;
+        }
     }
 
     /**
      * 获取response
      */
     public static HttpServletResponse getResponse() {
-        return getRequestAttributes().getResponse();
+        try {
+            return getRequestAttributes().getResponse();
+        } catch (Exception e) {
+            return null;
+        }
     }
 
     /**
@@ -119,8 +129,33 @@ public class ServletUtils extends JakartaServletUtil {
     }
 
     public static ServletRequestAttributes getRequestAttributes() {
-        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
-        return (ServletRequestAttributes) attributes;
+        try {
+            RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
+            return (ServletRequestAttributes) attributes;
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static String getHeader(HttpServletRequest request, String name) {
+        String value = request.getHeader(name);
+        if (StringUtils.isEmpty(value)) {
+            return StringUtils.EMPTY;
+        }
+        return urlDecode(value);
+    }
+
+    public static Map<String, String> getHeaders(HttpServletRequest request) {
+        Map<String, String> map = new LinkedCaseInsensitiveMap<>();
+        Enumeration<String> enumeration = request.getHeaderNames();
+        if (enumeration != null) {
+            while (enumeration.hasMoreElements()) {
+                String key = enumeration.nextElement();
+                String value = request.getHeader(key);
+                map.put(key, value);
+            }
+        }
+        return map;
     }
 
     /**

+ 8 - 8
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SwaggerConfig.java → ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java

@@ -1,13 +1,13 @@
 package org.dromara.common.doc.config;
 
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.doc.config.properties.SwaggerProperties;
-import org.dromara.common.doc.handler.OpenApiHandler;
 import io.swagger.v3.oas.models.OpenAPI;
 import io.swagger.v3.oas.models.Paths;
 import io.swagger.v3.oas.models.info.Info;
 import io.swagger.v3.oas.models.security.SecurityRequirement;
 import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.doc.config.properties.SpringDocProperties;
+import org.dromara.common.doc.handler.OpenApiHandler;
 import org.springdoc.core.configuration.SpringDocConfiguration;
 import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
 import org.springdoc.core.customizers.OpenApiCustomizer;
@@ -36,18 +36,18 @@ import java.util.Set;
  */
 @RequiredArgsConstructor
 @AutoConfiguration(before = SpringDocConfiguration.class)
-@EnableConfigurationProperties(SwaggerProperties.class)
+@EnableConfigurationProperties(SpringDocProperties.class)
 @ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true)
-public class SwaggerConfig {
+public class SpringDocConfig {
 
     private final ServerProperties serverProperties;
 
     @Bean
     @ConditionalOnMissingBean(OpenAPI.class)
-    public OpenAPI openApi(SwaggerProperties swaggerProperties) {
+    public OpenAPI openApi(SpringDocProperties swaggerProperties) {
         OpenAPI openApi = new OpenAPI();
         // 文档基本信息
-        SwaggerProperties.InfoProperties infoProperties = swaggerProperties.getInfo();
+        SpringDocProperties.InfoProperties infoProperties = swaggerProperties.getInfo();
         Info info = convertInfo(infoProperties);
         openApi.info(info);
         // 扩展文档信息
@@ -65,7 +65,7 @@ public class SwaggerConfig {
         return openApi;
     }
 
-    private Info convertInfo(SwaggerProperties.InfoProperties infoProperties) {
+    private Info convertInfo(SpringDocProperties.InfoProperties infoProperties) {
         Info info = new Info();
         info.setTitle(infoProperties.getTitle());
         info.setDescription(infoProperties.getDescription());

+ 2 - 2
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SwaggerProperties.java → ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java

@@ -18,8 +18,8 @@ import java.util.List;
  * @author Lion Li
  */
 @Data
-@ConfigurationProperties(prefix = "swagger")
-public class SwaggerProperties {
+@ConfigurationProperties(prefix = "springdoc")
+public class SpringDocProperties {
 
     /**
      * 文档基本信息

+ 1 - 1
ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -1 +1 @@
-org.dromara.common.doc.config.SwaggerConfig
+org.dromara.common.doc.config.SpringDocConfig

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

@@ -7,11 +7,13 @@ import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.dromara.common.core.factory.YmlPropertySourceFactory;
 import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler;
 import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
 import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.PropertySource;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
 
 /**
@@ -22,6 +24,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 @EnableTransactionManagement(proxyTargetClass = true)
 @AutoConfiguration
 @MapperScan("${mybatis-plus.mapperPackage}")
+@PropertySource(value = "classpath:common-mybatis.yml", factory = YmlPropertySourceFactory.class)
 public class MybatisPlusConfig {
 
     @Bean

+ 33 - 0
ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml

@@ -0,0 +1,33 @@
+# 内置配置 不允许修改 如需修改请在 nacos 上写相同配置覆盖
+# MyBatisPlus配置
+# https://baomidou.com/config/
+mybatis-plus:
+  # 启动时是否检查 MyBatis XML 文件的存在,默认不检查
+  checkConfigLocation: false
+  configuration:
+    # 自动驼峰命名规则(camel case)映射
+    mapUnderscoreToCamelCase: true
+    # MyBatis 自动映射策略
+    # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射
+    autoMappingBehavior: FULL
+    # MyBatis 自动映射时未知列或未知属性处理策
+    # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
+    autoMappingUnknownColumnBehavior: NONE
+    # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl
+    # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl
+    # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
+    logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
+  global-config:
+    # 是否打印 Logo banner
+    banner: true
+    dbConfig:
+      # 主键类型
+      # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
+      idType: ASSIGN_ID
+      # 逻辑已删除值(框架表均使用此值 禁止随意修改)
+      logicDeleteValue: 2
+      # 逻辑未删除值
+      logicNotDeleteValue: 0
+      insertStrategy: NOT_NULL
+      updateStrategy: NOT_NULL
+      whereStrategy: NOT_NULL

+ 3 - 0
ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java

@@ -4,10 +4,12 @@ import cn.dev33.satoken.dao.SaTokenDao;
 import cn.dev33.satoken.jwt.StpLogicJwtForSimple;
 import cn.dev33.satoken.stp.StpInterface;
 import cn.dev33.satoken.stp.StpLogic;
+import org.dromara.common.core.factory.YmlPropertySourceFactory;
 import org.dromara.common.satoken.core.dao.PlusSaTokenDao;
 import org.dromara.common.satoken.core.service.SaPermissionImpl;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
 import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.PropertySource;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
 /**
@@ -16,6 +18,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  * @author Lion Li
  */
 @AutoConfiguration
+@PropertySource(value = "classpath:common-satoken.yml", factory = YmlPropertySourceFactory.class)
 public class SaTokenConfig implements WebMvcConfigurer {
 
     @Bean

+ 11 - 0
ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml

@@ -0,0 +1,11 @@
+# 内置配置 不允许修改 如需修改请在 nacos 上写相同配置覆盖
+# Sa-Token配置
+sa-token:
+  # 允许从 请求参数 读取 token
+  is-read-body: true
+  # 允许从 header 读取 token
+  is-read-header: true
+  # 关闭 cookie 鉴权 从根源杜绝 csrf 漏洞风险
+  is-read-cookie: false
+  # token前缀
+  token-prefix: "Bearer"

+ 9 - 12
ruoyi-common/ruoyi-common-sms/pom.xml

@@ -16,22 +16,19 @@
     </description>
 
     <dependencies>
-        <dependency>
-            <groupId>org.dromara</groupId>
-            <artifactId>ruoyi-common-json</artifactId>
-        </dependency>
 
         <dependency>
-            <groupId>com.aliyun</groupId>
-            <artifactId>dysmsapi20170525</artifactId>
-            <optional>true</optional>
+            <groupId>org.dromara.sms4j</groupId>
+            <artifactId>sms4j-spring-boot-starter</artifactId>
+            <exclusions>
+                <!-- 排除京东短信内存在的fastjson等待作者后续修复 -->
+                <exclusion>
+                    <groupId>com.alibaba</groupId>
+                    <artifactId>fastjson</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
 
-        <dependency>
-            <groupId>com.tencentcloudapi</groupId>
-            <artifactId>tencentcloud-sdk-java-sms</artifactId>
-            <optional>true</optional>
-        </dependency>
     </dependencies>
 
 </project>

+ 1 - 34
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsConfig.java

@@ -1,15 +1,6 @@
 package org.dromara.common.sms.config;
 
-import org.dromara.common.sms.config.properties.SmsProperties;
-import org.dromara.common.sms.core.AliyunSmsTemplate;
-import org.dromara.common.sms.core.SmsTemplate;
-import org.dromara.common.sms.core.TencentSmsTemplate;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
 
 /**
  * 短信配置类
@@ -18,31 +9,7 @@ import org.springframework.context.annotation.Configuration;
  * @version 4.2.0
  */
 @AutoConfiguration
-@EnableConfigurationProperties(SmsProperties.class)
+//@EnableConfigurationProperties(SmsProperties.class)
 public class SmsConfig {
 
-    @Configuration
-    @ConditionalOnProperty(value = "sms.enabled", havingValue = "true")
-    @ConditionalOnClass(com.aliyun.dysmsapi20170525.Client.class)
-    static class AliyunSmsConfig {
-
-        @Bean
-        public SmsTemplate aliyunSmsTemplate(SmsProperties smsProperties) {
-            return new AliyunSmsTemplate(smsProperties);
-        }
-
-    }
-
-    @Configuration
-    @ConditionalOnProperty(value = "sms.enabled", havingValue = "true")
-    @ConditionalOnClass(com.tencentcloudapi.sms.v20190711.SmsClient.class)
-    static class TencentSmsConfig {
-
-        @Bean
-        public SmsTemplate tencentSmsTemplate(SmsProperties smsProperties) {
-            return new TencentSmsTemplate(smsProperties);
-        }
-
-    }
-
 }

+ 19 - 45
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/properties/SmsProperties.java

@@ -1,45 +1,19 @@
-package org.dromara.common.sms.config.properties;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
-/**
- * SMS短信 配置属性
- *
- * @author Lion Li
- * @version 4.2.0
- */
-@Data
-@ConfigurationProperties(prefix = "sms")
-public class SmsProperties {
-
-    private Boolean enabled;
-
-    /**
-     * 配置节点
-     * 阿里云 dysmsapi.aliyuncs.com
-     * 腾讯云 sms.tencentcloudapi.com
-     */
-    private String endpoint;
-
-    /**
-     * key
-     */
-    private String accessKeyId;
-
-    /**
-     * 密匙
-     */
-    private String accessKeySecret;
-
-    /*
-     * 短信签名
-     */
-    private String signName;
-
-    /**
-     * 短信应用ID (腾讯专属)
-     */
-    private String sdkAppId;
-
-}
+//package org.dromara.common.sms.config.properties;
+//
+//import lombok.Data;
+//import org.springframework.boot.context.properties.ConfigurationProperties;
+//
+///**
+// * SMS短信 配置属性
+// *
+// * @author Lion Li
+// * @version 4.2.0
+// */
+//@Data
+//@ConfigurationProperties(prefix = "sms")
+//public class SmsProperties {
+//
+//    private Boolean enabled;
+//
+//
+//}

+ 0 - 66
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/AliyunSmsTemplate.java

@@ -1,66 +0,0 @@
-package org.dromara.common.sms.core;
-
-import com.aliyun.dysmsapi20170525.Client;
-import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
-import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
-import com.aliyun.teaopenapi.models.Config;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.json.utils.JsonUtils;
-import org.dromara.common.sms.config.properties.SmsProperties;
-import org.dromara.common.sms.entity.SmsResult;
-import org.dromara.common.sms.exception.SmsException;
-import lombok.SneakyThrows;
-
-import java.util.Map;
-
-/**
- * Aliyun 短信模板
- *
- * @author Lion Li
- * @version 4.2.0
- */
-public class AliyunSmsTemplate implements SmsTemplate {
-
-    private SmsProperties properties;
-
-    private Client client;
-
-    @SneakyThrows(Exception.class)
-    public AliyunSmsTemplate(SmsProperties smsProperties) {
-        this.properties = smsProperties;
-        Config config = new Config()
-            // 您的AccessKey ID
-            .setAccessKeyId(smsProperties.getAccessKeyId())
-            // 您的AccessKey Secret
-            .setAccessKeySecret(smsProperties.getAccessKeySecret())
-            // 访问的域名
-            .setEndpoint(smsProperties.getEndpoint());
-        this.client = new Client(config);
-    }
-
-    @Override
-    public SmsResult send(String phones, String templateId, Map<String, String> param) {
-        if (StringUtils.isBlank(phones)) {
-            throw new SmsException("手机号不能为空");
-        }
-        if (StringUtils.isBlank(templateId)) {
-            throw new SmsException("模板ID不能为空");
-        }
-        SendSmsRequest req = new SendSmsRequest()
-            .setPhoneNumbers(phones)
-            .setSignName(properties.getSignName())
-            .setTemplateCode(templateId)
-            .setTemplateParam(JsonUtils.toJsonString(param));
-        try {
-            SendSmsResponse resp = client.sendSms(req);
-            return SmsResult.builder()
-                .isSuccess("OK".equals(resp.getBody().getCode()))
-                .message(resp.getBody().getMessage())
-                .response(JsonUtils.toJsonString(resp))
-                .build();
-        } catch (Exception e) {
-            throw new SmsException(e.getMessage());
-        }
-    }
-
-}

+ 0 - 26
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/SmsTemplate.java

@@ -1,26 +0,0 @@
-package org.dromara.common.sms.core;
-
-import org.dromara.common.sms.entity.SmsResult;
-
-import java.util.Map;
-
-/**
- * 短信模板
- *
- * @author Lion Li
- * @version 4.2.0
- */
-public interface SmsTemplate {
-
-    /**
-     * 发送短信
-     *
-     * @param phones     电话号(多个逗号分割)
-     * @param templateId 模板id
-     * @param param      模板对应参数
-     *                   阿里 需使用 模板变量名称对应内容 例如: code=1234
-     *                   腾讯 需使用 模板变量顺序对应内容 例如: 1=1234, 1为模板内第一个参数
-     */
-    SmsResult send(String phones, String templateId, Map<String, String> param);
-
-}

+ 0 - 82
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/TencentSmsTemplate.java

@@ -1,82 +0,0 @@
-package org.dromara.common.sms.core;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ArrayUtil;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.json.utils.JsonUtils;
-import org.dromara.common.sms.config.properties.SmsProperties;
-import org.dromara.common.sms.entity.SmsResult;
-import org.dromara.common.sms.exception.SmsException;
-import com.tencentcloudapi.common.Credential;
-import com.tencentcloudapi.common.profile.ClientProfile;
-import com.tencentcloudapi.common.profile.HttpProfile;
-import com.tencentcloudapi.sms.v20190711.SmsClient;
-import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest;
-import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse;
-import com.tencentcloudapi.sms.v20190711.models.SendStatus;
-import lombok.SneakyThrows;
-
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Tencent 短信模板
- *
- * @author Lion Li
- * @version 4.2.0
- */
-public class TencentSmsTemplate implements SmsTemplate {
-
-    private SmsProperties properties;
-
-    private SmsClient client;
-
-    @SneakyThrows(Exception.class)
-    public TencentSmsTemplate(SmsProperties smsProperties) {
-        this.properties = smsProperties;
-        Credential credential = new Credential(smsProperties.getAccessKeyId(), smsProperties.getAccessKeySecret());
-        HttpProfile httpProfile = new HttpProfile();
-        httpProfile.setEndpoint(smsProperties.getEndpoint());
-        ClientProfile clientProfile = new ClientProfile();
-        clientProfile.setHttpProfile(httpProfile);
-        this.client = new SmsClient(credential, "", clientProfile);
-    }
-
-    @Override
-    public SmsResult send(String phones, String templateId, Map<String, String> param) {
-        if (StringUtils.isBlank(phones)) {
-            throw new SmsException("手机号不能为空");
-        }
-        if (StringUtils.isBlank(templateId)) {
-            throw new SmsException("模板ID不能为空");
-        }
-        SendSmsRequest req = new SendSmsRequest();
-        Set<String> set = Arrays.stream(phones.split(StringUtils.SEPARATOR)).map(p -> "+86" + p).collect(Collectors.toSet());
-        req.setPhoneNumberSet(ArrayUtil.toArray(set, String.class));
-        if (CollUtil.isNotEmpty(param)) {
-            req.setTemplateParamSet(ArrayUtil.toArray(param.values(), String.class));
-        }
-        req.setTemplateID(templateId);
-        req.setSign(properties.getSignName());
-        req.setSmsSdkAppid(properties.getSdkAppId());
-        try {
-            SendSmsResponse resp = client.SendSms(req);
-            SmsResult.SmsResultBuilder builder = SmsResult.builder()
-                .isSuccess(true)
-                .message("send success")
-                .response(JsonUtils.toJsonString(resp));
-            for (SendStatus sendStatus : resp.getSendStatusSet()) {
-                if (!"Ok".equals(sendStatus.getCode())) {
-                    builder.isSuccess(false).message(sendStatus.getMessage());
-                    break;
-                }
-            }
-            return builder.build();
-        } catch (Exception e) {
-            throw new SmsException(e.getMessage());
-        }
-    }
-
-}

+ 0 - 31
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/entity/SmsResult.java

@@ -1,31 +0,0 @@
-package org.dromara.common.sms.entity;
-
-import lombok.Builder;
-import lombok.Data;
-
-/**
- * 上传返回体
- *
- * @author Lion Li
- */
-@Data
-@Builder
-public class SmsResult {
-
-    /**
-     * 是否成功
-     */
-    private boolean isSuccess;
-
-    /**
-     * 响应消息
-     */
-    private String message;
-
-    /**
-     * 实际响应体
-     * <p>
-     * 可自行转换为 SDK 对应的 SendSmsResponse
-     */
-    private String response;
-}

+ 0 - 19
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/exception/SmsException.java

@@ -1,19 +0,0 @@
-package org.dromara.common.sms.exception;
-
-import java.io.Serial;
-
-/**
- * Sms异常类
- *
- * @author Lion Li
- */
-public class SmsException extends RuntimeException {
-
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    public SmsException(String msg) {
-        super(msg);
-    }
-
-}

+ 0 - 10
ruoyi-modules/ruoyi-demo/pom.xml

@@ -97,16 +97,6 @@
             <groupId>org.dromara</groupId>
             <artifactId>ruoyi-common-websocket</artifactId>
         </dependency>
-        <!-- 短信 用哪个导入哪个依赖 -->
-<!--        <dependency>-->
-<!--            <groupId>com.aliyun</groupId>-->
-<!--            <artifactId>dysmsapi20170525</artifactId>-->
-<!--        </dependency>-->
-
-<!--        <dependency>-->
-<!--            <groupId>com.tencentcloudapi</groupId>-->
-<!--            <artifactId>tencentcloud-sdk-java-sms</artifactId>-->
-<!--        </dependency>-->
 
     </dependencies>
 

+ 14 - 30
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java

@@ -1,17 +1,17 @@
 package org.dromara.demo.controller;
 
-import org.dromara.common.core.domain.R;
-import org.dromara.common.core.utils.SpringUtils;
-import org.dromara.common.sms.config.properties.SmsProperties;
-import org.dromara.common.sms.core.SmsTemplate;
 import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.sms4j.api.SmsBlend;
+import org.dromara.sms4j.api.entity.SmsResponse;
+import org.dromara.sms4j.core.factory.SmsFactory;
+import org.dromara.sms4j.provider.enumerate.SupplierType;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.util.HashMap;
-import java.util.Map;
+import java.util.LinkedHashMap;
 
 /**
  * 短信演示案例
@@ -26,10 +26,6 @@ import java.util.Map;
 @RequestMapping("/demo/sms")
 public class SmsController {
 
-    private final SmsProperties smsProperties;
-//    private final SmsTemplate smsTemplate; // 可以使用spring注入
-//    private final AliyunSmsTemplate smsTemplate; // 也可以注入某个厂家的模板工具
-
     /**
      * 发送短信Aliyun
      *
@@ -38,17 +34,11 @@ public class SmsController {
      */
     @GetMapping("/sendAliyun")
     public R<Object> sendAliyun(String phones, String templateId) {
-        if (!smsProperties.getEnabled()) {
-            return R.fail("当前系统没有开启短信功能!");
-        }
-        if (!SpringUtils.containsBean("aliyunSmsTemplate")) {
-            return R.fail("阿里云依赖未引入!");
-        }
-        SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class);
-        Map<String, String> map = new HashMap<>(1);
+        LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
         map.put("code", "1234");
-        Object send = smsTemplate.send(phones, templateId, map);
-        return R.ok(send);
+        SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
+        SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map);
+        return R.ok(smsResponse);
     }
 
     /**
@@ -59,18 +49,12 @@ public class SmsController {
      */
     @GetMapping("/sendTencent")
     public R<Object> sendTencent(String phones, String templateId) {
-        if (!smsProperties.getEnabled()) {
-            return R.fail("当前系统没有开启短信功能!");
-        }
-        if (!SpringUtils.containsBean("tencentSmsTemplate")) {
-            return R.fail("腾讯云依赖未引入!");
-        }
-        SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class);
-        Map<String, String> map = new HashMap<>(1);
+        LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
 //        map.put("2", "测试测试");
         map.put("1", "1234");
-        Object send = smsTemplate.send(phones, templateId, map);
-        return R.ok(send);
+        SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.TENCENT);
+        SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map);
+        return R.ok(smsResponse);
     }
 
 }

+ 2 - 1
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java

@@ -2,6 +2,7 @@ package org.dromara.generator.mapper;
 
 import com.baomidou.dynamic.datasource.annotation.DS;
 import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import org.apache.ibatis.annotations.Param;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 import org.dromara.generator.domain.GenTableColumn;
 
@@ -22,6 +23,6 @@ public interface GenTableColumnMapper extends BaseMapperPlus<GenTableColumn, Gen
      * @return 列信息
      */
     @DS("#dataName")
-    List<GenTableColumn> selectDbTableColumnsByName(String tableName, String dataName);
+    List<GenTableColumn> selectDbTableColumnsByName(@Param("tableName") String tableName, String dataName);
 
 }

+ 3 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java

@@ -4,6 +4,7 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.dev33.satoken.annotation.SaCheckRole;
 import com.baomidou.lock.annotation.Lock4j;
 import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.Min;
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
@@ -174,7 +175,8 @@ public class SysTenantController extends BaseController {
     @SaCheckPermission("system:tenant:edit")
     @Log(title = "租户", businessType = BusinessType.UPDATE)
     @GetMapping("/syncTenantPackage")
-    public R<Void> syncTenantPackage(@NotBlank(message = "租户ID不能为空") String tenantId, @NotBlank(message = "套餐ID不能为空") Long packageId) {
+    public R<Void> syncTenantPackage(@NotBlank(message = "租户ID不能为空") String tenantId,
+                                     @NotNull(message = "套餐ID不能为空") Long packageId) {
         return toAjax(TenantHelper.ignore(() -> tenantService.syncTenantPackage(tenantId, packageId)));
     }
 

+ 4 - 3
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java

@@ -94,7 +94,7 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
      * @return 用户对象信息
      */
     @InterceptorIgnore(tenantLine = "true")
-    SysUserVo selectTenantUserByUserName(String userName, String tenantId);
+    SysUserVo selectTenantUserByUserName(@Param("userName") String userName, @Param("tenantId") String tenantId);
 
     /**
      * 通过手机号查询用户(不走租户插件)
@@ -104,7 +104,7 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
      * @return 用户对象信息
      */
     @InterceptorIgnore(tenantLine = "true")
-    SysUserVo selectTenantUserByPhonenumber(String phonenumber, String tenantId);
+    SysUserVo selectTenantUserByPhonenumber(@Param("phonenumber") String phonenumber, @Param("tenantId") String tenantId);
 
     /**
      * 通过邮箱查询用户(不走租户插件)
@@ -114,7 +114,8 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
      * @return 用户对象信息
      */
     @InterceptorIgnore(tenantLine = "true")
-    SysUserVo selectTenantUserByEmail(String email, String tenantId);
+    SysUserVo selectTenantUserByEmail(@Param("email") String email, @Param("tenantId") String tenantId);
+
 
     /**
      * 通过用户ID查询用户

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

@@ -22,7 +22,7 @@ public class SysSensitiveServiceImpl implements SensitiveService {
     @Override
     public boolean isSensitive() {
         if (TenantHelper.isEnable()) {
-            return !LoginHelper.isSuperAdmin() || !LoginHelper.isTenantAdmin();
+            return !LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin();
         }
         return !LoginHelper.isSuperAdmin();
     }