From e57d11d55a95ceafc793f714710d488bb1afc585 Mon Sep 17 00:00:00 2001
From: 疯狂的狮子li <15040126243@163.com>
Date: 星期五, 06 五月 2022 18:07:00 +0800
Subject: [PATCH] add 增加 ruoyi-sms 短信模块 整合 阿里云、腾讯云 短信功能

---
 ruoyi-sms/src/main/java/com/ruoyi/sms/entity/SmsResult.java                |   29 ++++
 ruoyi-sms/src/main/java/com/ruoyi/sms/config/SmsConfig.java                |   44 ++++++
 ruoyi-sms/src/main/java/com/ruoyi/sms/core/SmsTemplate.java                |   26 +++
 ruoyi-admin/src/main/resources/application-prod.yml                        |   12 +
 ruoyi-sms/src/main/java/com/ruoyi/sms/core/AliyunSmsTemplate.java          |   65 +++++++++
 ruoyi-sms/src/main/java/com/ruoyi/sms/exception/SmsException.java          |   16 ++
 ruoyi-sms/src/main/java/com/ruoyi/sms/core/TencentSmsTemplate.java         |   80 +++++++++++
 pom.xml                                                                    |   24 +++
 ruoyi-sms/src/main/java/com/ruoyi/sms/config/properties/SmsProperties.java |   47 ++++++
 ruoyi-admin/src/main/resources/application-dev.yml                         |   12 +
 ruoyi-sms/pom.xml                                                          |   40 +++++
 11 files changed, 395 insertions(+), 0 deletions(-)

diff --git a/pom.xml b/pom.xml
index 4fc098f..bd82267 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,6 +50,10 @@
         <qcloud.cos.version>5.6.72</qcloud.cos.version>
         <minio.version>8.3.8</minio.version>
 
+        <!-- SMS 閰嶇疆 -->
+        <aliyun.sms.version>2.0.9</aliyun.sms.version>
+        <tencent.sms.version>3.1.500</tencent.sms.version>
+
         <!-- docker 閰嶇疆 -->
         <docker.registry.url>localhost</docker.registry.url>
         <docker.registry.host>http://${docker.registry.url}:2375</docker.registry.host>
@@ -193,6 +197,18 @@
             </dependency>
 
             <dependency>
