短信模块写成starter

发送短信需要环境
This commit is contained in:
鲸落
2024-10-11 14:11:18 +08:00
parent c77ca554c0
commit 872977d4c2
26 changed files with 590 additions and 18 deletions

View File

@@ -18,6 +18,7 @@
<module>ruoyi-common-sensitive</module>
<module>ruoyi-common-datascope</module>
<module>ruoyi-common-datasource</module>
<module>ruoyi-common-sms</module>
</modules>
<artifactId>ruoyi-common</artifactId>

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.4</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-sms</artifactId>
<description>
ruoyi-common-sms 短信模块
</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version> <!-- 或其他兼容版本 -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,24 @@
package com.ruoyi.common.sms;
import com.ruoyi.common.sms.component.SmsComponent;
import com.ruoyi.common.sms.properties.XunDaYunXinProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
@EnableConfigurationProperties(XunDaYunXinProperties.class)
public class XunDaYunXinAutoConfiguration {
@Bean
public SmsComponent smsComponent() {
return new SmsComponent();
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

View File

@@ -0,0 +1,145 @@
package com.ruoyi.common.sms.component;
import com.ruoyi.common.sms.entity.response.SmsEntity;
import com.ruoyi.common.sms.entity.response.SmsResponse;
import com.ruoyi.common.sms.properties.XunDaYunXinProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import java.util.*;
@Slf4j
public class SmsComponent {
@Autowired
private XunDaYunXinProperties properties;
@Autowired
private RestTemplate restTemplate;
/**
* 点对点
*
* @param mobileContentKvp 号码内容键值对 示例 {"15100000000":"【测试】test1","15100000001":"【测试】test2"}
* @return SmsResponse<SmsEntity>
*/
public SmsResponse sendP2PMsg(Map<String, String> mobileContentKvp) {
Map<String, Object> extraParams = new HashMap<>();
for (Map.Entry<String, String> entry : mobileContentKvp.entrySet()) {
String oldValue = entry.getValue();
String newValue = replaceCode(properties.getTemplate(), oldValue);
entry.setValue(newValue);
}
extraParams.put("mobileContentKvp", mobileContentKvp);
return sendSmsRequest("p2p", extraParams, new ParameterizedTypeReference<SmsResponse>() {
});
}
/**
* 发送群发信息
*
* @param mobile 电话号码按照,分割 示例 "15100000000,15100000001"
* @param content 内容 一般为验证码
* @return SmsResponse<SmsEntity>
*/
public SmsResponse<SmsEntity> sendGroupMsg(String mobile, String content) {
Map<String, Object> extraParams = new HashMap<>();
extraParams.put("mobile", removeDuplicates(mobile));
extraParams.put("content", replaceCode(properties.getTemplate(), content));
return sendSmsRequest("send", extraParams, new ParameterizedTypeReference<SmsResponse<SmsEntity>>() {
});
}
public SmsResponse<?> checkBalance() {
String url = properties.getBaseUrl() + "/smsv2";
Map<String, Object> params = new HashMap<>();
params.put("action", "balance");
params.put("account", properties.getAccount());
params.put("password", properties.getPassword());
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(params);
ResponseEntity<SmsResponse<?>> responseEntity = restTemplate.exchange(
url,
HttpMethod.POST,
requestEntity,
new ParameterizedTypeReference<SmsResponse<?>>() {
}
);
return responseEntity.getBody();
}
/**
* 发送短信请求的通用方法,适用于不同的短信操作。
*
* @param action 短信操作的类型,例如 "p2p"、"send" "balance"。
* @param extraParams 附加的请求参数,具体取决于短信操作的需求。可以为 null。
* @param responseType 返回值的泛型类型,用于指定响应的具体类型。
* @param <T> 响应体中泛型的类型参数。
* @return 包含响应结果的 SmsResponse 对象,响应体中可能包含不同类型的数据。
*/
private <T> T sendSmsRequest(String action, Map<String, Object> extraParams, ParameterizedTypeReference<T> responseType) {
// 拼接请求的 URL 地址
String url = properties.getBaseUrl() + "/smsv2";
// 创建请求参数 Map并填充必需的账户信息和操作类型
Map<String, Object> params = new HashMap<>();
params.put("action", action); // 设置请求的操作类型,如发送短信或查询余额
params.put("account", properties.getAccount()); // 设置账户名
params.put("password", properties.getPassword()); // 设置密码
params.put("extno", properties.getExtno()); // 虚拟接入码
// 如果有额外的参数,则将它们添加到请求参数中
if (extraParams != null) {
params.putAll(extraParams);
}
// 构建 HttpEntity 实体,包含请求参数
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(params);
// 使用 RestTemplate 的 exchange 方法发送 POST 请求,并指定返回的泛型类型
ResponseEntity<T> responseEntity = restTemplate.exchange(
url, // 请求 URL
HttpMethod.POST, // HTTP 方法类型为 POST
requestEntity, // 请求体包含请求参数
responseType // 指定返回类型的泛型引用,用于保留泛型信息
);
// 返回响应体(根据调用方法传入的类型)
return responseEntity.getBody();
}
/**
* 相同号码去重
*
* @param input 字符串电话号码 逗号分隔符分割
* @return String 去重之后的手机电话号码
*/
private String removeDuplicates(String input) {
// 使用 LinkedHashSet 保持插入顺序并去重
Set<String> uniqueSet = new LinkedHashSet<>(Arrays.asList(input.split(",")));
if (uniqueSet.size() >= 1000) {
throw new IllegalArgumentException("群发不建议超过1000个电话号码");
}
// 将去重后的集合转换回字符串
return String.join(",", uniqueSet);
}
/**
* 模板替换占位符
*
* @param template 模板
* @param code 实际值
* @return 替换之后的模板
*/
public String replaceCode(String template, String code) {
return template.replace("{code}", code);
}
}

View File

@@ -0,0 +1 @@
package com.ruoyi.common.sms.entity;

View File

@@ -0,0 +1 @@
package com.ruoyi.common.sms.entity.request;

View File

@@ -0,0 +1,32 @@
package com.ruoyi.common.sms.entity.response;
public class SmsEntity {
private String mid;
private String mobile;
private int result;
// Getters and Setters
public String getMid() {
return mid;
}
public void setMid(String mid) {
this.mid = mid;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public int getResult() {
return result;
}
public void setResult(int result) {
this.result = result;
}
}

View File

@@ -0,0 +1,12 @@
package com.ruoyi.common.sms.entity.response;
import lombok.Data;
import java.util.List;
@Data
public class SmsResponse<T> {
private Integer status;
private Integer balance;
private List<T> list;
}

View File

@@ -0,0 +1,40 @@
package com.ruoyi.common.sms.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 迅达云信短信 配置类
*/
@Data
@ConfigurationProperties(prefix = "xundayunxin")
public class XunDaYunXinProperties {
/**
* 请求地址
*/
private String baseUrl = "http://47.96.236.136:7862/";
/**
* 账号
*/
private String account = "932425";
/**
* 密码
*/
private String password = "alDE77Gmo";
/**
* 虚拟接入码
*/
private String extno = "10690367";
/**
* 是否启用手机号加密
*/
private boolean encryptionEnabled;
/**
* 短信模板
*/
private String template = "【信用秒租】验证码为:{code}您正在登录信用秒租请在3分钟内完成验证如非本人操作请忽略本短信。";
}

View File

@@ -0,0 +1,2 @@
com.ruoyi.common.sms.XunDaYunXinAutoConfiguration
com.ruoyi.common.sms.component.SmsComponent