first commit

This commit is contained in:
zc
2025-06-05 09:51:30 +08:00
commit b3657fb024
680 changed files with 83364 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.dcsoft</groupId>
<artifactId>dcsoft-common</artifactId>
<version>3.6.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dcsoft-common-sms</artifactId>
<description>
dcsoft-common-sms 短信模块
</description>
<dependencies>
<dependency>
<groupId>com.dcsoft</groupId>
<artifactId>dcsoft-common-core</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-sms</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,49 @@
package com.dcsoft.common.sms.config;
import com.dcsoft.common.sms.service.SmsTemplate;
import com.dcsoft.common.sms.service.impl.AliyunSmsTemplate;
import com.dcsoft.common.sms.service.impl.TencentSmsTemplate;
import com.dcsoft.common.sms.config.properties.SmsProperties;
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;
/**
* 短信配置类
*
* @author Lion Li
* @version 4.2.0
*/
@AutoConfiguration
@EnableConfigurationProperties(SmsProperties.class)
public class SmsAutoConfiguration {
@Configuration
@ConditionalOnProperty(value = "sms.enabled", havingValue = "true")
@ConditionalOnClass(com.aliyun.dysmsapi20170525.Client.class)
static class AliyunSmsConfiguration {
@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 TencentSmsConfiguration {
@Bean
public SmsTemplate tencentSmsTemplate(SmsProperties smsProperties) {
return new TencentSmsTemplate(smsProperties);
}
}
}

View File

@@ -0,0 +1,89 @@
package com.dcsoft.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;
private String template1;
private String template2;
/**
* 访客申请审核通知
*/
private String template3;
/**
* 访客申请不通过申请
*/
private String template4;
/**
* 访客申请二维码成功通知
*/
private String template5;
/**
* 物业访客申请审核通知
*/
private String template6;
/**
* 物业访客申请成功
*/
private String template7;
/**
* 物业访客申请不通过
*/
private String template8;
/**
* 兴安访客审核通过
*/
private String template9;
/**
* 兴安访客审核不通过
*/
private String template10;
}

View File

@@ -0,0 +1,31 @@
package com.dcsoft.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

@@ -0,0 +1,16 @@
package com.dcsoft.common.sms.exception;
/**
* Sms异常类
*
* @author Lion Li
*/
public class SmsException extends RuntimeException {
private static final long serialVersionUID = 1L;
public SmsException(String msg) {
super(msg);
}
}

View File

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

View File

@@ -0,0 +1,65 @@
package com.dcsoft.common.sms.service.impl;
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.dcsoft.common.core.utils.JsonUtils;
import com.dcsoft.common.core.utils.StringUtils;
import com.dcsoft.common.sms.config.properties.SmsProperties;
import com.dcsoft.common.sms.entity.SmsResult;
import com.dcsoft.common.sms.exception.SmsException;
import com.dcsoft.common.sms.service.SmsTemplate;
import lombok.SneakyThrows;
import java.util.Map;
/**
* Aliyun 短信模板
*
* @author ai-cloud
*/
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(JsonUtils.toJsonString(resp))
.build();
} catch (Exception e) {
throw new SmsException(e.getMessage());
}
}
}

View File

@@ -0,0 +1,82 @@
package com.dcsoft.common.sms.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
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 com.dcsoft.common.core.utils.JsonUtils;
import com.dcsoft.common.core.utils.StringUtils;
import com.dcsoft.common.sms.config.properties.SmsProperties;
import com.dcsoft.common.sms.entity.SmsResult;
import com.dcsoft.common.sms.exception.SmsException;
import com.dcsoft.common.sms.service.SmsTemplate;
import lombok.SneakyThrows;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Tencent 短信模板
*
* @author ai-cloud
*/
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(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

@@ -0,0 +1 @@
com.dcsoft.common.sms.config.SmsAutoConfiguration