From 696daae92c78b6b1bfac7c60ccb4aebefdcdcd84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90li?= <15040126243@163.com> Date: Sat, 7 May 2022 13:55:07 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E5=A2=9E=E5=8A=A0=20ruoyi-common-sms=20?= =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=A8=A1=E5=9D=97=20=E6=95=B4=E5=90=88=20?= =?UTF-8?q?=E9=98=BF=E9=87=8C=E4=BA=91=E3=80=81=E8=85=BE=E8=AE=AF=E4=BA=91?= =?UTF-8?q?=20=E7=9F=AD=E4=BF=A1=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + config/dev/application-common.yml | 11 +++ pom.xml | 22 +++++ ruoyi-common/pom.xml | 1 + ruoyi-common/ruoyi-common-bom/pom.xml | 6 ++ ruoyi-common/ruoyi-common-sms/pom.xml | 38 +++++++++ .../sms/config/SmsAutoConfiguration.java | 46 +++++++++++ .../sms/config/properties/SmsProperties.java | 46 +++++++++++ .../common/sms/core/AliyunSmsTemplate.java | 65 +++++++++++++++ .../ruoyi/common/sms/core/SmsTemplate.java | 26 ++++++ .../common/sms/core/TencentSmsTemplate.java | 80 +++++++++++++++++++ .../ruoyi/common/sms/entity/SmsResult.java | 29 +++++++ .../common/sms/exception/SmsException.java | 16 ++++ .../main/resources/META-INF/spring.factories | 2 + 14 files changed, 389 insertions(+) create mode 100644 ruoyi-common/ruoyi-common-sms/pom.xml create mode 100644 ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/config/SmsAutoConfiguration.java create mode 100644 ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/config/properties/SmsProperties.java create mode 100644 ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/core/AliyunSmsTemplate.java create mode 100644 ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/core/SmsTemplate.java create mode 100644 ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/core/TencentSmsTemplate.java create mode 100644 ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/entity/SmsResult.java create mode 100644 ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/exception/SmsException.java create mode 100644 ruoyi-common/ruoyi-common-sms/src/main/resources/META-INF/spring.factories diff --git a/README.md b/README.md index 8f3d2baf..83b44dfe 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ | 分布式任务调度 | Xxl-Job | [Xxl-Job官网](https://www.xuxueli.com/xxl-job/) | 高性能 高可靠 易扩展 | | 分布式文件存储 | Minio | [Minio文档](https://docs.min.io/) | 本地存储 | | 分布式云存储 | 七牛、阿里、腾讯 | [OSS使用文档](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages?sort_id=4359146&doc_id=1469725) | 云存储 | +| 短信模块 | 阿里、腾讯 | [短信使用文档](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages?sort_id=5578491&doc_id=1469725) | 短信发送 | | 分布式监控(未完成) | Prometheus、Grafana | [Prometheus文档](https://prometheus.io/docs/introduction/overview/) | 全方位性能监控 | | 服务监控 | SpringBoot-Admin | [SpringBoot-Admin文档](https://codecentric.github.io/spring-boot-admin/current/) | 全方位服务监控 | | 数据库框架 | Mybatis-Plus | [Mybatis-Plus文档](https://baomidou.com/guide/) | 快速 CRUD 增加开发效率 | diff --git a/config/dev/application-common.yml b/config/dev/application-common.yml index 42900a6f..a6fde852 100644 --- a/config/dev/application-common.yml +++ b/config/dev/application-common.yml @@ -313,3 +313,14 @@ mail: timeout: 0 # Socket连接超时值,单位毫秒,缺省值不超时 connectionTimeout: 0 + +sms: + enabled: false + # 阿里云 dysmsapi.aliyuncs.com + # 腾讯云 sms.tencentcloudapi.com + endpoint: "dysmsapi.aliyuncs.com" + accessKeyId: xxxxxxx + accessKeySecret: xxxxxx + signName: 测试 + # 腾讯专用 + sdkAppId: diff --git a/pom.xml b/pom.xml index bb132e6e..54ffd023 100644 --- a/pom.xml +++ b/pom.xml @@ -50,6 +50,10 @@ 8.3.8 4.9.3 + + 2.0.9 + 3.1.500 + localhost http://${docker.registry.url}:2375 @@ -248,6 +252,24 @@ ${okhttp.version} + + com.aliyun + dysmsapi20170525 + ${aliyun.sms.version} + + + + com.tencentcloudapi + tencentcloud-sdk-java + ${tencent.sms.version} + + + com.squareup.okio + okio + + + + com.google.guava diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 69acd258..2399841b 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -28,6 +28,7 @@ ruoyi-common-oss ruoyi-common-idempotent ruoyi-common-mail + ruoyi-common-sms ruoyi-common diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml index 32380bba..18395e26 100644 --- a/ruoyi-common/ruoyi-common-bom/pom.xml +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -126,6 +126,12 @@ ${project.version} + + com.ruoyi + ruoyi-common-sms + ${project.version} + + diff --git a/ruoyi-common/ruoyi-common-sms/pom.xml b/ruoyi-common/ruoyi-common-sms/pom.xml new file mode 100644 index 00000000..87b22b21 --- /dev/null +++ b/ruoyi-common/ruoyi-common-sms/pom.xml @@ -0,0 +1,38 @@ + + + + com.ruoyi + ruoyi-common + 0.10.0 + + 4.0.0 + + ruoyi-common-sms + + + ruoyi-common-sms 短信模块 + + + + + + com.ruoyi + ruoyi-common-core + + + + com.aliyun + dysmsapi20170525 + true + + + + com.tencentcloudapi + tencentcloud-sdk-java + true + + + + diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/config/SmsAutoConfiguration.java b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/config/SmsAutoConfiguration.java new file mode 100644 index 00000000..d58e127c --- /dev/null +++ b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/config/SmsAutoConfiguration.java @@ -0,0 +1,46 @@ +package com.ruoyi.common.sms.config; + +import com.ruoyi.common.sms.config.properties.SmsProperties; +import com.ruoyi.common.sms.core.AliyunSmsTemplate; +import com.ruoyi.common.sms.core.SmsTemplate; +import com.ruoyi.common.sms.core.TencentSmsTemplate; +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; + +/** + * 短信配置类 + * + * @author Lion Li + * @version 4.2.0 + */ +@Configuration +@ConditionalOnProperty(value = "sms.enabled", havingValue = "true") +@EnableConfigurationProperties(SmsProperties.class) +public class SmsAutoConfiguration { + + @Configuration + @ConditionalOnClass(com.aliyun.dysmsapi20170525.Client.class) + static class AliyunSmsConfiguration { + + @Bean + public SmsTemplate aliyunSmsTemplate(SmsProperties smsProperties) { + return new AliyunSmsTemplate(smsProperties); + } + + } + + @Configuration + @ConditionalOnClass(com.tencentcloudapi.sms.v20190711.SmsClient.class) + static class TencentSmsConfiguration { + + @Bean + public SmsTemplate tencentSmsTemplate(SmsProperties smsProperties) { + return new TencentSmsTemplate(smsProperties); + } + + } + +} diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/config/properties/SmsProperties.java b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/config/properties/SmsProperties.java new file mode 100644 index 00000000..c0afb0b6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/config/properties/SmsProperties.java @@ -0,0 +1,46 @@ +package com.ruoyi.common.sms.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 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; + +} diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/core/AliyunSmsTemplate.java b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/core/AliyunSmsTemplate.java new file mode 100644 index 00000000..7d36aa7e --- /dev/null +++ b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/core/AliyunSmsTemplate.java @@ -0,0 +1,65 @@ +package com.ruoyi.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 com.ruoyi.common.core.utils.JsonUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.sms.config.properties.SmsProperties; +import com.ruoyi.common.sms.entity.SmsResult; +import com.ruoyi.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); + } + + 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(resp) + .build(); + } catch (Exception e) { + throw new SmsException(e.getMessage()); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/core/SmsTemplate.java b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/core/SmsTemplate.java new file mode 100644 index 00000000..eb61b863 --- /dev/null +++ b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/core/SmsTemplate.java @@ -0,0 +1,26 @@ +package com.ruoyi.common.sms.core; + +import com.ruoyi.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/com/ruoyi/common/sms/core/TencentSmsTemplate.java b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/core/TencentSmsTemplate.java new file mode 100644 index 00000000..0827d10c --- /dev/null +++ b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/core/TencentSmsTemplate.java @@ -0,0 +1,80 @@ +package com.ruoyi.common.sms.core; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.sms.config.properties.SmsProperties; +import com.ruoyi.common.sms.entity.SmsResult; +import com.ruoyi.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); + } + + 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(",")).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(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/com/ruoyi/common/sms/entity/SmsResult.java b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/entity/SmsResult.java new file mode 100644 index 00000000..b1a7b28f --- /dev/null +++ b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/entity/SmsResult.java @@ -0,0 +1,29 @@ +package com.ruoyi.common.sms.entity; + +import lombok.Builder; +import lombok.Data; + +/** + * 上传返回体 + * + * @author Lion Li + */ +@Data +@Builder +public class SmsResult { + + /** + * 是否成功 + */ + private boolean isSuccess; + + /** + * 响应消息 + */ + private String message; + + /** + * 实际响应体 + */ + private Object response; +} diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/exception/SmsException.java b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/exception/SmsException.java new file mode 100644 index 00000000..f855a29a --- /dev/null +++ b/ruoyi-common/ruoyi-common-sms/src/main/java/com/ruoyi/common/sms/exception/SmsException.java @@ -0,0 +1,16 @@ +package com.ruoyi.common.sms.exception; + +/** + * Sms异常类 + * + * @author Lion Li + */ +public class SmsException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public SmsException(String msg) { + super(msg); + } + +} diff --git a/ruoyi-common/ruoyi-common-sms/src/main/resources/META-INF/spring.factories b/ruoyi-common/ruoyi-common-sms/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..1058e084 --- /dev/null +++ b/ruoyi-common/ruoyi-common-sms/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.ruoyi.common.sms.config.SmsAutoConfiguration