+                <groupId>com.aliyun</groupId>
+                <artifactId>dysmsapi20170525</artifactId>
+                <version>${aliyun.sms.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.tencentcloudapi</groupId>
+                <artifactId>tencentcloud-sdk-java</artifactId>
+                <version>${tencent.sms.version}</version>
+            </dependency>
+
+            <dependency>
                 <groupId>de.codecentric</groupId>
                 <artifactId>spring-boot-admin-starter-server</artifactId>
                 <version>${spring-boot-admin.version}</version>
@@ -297,6 +313,13 @@
                 <version>${ruoyi-vue-plus.version}</version>
             </dependency>
 
+            <!-- SMS鐭俊妯″潡 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-sms</artifactId>
+                <version>${ruoyi-vue-plus.version}</version>
+            </dependency>
+
             <!-- demo妯″潡 -->
             <dependency>
                 <groupId>com.ruoyi</groupId>
@@ -317,6 +340,7 @@
         <module>ruoyi-demo</module>
         <module>ruoyi-extend</module>
         <module>ruoyi-oss</module>
+        <module>ruoyi-sms</module>
     </modules>
     <packaging>pom</packaging>
 
diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
index 6be268b..d14047f 100644
--- a/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -178,3 +178,15 @@
   timeout: 0
   # Socket杩炴帴瓒呮椂鍊硷紝鍗曚綅姣锛岀己鐪佸�间笉瓒呮椂
   connectionTimeout: 0
+
+--- # sms 鐭俊
+sms:
+  enabled: false
+  # 闃块噷浜� dysmsapi.aliyuncs.com
+  # 鑵捐浜� sms.tencentcloudapi.com
+  endpoint: "dysmsapi.aliyuncs.com"
+  accessKeyId: xxxxxxx
+  accessKeySecret: xxxxxx
+  signName: 娴嬭瘯
+  # 鑵捐涓撶敤
+  sdkAppId:
diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml
index 4966a41..6619e05 100644
--- a/ruoyi-admin/src/main/resources/application-prod.yml
+++ b/ruoyi-admin/src/main/resources/application-prod.yml
@@ -181,3 +181,15 @@
   timeout: 0
   # Socket杩炴帴瓒呮椂鍊硷紝鍗曚綅姣锛岀己鐪佸�间笉瓒呮椂
   connectionTimeout: 0
+
+--- # sms 鐭俊
+sms:
+  enabled: false
+  # 闃块噷浜� dysmsapi.aliyuncs.com
+  # 鑵捐浜� sms.tencentcloudapi.com
+  endpoint: "dysmsapi.aliyuncs.com"
+  accessKeyId: xxxxxxx
+  accessKeySecret: xxxxxx
+  signName: 娴嬭瘯
+  # 鑵捐涓撶敤
+  sdkAppId:
diff --git a/ruoyi-sms/pom.xml b/ruoyi-sms/pom.xml
new file mode 100644
index 0000000..8550e8c
--- /dev/null
+++ b/ruoyi-sms/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>ruoyi-vue-plus</artifactId>
+        <groupId>com.ruoyi</groupId>
+        <version>4.1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-sms</artifactId>
+
+    <description>
+        SMS鐭俊妯″潡
+    </description>
+
+    <dependencies>
+
+        <!-- 閫氱敤宸ュ叿-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-common</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>dysmsapi20170525</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>com.tencentcloudapi</groupId>
+            <artifactId>tencentcloud-sdk-java</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/ruoyi-sms/src/main/java/com/ruoyi/sms/config/SmsConfig.java b/ruoyi-sms/src/main/java/com/ruoyi/sms/config/SmsConfig.java
new file mode 100644
index 0000000..abc4bb9
--- /dev/null
+++ b/ruoyi-sms/src/main/java/com/ruoyi/sms/config/SmsConfig.java
@@ -0,0 +1,44 @@
+package com.ruoyi.sms.config;
+
+import com.ruoyi.sms.config.properties.SmsProperties;
+import com.ruoyi.sms.core.AliyunSmsTemplate;
+import com.ruoyi.sms.core.SmsTemplate;
+import com.ruoyi.sms.core.TencentSmsTemplate;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+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")
+public class SmsConfig {
+
+    @Configuration
+    @ConditionalOnClass(com.aliyun.dysmsapi20170525.Client.class)
+    static class AliyunSmsConfig {
+
+        @Bean
+        public SmsTemplate aliyunSmsTemplate(SmsProperties smsProperties) {
+            return new AliyunSmsTemplate(smsProperties);
+        }
+
+    }
+
+    @Configuration
+    @ConditionalOnClass(com.tencentcloudapi.sms.v20190711.SmsClient.class)
+    static class TencentSmsConfig {
+
+        @Bean
+        public SmsTemplate tencentSmsTemplate(SmsProperties smsProperties) {
+            return new TencentSmsTemplate(smsProperties);
+        }
+
+    }
+
+}
diff --git a/ruoyi-sms/src/main/java/com/ruoyi/sms/config/properties/SmsProperties.java b/ruoyi-sms/src/main/java/com/ruoyi/sms/config/properties/SmsProperties.java
new file mode 100644
index 0000000..39359cd
--- /dev/null
+++ b/ruoyi-sms/src/main/java/com/ruoyi/sms/config/properties/SmsProperties.java
@@ -0,0 +1,47 @@
+package com.ruoyi.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
+@Component
+@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-sms/src/main/java/com/ruoyi/sms/core/AliyunSmsTemplate.java b/ruoyi-sms/src/main/java/com/ruoyi/sms/core/AliyunSmsTemplate.java
new file mode 100644
index 0000000..87c3f3b
--- /dev/null
+++ b/ruoyi-sms/src/main/java/com/ruoyi/sms/core/AliyunSmsTemplate.java
@@ -0,0 +1,65 @@
+package com.ruoyi.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.utils.JsonUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.sms.config.properties.SmsProperties;
+import com.ruoyi.sms.entity.SmsResult;
+import com.ruoyi.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<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(resp)
+                .build();
+        } catch (Exception e) {
+            throw new SmsException(e.getMessage());
+        }
+    }
+
+}
diff --git a/ruoyi-sms/src/main/java/com/ruoyi/sms/core/SmsTemplate.java b/ruoyi-sms/src/main/java/com/ruoyi/sms/core/SmsTemplate.java
new file mode 100644
index 0000000..0aec3dd
--- /dev/null
+++ b/ruoyi-sms/src/main/java/com/ruoyi/sms/core/SmsTemplate.java
@@ -0,0 +1,26 @@
+package com.ruoyi.sms.core;
+
+import com.ruoyi.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);
+
+}
diff --git a/ruoyi-sms/src/main/java/com/ruoyi/sms/core/TencentSmsTemplate.java b/ruoyi-sms/src/main/java/com/ruoyi/sms/core/TencentSmsTemplate.java
new file mode 100644
index 0000000..ce82c3c
--- /dev/null
+++ b/ruoyi-sms/src/main/java/com/ruoyi/sms/core/TencentSmsTemplate.java
@@ -0,0 +1,80 @@
+package com.ruoyi.sms.core;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ArrayUtil;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.sms.config.properties.SmsProperties;
+import com.ruoyi.sms.entity.SmsResult;
+import com.ruoyi.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<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(",")).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-sms/src/main/java/com/ruoyi/sms/entity/SmsResult.java b/ruoyi-sms/src/main/java/com/ruoyi/sms/entity/SmsResult.java
new file mode 100644
index 0000000..3f13b27
--- /dev/null
+++ b/ruoyi-sms/src/main/java/com/ruoyi/sms/entity/SmsResult.java
@@ -0,0 +1,29 @@
+package com.ruoyi.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-sms/src/main/java/com/ruoyi/sms/exception/SmsException.java b/ruoyi-sms/src/main/java/com/ruoyi/sms/exception/SmsException.java
new file mode 100644
index 0000000..28632a3
--- /dev/null
+++ b/ruoyi-sms/src/main/java/com/ruoyi/sms/exception/SmsException.java
@@ -0,0 +1,16 @@
+package com.ruoyi.sms.exception;
+
+/**
+ * Sms寮傚父绫�
+ *
+ * @author Lion Li
+ */
+public class SmsException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    public SmsException(String msg) {
+        super(msg);
+    }
+
+}

--
Gitblit v1.9.3