diff --git a/README.md b/README.md index eb82295ad..6696573c4 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ | 分布式任务调度 | 采用 Xxl-Job 天生支持分布式 统一的管理中心 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造 | | 文件存储 | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储
支持权限管理 安全可靠 文件可加密存储 | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应 | | 云存储 | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家 | 不支持 | -| 短信 | 支持 阿里、腾讯 只需在yml配置好厂家密钥即可使用 接口化支持扩展其他厂家 | 不支持 | +| 短信 | 采用 sms4j 短信融合包 支持数十种短信厂家 只需在yml配置好厂家密钥即可使用 可多厂家共用 | 不支持 | | 邮件 | 采用 mail-api 通用协议支持大部分邮件厂商 | 不支持 | | 接口文档 | 采用 SpringDoc、javadoc 无注解零入侵基于java注释
只需把注释写好 无需再写一大堆的文档注解了 | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成 | | 校验框架 | 采用 Validation 支持注解与工具类校验 注解支持国际化 | 仅支持注解 且注解不支持国际化 | diff --git a/pom.xml b/pom.xml index e69ab1532..dfcfa75e5 100644 --- a/pom.xml +++ b/pom.xml @@ -49,8 +49,7 @@ 1.12.400 - 2.0.23 - 3.1.687 + 2.1.1 3.2.2 @@ -242,17 +241,11 @@ aws-java-sdk-s3 ${aws-java-sdk-s3.version} - + - com.aliyun - dysmsapi20170525 - ${aliyun.sms.version} - - - - com.tencentcloudapi - tencentcloud-sdk-java-sms - ${tencent.sms.version} + org.dromara.sms4j + sms4j-spring-boot-starter + ${sms4j.version} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java index dd9fa196e..70d79ca4f 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java +++ b/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 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 map = new HashMap<>(1); + LinkedHashMap 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(); } diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java index 84c554d14..479c390f3 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java +++ b/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() - .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); } diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 78cad6ed1..5adc8aed8 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/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 diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml index e760823ad..4b29d1cec 100644 --- a/ruoyi-admin/src/main/resources/application-prod.yml +++ b/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 diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 31d0de5ff..b68a3dcd9 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/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.演示模块 diff --git a/ruoyi-common/ruoyi-common-core/pom.xml b/ruoyi-common/ruoyi-common-core/pom.xml index 8f3740fd9..33f9f7fc4 100644 --- a/ruoyi-common/ruoyi-common-core/pom.xml +++ b/ruoyi-common/ruoyi-common-core/pom.xml @@ -34,6 +34,11 @@ spring-boot-starter-validation + + org.springframework.boot + spring-boot-starter-aop + + org.apache.commons diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java index de9a9bcaa..9a32afe55 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java +++ b/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"); } /** diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java index 00825c2fd..45c5bd13c 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java +++ b/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(); + } } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java new file mode 100644 index 000000000..af61b90ca --- /dev/null +++ b/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); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java index 6f3729b98..48dfc08d7 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java +++ b/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; + } } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java index 91e2990bd..a1316eb85 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java +++ b/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 getHeaders(HttpServletRequest request) { + Map map = new LinkedCaseInsensitiveMap<>(); + Enumeration enumeration = request.getHeaderNames(); + if (enumeration != null) { + while (enumeration.hasMoreElements()) { + String key = enumeration.nextElement(); + String value = request.getHeader(key); + map.put(key, value); + } + } + return map; } /** diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SwaggerConfig.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java similarity index 92% rename from ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SwaggerConfig.java rename to ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java index 459941c97..4e3238007 100644 --- a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SwaggerConfig.java +++ b/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()); diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SwaggerProperties.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java similarity index 95% rename from ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SwaggerProperties.java rename to ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java index 9e08e7398..eae3b4c62 100644 --- a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SwaggerProperties.java +++ b/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 { /** * 文档基本信息 diff --git a/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index e64b2eb3f..fe11e76e7 100644 --- a/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/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 diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java index 1fe7834fe..c07a2bb3b 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java +++ b/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 diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml b/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml new file mode 100644 index 000000000..f5dc63758 --- /dev/null +++ b/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 diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java index 54ae2da2b..aef8a66ae 100644 --- a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java +++ b/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 diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml b/ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml new file mode 100644 index 000000000..c631641e4 --- /dev/null +++ b/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" diff --git a/ruoyi-common/ruoyi-common-sms/pom.xml b/ruoyi-common/ruoyi-common-sms/pom.xml index b06c5caff..c50f222ac 100644 --- a/ruoyi-common/ruoyi-common-sms/pom.xml +++ b/ruoyi-common/ruoyi-common-sms/pom.xml @@ -16,22 +16,19 @@ - - org.dromara - ruoyi-common-json - - com.aliyun - dysmsapi20170525 - true + org.dromara.sms4j + sms4j-spring-boot-starter + + + + com.alibaba + fastjson + + - - com.tencentcloudapi - tencentcloud-sdk-java-sms - true - diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsConfig.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsConfig.java index 86881f1d8..6b5a84442 100644 --- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsConfig.java +++ b/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); - } - - } - } diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/properties/SmsProperties.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/properties/SmsProperties.java index da6d9400e..c7b3ef1a5 100644 --- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/properties/SmsProperties.java +++ b/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; +// +// +//} diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/AliyunSmsTemplate.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/AliyunSmsTemplate.java deleted file mode 100644 index 00d81523a..000000000 --- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/AliyunSmsTemplate.java +++ /dev/null @@ -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 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()); - } - } - -} diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/SmsTemplate.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/SmsTemplate.java deleted file mode 100644 index eba38dfff..000000000 --- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/SmsTemplate.java +++ /dev/null @@ -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 param); - -} diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/TencentSmsTemplate.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/TencentSmsTemplate.java deleted file mode 100644 index 18d738408..000000000 --- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/TencentSmsTemplate.java +++ /dev/null @@ -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 param) { - if (StringUtils.isBlank(phones)) { - throw new SmsException("手机号不能为空"); - } - if (StringUtils.isBlank(templateId)) { - throw new SmsException("模板ID不能为空"); - } - SendSmsRequest req = new SendSmsRequest(); - Set 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()); - } - } - -} diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/entity/SmsResult.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/entity/SmsResult.java deleted file mode 100644 index 232d61201..000000000 --- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/entity/SmsResult.java +++ /dev/null @@ -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; - - /** - * 实际响应体 - *

