!367 集成sms4j短信

集成sms4j短信
This commit is contained in:
友杰 2023-06-09 01:58:50 +00:00 committed by 疯狂的狮子Li
parent d34be960cb
commit bb587607e1
12 changed files with 39 additions and 333 deletions

17
pom.xml
View File

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

View File

@ -15,10 +15,11 @@ 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.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;
/**
* 验证码操作处理
@ -64,14 +64,13 @@ public class CaptchaController {
String code = RandomUtil.randomNumbers(4);
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
// 验证码模板id 自行处理 (查数据库或写死均可)
String templateId = "";
Map<String, String> map = new HashMap<>(1);
String templateId = "SMS_460945446";
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put("code", code);
SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class);
SmsResult result = smsTemplate.send(phonenumber, templateId, map);
if (!result.isSuccess()) {
log.error("验证码短信发送异常 => {}", result);
return R.fail(result.getMessage());
SmsResponse smsResponse = SmsFactory.createSmsBlend(SupplierType.ALIBABA).sendMessage(phonenumber, templateId, map);
if (!"OK".equals(smsResponse.getCode())) {
log.error("验证码短信发送异常 => {}", smsResponse);
return R.fail(smsResponse.getMessage());
}
return R.ok();
}

View File

@ -158,14 +158,16 @@ mail:
# Socket连接超时值单位毫秒缺省值不超时
connectionTimeout: 0
--- # sms 短信
--- # sms 短信 https://wind.kim/doc/start/springboot.html
sms:
enabled: false
enabled: true
# 阿里云 dysmsapi.aliyuncs.com
# 腾讯云 sms.tencentcloudapi.com
endpoint: "dysmsapi.aliyuncs.com"
alibaba:
#阿里云的accessKey
accessKeyId: xxxxxxx
accessKeySecret: xxxxxx
signName: 测试
# 腾讯专用
sdkAppId:
#阿里云的accessKeySecret
accessKeySecret: xxxxxxx
#短信签名
signature: 测试
#请求地址 默认为dysmsapi.aliyuncs.com 如无特殊改变可以不用设置
requestUrl: dysmsapi.aliyuncs.com

View File

@ -22,16 +22,10 @@
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<optional>true</optional>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-sms</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -1,15 +1,8 @@
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;
/**
* 短信配置类
@ -21,28 +14,4 @@ import org.springframework.context.annotation.Configuration;
@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);
}
}
}

View File

@ -15,31 +15,5 @@ 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;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
}

View File

@ -1,17 +1,18 @@
package org.dromara.demo.controller;
import lombok.RequiredArgsConstructor;
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.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;
/**
* 短信演示案例
@ -44,11 +45,10 @@ public class SmsController {
if (!SpringUtils.containsBean("aliyunSmsTemplate")) {
return R.fail("阿里云依赖未引入!");
}
SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class);
Map<String, String> map = new HashMap<>(1);
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put("code", "1234");
Object send = smsTemplate.send(phones, templateId, map);
return R.ok(send);
SmsResponse smsResponse = SmsFactory.createSmsBlend(SupplierType.ALIBABA).sendMessage(phones, templateId, map);
return R.ok(smsResponse);
}
/**
@ -65,12 +65,11 @@ public class SmsController {
if (!SpringUtils.containsBean("tencentSmsTemplate")) {
return R.fail("腾讯云依赖未引入!");
}
SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class);
Map<String, String> map = new HashMap<>(1);
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
// map.put("2", "测试测试");
map.put("1", "1234");
Object send = smsTemplate.send(phones, templateId, map);
return R.ok(send);
SmsResponse smsResponse = SmsFactory.createSmsBlend(SupplierType.TENCENT).sendMessage(phones, templateId, map);
return R.ok(smsResponse);
}
}