- * 可自行转换为 SDK 对应的 SendSmsResponse - */ - private String response; -} diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/exception/SmsException.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/exception/SmsException.java deleted file mode 100644 index eb7730ae4..000000000 --- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/exception/SmsException.java +++ /dev/null @@ -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); - } - -} diff --git a/ruoyi-modules/ruoyi-demo/pom.xml b/ruoyi-modules/ruoyi-demo/pom.xml index 09bf0bfae..4fd43bc5f 100644 --- a/ruoyi-modules/ruoyi-demo/pom.xml +++ b/ruoyi-modules/ruoyi-demo/pom.xml @@ -97,16 +97,6 @@ org.dromara ruoyi-common-websocket - - - - - - - - - - diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java index e130cae35..fb1973148 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java +++ b/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 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 map = new HashMap<>(1); + LinkedHashMap 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 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 map = new HashMap<>(1); + LinkedHashMap 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); } } diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java index 2d8b886bd..f38d39caf 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java +++ b/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 selectDbTableColumnsByName(String tableName, String dataName); + List selectDbTableColumnsByName(@Param("tableName") String tableName, String dataName); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java index dc8fbc03d..865b57a9f 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java +++ b/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 syncTenantPackage(@NotBlank(message = "租户ID不能为空") String tenantId, @NotBlank(message = "套餐ID不能为空") Long packageId) { + public R syncTenantPackage(@NotBlank(message = "租户ID不能为空") String tenantId, + @NotNull(message = "套餐ID不能为空") Long packageId) { return toAjax(TenantHelper.ignore(() -> tenantService.syncTenantPackage(tenantId, packageId))); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java index 81bd1ff3d..c3a886980 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java @@ -94,7 +94,7 @@ public interface SysUserMapper extends BaseMapperPlus { * @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 { * @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 { * @return 用户对象信息 */ @InterceptorIgnore(tenantLine = "true") - SysUserVo selectTenantUserByEmail(String email, String tenantId); + SysUserVo selectTenantUserByEmail(@Param("email") String email, @Param("tenantId") String tenantId); + /** * 通过用户ID查询用户 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java index 1302118db..1202c33f2 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java +++ b/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(); }