🔥 重构项目结构,新增 sms4j-provider 短信厂商对接模块(国内短信)

This commit is contained in:
Charles7c 2023-04-27 20:38:09 +08:00
parent 76fafd56d5
commit ce720abd07
56 changed files with 897 additions and 1255 deletions

55
pom.xml
View File

@ -2,7 +2,6 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.dromara.sms4j</groupId> <groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j</artifactId> <artifactId>sms4j</artifactId>
<version>${revision}</version> <version>${revision}</version>
@ -15,17 +14,10 @@
<modules> <modules>
<module>sms4j-comm</module> <module>sms4j-comm</module>
<module>sms4j-api</module> <module>sms4j-api</module>
<module>sms4j-provider</module>
<module>sms4j-core</module> <module>sms4j-core</module>
<module>sms4j-autoimmit</module> <module>sms4j-autoimmit</module>
<module>sms4j-spring-boot-starter</module> <module>sms4j-spring-boot-starter</module>
<module>sms4j-aliyun</module>
<module>sms4j-tencent</module>
<module>sms4j-unisms</module>
<module>sms4j-yunpian</module>
<module>sms4j-huawei</module>
<module>sms4j-jdcloud</module>
<module>sms4j-cloopen</module>
<module>sms4j-emay</module>
</modules> </modules>
<!-- 开源协议 Apache 2.0 --> <!-- 开源协议 Apache 2.0 -->
@ -117,51 +109,10 @@
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 短信厂商对接模块(国内短信) -->
<dependency> <dependency>
<groupId>org.dromara.sms4j</groupId> <groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-aliyun</artifactId> <artifactId>sms4j-provider</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-tencent</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-unisms</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-yunpian</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-huawei</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-jdcloud</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-cloopen</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-emay</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>

View File

@ -1,37 +0,0 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms4j-aliyun</artifactId>
<name>sms4j-aliyun</name>
<description>sms4j-aliyun</description>
<version>${revision}</version>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-comm</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.9</version>
</dependency>
</dependencies>
</project>

View File

@ -10,12 +10,9 @@
</parent> </parent>
<artifactId>sms4j-api</artifactId> <artifactId>sms4j-api</artifactId>
<name>sms4j-api</name> <name>sms4j-api</name>
<description>sms4j-api</description> <description>sms4j-api</description>
<version>${revision}</version>
<properties>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>

View File

@ -10,13 +10,10 @@
</parent> </parent>
<artifactId>sms4j-autoimmit</artifactId> <artifactId>sms4j-autoimmit</artifactId>
<version>${revision}</version>
<name>sms4j-autoimmit</name> <name>sms4j-autoimmit</name>
<description>sms4j-autoimmit</description> <description>sms4j-autoimmit</description>
<properties>
</properties>
<dependencies> <dependencies>
<!--aop依赖--> <!--aop依赖-->
<dependency> <dependency>

View File

@ -1,29 +0,0 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms4j-cloopen</artifactId>
<name>sms4j-cloopen</name>
<description>sms4j-cloopen</description>
<version>${revision}</version>
<dependencies>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-comm</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -10,15 +10,11 @@
</parent> </parent>
<artifactId>sms4j-comm</artifactId> <artifactId>sms4j-comm</artifactId>
<name>sms4j-comm</name> <name>sms4j-comm</name>
<description>sms4j-comm</description> <description>sms4j-comm</description>
<version>${revision}</version>
<properties>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId> <artifactId>fastjson</artifactId>

View File

@ -10,57 +10,14 @@
</parent> </parent>
<artifactId>sms4j-core</artifactId> <artifactId>sms4j-core</artifactId>
<version>${revision}</version>
<name>sms4j-core</name> <name>sms4j-core</name>
<description>sms4j-core</description> <description>sms4j-core</description>
<properties>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.dromara.sms4j</groupId> <groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-aliyun</artifactId> <artifactId>sms4j-provider</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-tencent</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-unisms</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-yunpian</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-huawei</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-jdcloud</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-emay</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-cloopen</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
</plugins>
</build>
</project> </project>

View File

@ -1,8 +1,5 @@
package org.dromara.sms4j.core.factory; package org.dromara.sms4j.core.factory;
import org.dromara.sms4j.comm.config.SmsConfig;
import org.dromara.sms4j.comm.enumerate.ConfigType;
import org.dromara.sms4j.comm.factory.BeanFactory;
import org.dromara.sms4j.core.SupplierSqlConfig; import org.dromara.sms4j.core.SupplierSqlConfig;
import org.dromara.sms4j.emay.config.EmaySmsConfig; import org.dromara.sms4j.emay.config.EmaySmsConfig;
import org.dromara.sms4j.aliyun.config.AlibabaSmsConfig; import org.dromara.sms4j.aliyun.config.AlibabaSmsConfig;

View File

@ -1,31 +0,0 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms4j-emay</artifactId>
<version>${revision}</version>
<name>sms4j-emay</name>
<description>sms4j-emay</description>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-comm</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,34 +0,0 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms4j-huawei</artifactId>
<version>${revision}</version>
<name>sms4j-huawei</name>
<description>sms4j-huawei</description>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-comm</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-api</artifactId>
</dependency>
</dependencies>
<build>
</build>
</project>

View File

@ -7,29 +7,29 @@
<groupId>org.dromara.sms4j</groupId> <groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j</artifactId> <artifactId>sms4j</artifactId>
<version>${revision}</version> <version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent> </parent>
<artifactId>sms4j-jdcloud</artifactId> <artifactId>sms4j-provider</artifactId>
<name>sms4j-jdcloud</name>
<description>sms4j-jdcloud</description> <name>sms4j-provider</name>
<version>${revision}</version> <description>短信厂商对接模块(国内短信)</description>
<dependencies> <dependencies>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-api</artifactId>
</dependency>
<!-- 合一短信依赖 -->
<dependency>
<groupId>com.apistd.uni</groupId>
<artifactId>uni-sdk</artifactId>
</dependency>
<!-- 京东云短信依赖 --> <!-- 京东云短信依赖 -->
<dependency> <dependency>
<groupId>com.jdcloud.sdk</groupId> <groupId>com.jdcloud.sdk</groupId>
<artifactId>sms</artifactId> <artifactId>sms</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-comm</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-api</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,44 +1,44 @@
package org.dromara.sms4j.aliyun.config; package org.dromara.sms4j.aliyun.config;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import lombok.experimental.SuperBuilder; import lombok.experimental.SuperBuilder;
import org.dromara.sms4j.comm.config.BaseConfig; import org.dromara.sms4j.comm.config.BaseConfig;
@Data @Data
@SuperBuilder @SuperBuilder
@ToString(callSuper = true) @ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class AlibabaConfig extends BaseConfig { public class AlibabaConfig extends BaseConfig {
/** /**
* 模板变量名称 * 模板变量名称
*/ */
private String templateName; private String templateName;
/** /**
* 请求地址 * 请求地址
*/ */
@Builder.Default @Builder.Default
private String requestUrl = "dysmsapi.aliyuncs.com"; private String requestUrl = "dysmsapi.aliyuncs.com";
/** /**
* 接口名称 * 接口名称
*/ */
@Builder.Default @Builder.Default
private String action = "SendSms"; private String action = "SendSms";
/** /**
* 接口版本号 * 接口版本号
*/ */
@Builder.Default @Builder.Default
private String version = "2017-05-25"; private String version = "2017-05-25";
/** /**
* 地域信息默认为 cn-hangzhou * 地域信息默认为 cn-hangzhou
*/ */
@Builder.Default @Builder.Default
private String regionId = "cn-hangzhou"; private String regionId = "cn-hangzhou";
} }

View File

@ -1,62 +1,62 @@
package org.dromara.sms4j.aliyun.config; package org.dromara.sms4j.aliyun.config;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.aliyun.service.AlibabaSmsImpl; import org.dromara.sms4j.aliyun.service.AlibabaSmsImpl;
import org.dromara.sms4j.comm.factory.BeanFactory; import org.dromara.sms4j.comm.factory.BeanFactory;
/** /**
* AlibabaSmsConfig * AlibabaSmsConfig
* <p> 阿里巴巴对象建造者 * <p> 阿里巴巴对象建造者
* *
* @author :Wind * @author :Wind
* 2023/4/8 14:54 * 2023/4/8 14:54
**/ **/
@Slf4j @Slf4j
public class AlibabaSmsConfig { public class AlibabaSmsConfig {
private static AlibabaSmsImpl alibabaSms; private static AlibabaSmsImpl alibabaSms;
private static AlibabaSmsConfig alibabaSmsConfig; private static AlibabaSmsConfig alibabaSmsConfig;
/** /**
* getAlibabaSms * getAlibabaSms
* <p> 建造一个短信实现对像 * <p> 建造一个短信实现对像
* *
* @author :Wind * @author :Wind
*/ */
public static AlibabaSmsImpl createAlibabaSms(AlibabaConfig alibabaConfig) { public static AlibabaSmsImpl createAlibabaSms(AlibabaConfig alibabaConfig) {
if (alibabaSmsConfig == null) { if (alibabaSmsConfig == null) {
alibabaSmsConfig = new AlibabaSmsConfig(); alibabaSmsConfig = new AlibabaSmsConfig();
} }
if (alibabaSms == null) { if (alibabaSms == null) {
alibabaSms = new AlibabaSmsImpl( alibabaSms = new AlibabaSmsImpl(
alibabaConfig, alibabaConfig,
BeanFactory.getExecutor(), BeanFactory.getExecutor(),
BeanFactory.getDelayedTime()); BeanFactory.getDelayedTime());
} }
return alibabaSms; return alibabaSms;
} }
/** /**
* refresh * refresh
* <p> 刷新对象 * <p> 刷新对象
* *
* @author :Wind * @author :Wind
*/ */
public static AlibabaSmsImpl refresh(AlibabaConfig alibabaConfig) { public static AlibabaSmsImpl refresh(AlibabaConfig alibabaConfig) {
// 如果配置对象为空则创建一个 // 如果配置对象为空则创建一个
if (alibabaSmsConfig == null) { if (alibabaSmsConfig == null) {
alibabaSmsConfig = new AlibabaSmsConfig(); alibabaSmsConfig = new AlibabaSmsConfig();
} }
//重新构造一个实现对象 //重新构造一个实现对象
alibabaSms = new AlibabaSmsImpl( alibabaSms = new AlibabaSmsImpl(
alibabaConfig, alibabaConfig,
BeanFactory.getExecutor(), BeanFactory.getExecutor(),
BeanFactory.getDelayedTime()); BeanFactory.getDelayedTime());
return alibabaSms; return alibabaSms;
} }
private AlibabaSmsConfig() { private AlibabaSmsConfig() {
} }
} }

View File

@ -1,196 +1,196 @@
package org.dromara.sms4j.aliyun.service; package org.dromara.sms4j.aliyun.service;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.dtflys.forest.config.ForestConfiguration; import com.dtflys.forest.config.ForestConfiguration;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.aliyun.config.AlibabaConfig; import org.dromara.sms4j.aliyun.config.AlibabaConfig;
import org.dromara.sms4j.aliyun.utils.AliyunUtils; import org.dromara.sms4j.aliyun.utils.AliyunUtils;
import org.dromara.sms4j.api.SmsBlend; import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.callback.CallBack; import org.dromara.sms4j.api.callback.CallBack;
import org.dromara.sms4j.api.entity.SmsResponse; import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.comm.annotation.Restricted; import org.dromara.sms4j.comm.annotation.Restricted;
import org.dromara.sms4j.comm.delayedTime.DelayedTime; import org.dromara.sms4j.comm.delayedTime.DelayedTime;
import org.dromara.sms4j.comm.exception.SmsBlendException; import org.dromara.sms4j.comm.exception.SmsBlendException;
import org.dromara.sms4j.comm.factory.BeanFactory; import org.dromara.sms4j.comm.factory.BeanFactory;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.TimerTask; import java.util.TimerTask;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
/** /**
* <p>类名: AlibabaSmsImpl * <p>类名: AlibabaSmsImpl
* <p>说明 阿里云短信实现 * <p>说明 阿里云短信实现
* *
* @author :Wind * @author :Wind
* 2023/3/26 17:16 * 2023/3/26 17:16
**/ **/
@Slf4j @Slf4j
public class AlibabaSmsImpl implements SmsBlend { public class AlibabaSmsImpl implements SmsBlend {
private final AlibabaConfig alibabaSmsConfig; private final AlibabaConfig alibabaSmsConfig;
private final Executor pool; private final Executor pool;
private final DelayedTime delayed; private final DelayedTime delayed;
private final ForestConfiguration http = BeanFactory.getForestConfiguration(); private final ForestConfiguration http = BeanFactory.getForestConfiguration();
/** /**
* AlibabaSmsImpl * AlibabaSmsImpl
* <p>构造器用于构造短信实现模块 * <p>构造器用于构造短信实现模块
* *
* @author :Wind * @author :Wind
*/ */
public AlibabaSmsImpl(AlibabaConfig alibabaSmsConfig, Executor pool, DelayedTime delayedTime) { public AlibabaSmsImpl(AlibabaConfig alibabaSmsConfig, Executor pool, DelayedTime delayedTime) {
this.alibabaSmsConfig = alibabaSmsConfig; this.alibabaSmsConfig = alibabaSmsConfig;
this.pool = pool; this.pool = pool;
this.delayed = delayedTime; this.delayed = delayedTime;
} }
@Override @Override
@Restricted @Restricted
public SmsResponse sendMessage(String phone, String message) { public SmsResponse sendMessage(String phone, String message) {
LinkedHashMap<String, String> map = new LinkedHashMap<>(); LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put(alibabaSmsConfig.getTemplateName(), message); map.put(alibabaSmsConfig.getTemplateName(), message);
return sendMessage(phone, alibabaSmsConfig.getTemplateId(), map); return sendMessage(phone, alibabaSmsConfig.getTemplateId(), map);
} }
@Override @Override
@Restricted @Restricted
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) { public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
String messageStr = JSON.toJSONString(messages); String messageStr = JSON.toJSONString(messages);
return getSmsResponse(phone, messageStr, templateId); return getSmsResponse(phone, messageStr, templateId);
} }
@Override @Override
@Restricted @Restricted
public SmsResponse massTexting(List<String> phones, String message) { public SmsResponse massTexting(List<String> phones, String message) {
LinkedHashMap<String, String> map = new LinkedHashMap<>(); LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put(alibabaSmsConfig.getTemplateName(), message); map.put(alibabaSmsConfig.getTemplateName(), message);
return massTexting(phones, alibabaSmsConfig.getTemplateId(), map); return massTexting(phones, alibabaSmsConfig.getTemplateId(), map);
} }
@Override @Override
@Restricted @Restricted
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) { public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
String messageStr = JSON.toJSONString(messages); String messageStr = JSON.toJSONString(messages);
return getSmsResponse(arrayToString(phones), messageStr, templateId); return getSmsResponse(arrayToString(phones), messageStr, templateId);
} }
private SmsResponse getSmsResponse(String phone, String message, String templateId) { private SmsResponse getSmsResponse(String phone, String message, String templateId) {
SmsResponse smsResponse = new SmsResponse(); SmsResponse smsResponse = new SmsResponse();
String requestUrl; String requestUrl;
String paramStr; String paramStr;
try { try {
requestUrl = AliyunUtils.generateSendSmsRequestUrl(this.alibabaSmsConfig, message, phone, templateId); requestUrl = AliyunUtils.generateSendSmsRequestUrl(this.alibabaSmsConfig, message, phone, templateId);
paramStr = AliyunUtils.generateParamBody(alibabaSmsConfig, phone, message, templateId); paramStr = AliyunUtils.generateParamBody(alibabaSmsConfig, phone, message, templateId);
} catch (Exception e) { } catch (Exception e) {
log.error("aliyun send message error", e); log.error("aliyun send message error", e);
throw new SmsBlendException(e.getMessage()); throw new SmsBlendException(e.getMessage());
} }
log.info("requestUrl {}", requestUrl); log.info("requestUrl {}", requestUrl);
http.post(requestUrl) http.post(requestUrl)
.addHeader("Content-Type", "application/x-www-form-urlencoded") .addHeader("Content-Type", "application/x-www-form-urlencoded")
.addBody(paramStr) .addBody(paramStr)
.onSuccess(((data, req, res) -> { .onSuccess(((data, req, res) -> {
JSONObject jsonBody = res.get(JSONObject.class); JSONObject jsonBody = res.get(JSONObject.class);
log.info(jsonBody.toJSONString()); log.info(jsonBody.toJSONString());
})) }))
.onError((ex, req, res) -> { .onError((ex, req, res) -> {
JSONObject jsonBody = res.get(JSONObject.class); JSONObject jsonBody = res.get(JSONObject.class);
log.info(jsonBody.toJSONString()); log.info(jsonBody.toJSONString());
}) })
.execute(); .execute();
return smsResponse; return smsResponse;
} }
@Override @Override
@Restricted @Restricted
public void sendMessageAsync(String phone, String message, CallBack callBack) { public void sendMessageAsync(String phone, String message, CallBack callBack) {
pool.execute(() -> { pool.execute(() -> {
SmsResponse smsResponse = sendMessage(phone, message); SmsResponse smsResponse = sendMessage(phone, message);
callBack.callBack(smsResponse); callBack.callBack(smsResponse);
}); });
} }
@Override @Override
@Restricted @Restricted
public void sendMessageAsync(String phone, String message) { public void sendMessageAsync(String phone, String message) {
pool.execute(() -> { pool.execute(() -> {
sendMessage(phone, message); sendMessage(phone, message);
}); });
} }
@Override @Override
@Restricted @Restricted
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) { public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
pool.execute(() -> { pool.execute(() -> {
SmsResponse smsResponse = sendMessage(phone, templateId, messages); SmsResponse smsResponse = sendMessage(phone, templateId, messages);
callBack.callBack(smsResponse); callBack.callBack(smsResponse);
}); });
} }
@Override @Override
@Restricted @Restricted
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) { public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
pool.execute(() -> { pool.execute(() -> {
sendMessage(phone, templateId, messages); sendMessage(phone, templateId, messages);
}); });
} }
@Override @Override
@Restricted @Restricted
public void delayedMessage(String phone, String message, Long delayedTime) { public void delayedMessage(String phone, String message, Long delayedTime) {
this.delayed.schedule(new TimerTask() { this.delayed.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
sendMessage(phone, message); sendMessage(phone, message);
} }
}, delayedTime); }, delayedTime);
} }
@Override @Override
@Restricted @Restricted
public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) { public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
this.delayed.schedule(new TimerTask() { this.delayed.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
sendMessage(phone, templateId, messages); sendMessage(phone, templateId, messages);
} }
}, delayedTime); }, delayedTime);
} }
@Override @Override
@Restricted @Restricted
public void delayMassTexting(List<String> phones, String message, Long delayedTime) { public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
this.delayed.schedule(new TimerTask() { this.delayed.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
massTexting(phones, message); massTexting(phones, message);
} }
}, delayedTime); }, delayedTime);
} }
@Override @Override
@Restricted @Restricted
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) { public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
this.delayed.schedule(new TimerTask() { this.delayed.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
massTexting(phones, templateId, messages); massTexting(phones, templateId, messages);
} }
}, delayedTime); }, delayedTime);
} }
private String arrayToString(List<String> list) { private String arrayToString(List<String> list) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (String s : list) { for (String s : list) {
sb.append(",").append("+86").append(s); sb.append(",").append("+86").append(s);
} }
return sb.substring(1); return sb.substring(1);
} }
} }

View File

@ -1,124 +1,124 @@
package org.dromara.sms4j.aliyun.utils; package org.dromara.sms4j.aliyun.utils;
import cn.hutool.core.codec.Base64; import cn.hutool.core.codec.Base64;
import org.dromara.sms4j.aliyun.config.AlibabaConfig; import org.dromara.sms4j.aliyun.config.AlibabaConfig;
import org.dromara.sms4j.comm.constant.Constant; import org.dromara.sms4j.comm.constant.Constant;
import javax.crypto.Mac; import javax.crypto.Mac;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
/** /**
* @author Richard * @author Richard
* @date 2023/4/20 16:55 * @date 2023/4/20 16:55
*/ */
public class AliyunUtils { public class AliyunUtils {
/** /**
* 加密方式 * 加密方式
*/ */
private static final String ALGORITHM = "HMAC-SHA1"; private static final String ALGORITHM = "HMAC-SHA1";
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
public static String generateSendSmsRequestUrl(AlibabaConfig alibabaConfig, String message, String phone, String templateId) throws Exception { public static String generateSendSmsRequestUrl(AlibabaConfig alibabaConfig, String message, String phone, String templateId) throws Exception {
// 这里一定要设置GMT时区 // 这里一定要设置GMT时区
sdf.setTimeZone(new SimpleTimeZone(0, "GMT")); sdf.setTimeZone(new SimpleTimeZone(0, "GMT"));
Map<String, String> paras = new HashMap<>(); Map<String, String> paras = new HashMap<>();
// 1. 公共请求参数 // 1. 公共请求参数
paras.put("SignatureMethod", ALGORITHM); paras.put("SignatureMethod", ALGORITHM);
paras.put("SignatureNonce", UUID.randomUUID().toString()); paras.put("SignatureNonce", UUID.randomUUID().toString());
paras.put("AccessKeyId", alibabaConfig.getAccessKeyId()); paras.put("AccessKeyId", alibabaConfig.getAccessKeyId());
paras.put("SignatureVersion", "1.0"); paras.put("SignatureVersion", "1.0");
paras.put("Timestamp", sdf.format(new Date())); paras.put("Timestamp", sdf.format(new Date()));
paras.put("Format", "JSON"); paras.put("Format", "JSON");
paras.put("Action", alibabaConfig.getAction()); paras.put("Action", alibabaConfig.getAction());
paras.put("Version", alibabaConfig.getVersion()); paras.put("Version", alibabaConfig.getVersion());
paras.put("RegionId", alibabaConfig.getRegionId()); paras.put("RegionId", alibabaConfig.getRegionId());
// 2. 业务API参数 // 2. 业务API参数
Map<String, String> paramMap = generateParamMap(alibabaConfig, phone, message, templateId); Map<String, String> paramMap = generateParamMap(alibabaConfig, phone, message, templateId);
// 3. 参数KEY排序 // 3. 参数KEY排序
Map<String, String> sortParas = new TreeMap<>(paras); Map<String, String> sortParas = new TreeMap<>(paras);
sortParas.putAll(paramMap); sortParas.putAll(paramMap);
// 4. 构造待签名的字符串 // 4. 构造待签名的字符串
Iterator<String> it = sortParas.keySet().iterator(); Iterator<String> it = sortParas.keySet().iterator();
StringBuilder sortQueryStringTmp = new StringBuilder(); StringBuilder sortQueryStringTmp = new StringBuilder();
while (it.hasNext()) { while (it.hasNext()) {
String key = it.next(); String key = it.next();
sortQueryStringTmp.append("&").append(specialUrlEncode(key)).append("=").append(specialUrlEncode(sortParas.get(key))); sortQueryStringTmp.append("&").append(specialUrlEncode(key)).append("=").append(specialUrlEncode(sortParas.get(key)));
} }
String stringToSign = "POST" + "&" + String stringToSign = "POST" + "&" +
specialUrlEncode("/") + "&" + specialUrlEncode("/") + "&" +
specialUrlEncode(sortQueryStringTmp.substring(1)); specialUrlEncode(sortQueryStringTmp.substring(1));
String signature = sign(alibabaConfig.getAccessKeySecret() + "&", stringToSign); String signature = sign(alibabaConfig.getAccessKeySecret() + "&", stringToSign);
// 5. 生成请求的url参数 // 5. 生成请求的url参数
StringBuilder sortQueryString = new StringBuilder(); StringBuilder sortQueryString = new StringBuilder();
it = paras.keySet().iterator(); it = paras.keySet().iterator();
while (it.hasNext()) { while (it.hasNext()) {
String key = it.next(); String key = it.next();
sortQueryString.append("&").append(specialUrlEncode(key)).append("=").append(specialUrlEncode(paras.get(key))); sortQueryString.append("&").append(specialUrlEncode(key)).append("=").append(specialUrlEncode(paras.get(key)));
} }
// 6.生成合法请求URL // 6.生成合法请求URL
return Constant.HTTPS_PREFIX + alibabaConfig.getRequestUrl() + "/?Signature=" + signature + sortQueryString; return Constant.HTTPS_PREFIX + alibabaConfig.getRequestUrl() + "/?Signature=" + signature + sortQueryString;
} }
/** /**
* url编码 * url编码
*/ */
private static String specialUrlEncode(String value) throws Exception { private static String specialUrlEncode(String value) throws Exception {
return URLEncoder.encode(value, StandardCharsets.UTF_8.name()).replace("+", "%20") return URLEncoder.encode(value, StandardCharsets.UTF_8.name()).replace("+", "%20")
.replace("*", "%2A").replace("%7E", "~"); .replace("*", "%2A").replace("%7E", "~");
} }
/** /**
* 生成签名 * 生成签名
* *
* @param accessSecret accessSecret * @param accessSecret accessSecret
* @param stringToSign 待生成签名的字符串 * @param stringToSign 待生成签名的字符串
*/ */
private static String sign(String accessSecret, String stringToSign) throws Exception { private static String sign(String accessSecret, String stringToSign) throws Exception {
Mac mac = Mac.getInstance("HmacSHA1"); Mac mac = Mac.getInstance("HmacSHA1");
mac.init(new javax.crypto.spec.SecretKeySpec(accessSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA1")); mac.init(new javax.crypto.spec.SecretKeySpec(accessSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA1"));
byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8)); byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
return Base64.encode(signData); return Base64.encode(signData);
} }
/** /**
* 生成请求body参数 * 生成请求body参数
* *
* @param alibabaConfig 配置数据 * @param alibabaConfig 配置数据
* @param phone 手机号 * @param phone 手机号
* @param message 短信内容 * @param message 短信内容
* @param templateId 模板id * @param templateId 模板id
*/ */
public static Map<String, String> generateParamMap(AlibabaConfig alibabaConfig, String phone, String message, String templateId) { public static Map<String, String> generateParamMap(AlibabaConfig alibabaConfig, String phone, String message, String templateId) {
Map<String, String> paramMap = new HashMap<>(); Map<String, String> paramMap = new HashMap<>();
paramMap.put("PhoneNumbers", phone); paramMap.put("PhoneNumbers", phone);
paramMap.put("SignName", alibabaConfig.getSignature()); paramMap.put("SignName", alibabaConfig.getSignature());
paramMap.put("TemplateParam", message); paramMap.put("TemplateParam", message);
paramMap.put("TemplateCode", templateId); paramMap.put("TemplateCode", templateId);
return paramMap; return paramMap;
} }
/** /**
* 生成请求参数body字符串 * 生成请求参数body字符串
* *
* @param alibabaConfig * @param alibabaConfig
* @param phone * @param phone
* @param message * @param message
* @param templateId * @param templateId
*/ */
public static String generateParamBody(AlibabaConfig alibabaConfig, String phone, String message, String templateId) throws Exception { public static String generateParamBody(AlibabaConfig alibabaConfig, String phone, String message, String templateId) throws Exception {
Map<String, String> paramMap = generateParamMap(alibabaConfig, phone, message, templateId); Map<String, String> paramMap = generateParamMap(alibabaConfig, phone, message, templateId);
StringBuilder sortQueryString = new StringBuilder(); StringBuilder sortQueryString = new StringBuilder();
for (String key : paramMap.keySet()) { for (String key : paramMap.keySet()) {
sortQueryString.append("&").append(specialUrlEncode(key)).append("=") sortQueryString.append("&").append(specialUrlEncode(key)).append("=")
.append(specialUrlEncode(paramMap.get(key))); .append(specialUrlEncode(paramMap.get(key)));
} }
return sortQueryString.substring(1); return sortQueryString.substring(1);
} }
} }

View File

@ -1,52 +1,52 @@
package org.dromara.sms4j.tencent.config; package org.dromara.sms4j.tencent.config;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import lombok.experimental.SuperBuilder; import lombok.experimental.SuperBuilder;
import org.dromara.sms4j.comm.config.BaseConfig; import org.dromara.sms4j.comm.config.BaseConfig;
@Data @Data
@SuperBuilder @SuperBuilder
@ToString(callSuper = true) @ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class TencentConfig extends BaseConfig { public class TencentConfig extends BaseConfig {
/** /**
* 短信sdkAppId * 短信sdkAppId
*/ */
private String sdkAppId; private String sdkAppId;
/** /**
* 地域信息默认为 ap-guangzhou * 地域信息默认为 ap-guangzhou
*/ */
@Builder.Default @Builder.Default
private String territory = "ap-guangzhou"; private String territory = "ap-guangzhou";
/** /**
* 请求超时时间 * 请求超时时间
*/ */
@Builder.Default @Builder.Default
private Integer connTimeout = 60; private Integer connTimeout = 60;
/** 请求地址*/ /** 请求地址*/
@Builder.Default @Builder.Default
private String requestUrl = "sms.tencentcloudapi.com"; private String requestUrl = "sms.tencentcloudapi.com";
/** /**
* 接口名称 * 接口名称
*/ */
@Builder.Default @Builder.Default
private String action = "SendSms"; private String action = "SendSms";
/** /**
* 接口版本 * 接口版本
*/ */
@Builder.Default @Builder.Default
private String version = "2021-01-11"; private String version = "2021-01-11";
/** /**
* 服务名 * 服务名
*/ */
@Builder.Default @Builder.Default
private String service = "sms"; private String service = "sms";
} }

View File

@ -1,52 +1,52 @@
package org.dromara.sms4j.tencent.config; package org.dromara.sms4j.tencent.config;
import org.dromara.sms4j.comm.factory.BeanFactory; import org.dromara.sms4j.comm.factory.BeanFactory;
import org.dromara.sms4j.tencent.service.TencentSmsImpl; import org.dromara.sms4j.tencent.service.TencentSmsImpl;
/** /**
* TencentSmsConfig * TencentSmsConfig
* <p> 建造腾讯云短信 * <p> 建造腾讯云短信
* *
* @author :Wind * @author :Wind
* 2023/4/8 16:05 * 2023/4/8 16:05
**/ **/
public class TencentSmsConfig { public class TencentSmsConfig {
private TencentSmsConfig() { private TencentSmsConfig() {
} }
private static TencentSmsImpl tencentSms; private static TencentSmsImpl tencentSms;
private static TencentSmsConfig tencentSmsConfig; private static TencentSmsConfig tencentSmsConfig;
/** /**
* 建造一个腾讯云的短信实现 * 建造一个腾讯云的短信实现
*/ */
public static TencentSmsImpl createTencentSms(TencentConfig tencentConfig) { public static TencentSmsImpl createTencentSms(TencentConfig tencentConfig) {
if (tencentSmsConfig == null) { if (tencentSmsConfig == null) {
tencentSmsConfig = new TencentSmsConfig(); tencentSmsConfig = new TencentSmsConfig();
} }
if (tencentSms == null) { if (tencentSms == null) {
tencentSms = new TencentSmsImpl( tencentSms = new TencentSmsImpl(
tencentConfig, tencentConfig,
BeanFactory.getExecutor(), BeanFactory.getExecutor(),
BeanFactory.getDelayedTime() BeanFactory.getDelayedTime()
); );
} }
return tencentSms; return tencentSms;
} }
/** /**
* 刷新对象 * 刷新对象
*/ */
public static TencentSmsImpl refresh(TencentConfig tencentConfig) { public static TencentSmsImpl refresh(TencentConfig tencentConfig) {
if (tencentSmsConfig == null) { if (tencentSmsConfig == null) {
tencentSmsConfig = new TencentSmsConfig(); tencentSmsConfig = new TencentSmsConfig();
} }
tencentSms = new TencentSmsImpl( tencentSms = new TencentSmsImpl(
tencentConfig, tencentConfig,
BeanFactory.getExecutor(), BeanFactory.getExecutor(),
BeanFactory.getDelayedTime() BeanFactory.getDelayedTime()
); );
return tencentSms; return tencentSms;
} }
} }

View File

@ -1,205 +1,205 @@
package org.dromara.sms4j.tencent.service; package org.dromara.sms4j.tencent.service;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.dtflys.forest.config.ForestConfiguration; import com.dtflys.forest.config.ForestConfiguration;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.SmsBlend; import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.callback.CallBack; import org.dromara.sms4j.api.callback.CallBack;
import org.dromara.sms4j.api.entity.SmsResponse; import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.comm.annotation.Restricted; import org.dromara.sms4j.comm.annotation.Restricted;
import org.dromara.sms4j.comm.constant.Constant; import org.dromara.sms4j.comm.constant.Constant;
import org.dromara.sms4j.comm.delayedTime.DelayedTime; import org.dromara.sms4j.comm.delayedTime.DelayedTime;
import org.dromara.sms4j.comm.exception.SmsBlendException; import org.dromara.sms4j.comm.exception.SmsBlendException;
import org.dromara.sms4j.comm.factory.BeanFactory; import org.dromara.sms4j.comm.factory.BeanFactory;
import org.dromara.sms4j.tencent.config.TencentConfig; import org.dromara.sms4j.tencent.config.TencentConfig;
import org.dromara.sms4j.tencent.utils.TencentUtils; import org.dromara.sms4j.tencent.utils.TencentUtils;
import java.util.*; import java.util.*;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@Slf4j @Slf4j
public class TencentSmsImpl implements SmsBlend { public class TencentSmsImpl implements SmsBlend {
private TencentConfig tencentSmsConfig; private TencentConfig tencentSmsConfig;
private Executor pool; private Executor pool;
private DelayedTime delayed; private DelayedTime delayed;
private final ForestConfiguration http = BeanFactory.getForestConfiguration(); private final ForestConfiguration http = BeanFactory.getForestConfiguration();
public TencentSmsImpl(TencentConfig tencentSmsConfig, Executor pool, DelayedTime delayed) { public TencentSmsImpl(TencentConfig tencentSmsConfig, Executor pool, DelayedTime delayed) {
this.tencentSmsConfig = tencentSmsConfig; this.tencentSmsConfig = tencentSmsConfig;
this.pool = pool; this.pool = pool;
this.delayed = delayed; this.delayed = delayed;
} }
@Override @Override
@Restricted @Restricted
public SmsResponse sendMessage(String phone, String message) { public SmsResponse sendMessage(String phone, String message) {
String[] split = message.split("&"); String[] split = message.split("&");
LinkedHashMap<String, String> map = new LinkedHashMap<>(); LinkedHashMap<String, String> map = new LinkedHashMap<>();
for (int i = 0; i < split.length; i++) { for (int i = 0; i < split.length; i++) {
map.put(String.valueOf(i), split[i]); map.put(String.valueOf(i), split[i]);
} }
return sendMessage(phone, tencentSmsConfig.getTemplateId(), map); return sendMessage(phone, tencentSmsConfig.getTemplateId(), map);
} }
@Override @Override
@Restricted @Restricted
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) { public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
List<String> list = new ArrayList<>(); List<String> list = new ArrayList<>();
for (Map.Entry<String, String> entry : messages.entrySet()) { for (Map.Entry<String, String> entry : messages.entrySet()) {
list.add(entry.getValue()); list.add(entry.getValue());
} }
String[] s = new String[list.size()]; String[] s = new String[list.size()];
return getSmsResponse(new String[]{"+86" + phone}, list.toArray(s), templateId); return getSmsResponse(new String[]{"+86" + phone}, list.toArray(s), templateId);
} }
@Override @Override
@Restricted @Restricted
public SmsResponse massTexting(List<String> phones, String message) { public SmsResponse massTexting(List<String> phones, String message) {
String[] split = message.split("&"); String[] split = message.split("&");
LinkedHashMap<String, String> map = new LinkedHashMap<>(); LinkedHashMap<String, String> map = new LinkedHashMap<>();
for (int i = 0; i < split.length; i++) { for (int i = 0; i < split.length; i++) {
map.put(String.valueOf(i), split[i]); map.put(String.valueOf(i), split[i]);
} }
return massTexting(phones, tencentSmsConfig.getTemplateId(), map); return massTexting(phones, tencentSmsConfig.getTemplateId(), map);
} }
@Override @Override
@Restricted @Restricted
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) { public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
List<String> list = new ArrayList<>(); List<String> list = new ArrayList<>();
for (Map.Entry<String, String> entry : messages.entrySet()) { for (Map.Entry<String, String> entry : messages.entrySet()) {
list.add(entry.getValue()); list.add(entry.getValue());
} }
String[] s = new String[list.size()]; String[] s = new String[list.size()];
return getSmsResponse(arrayToString(phones), list.toArray(s), templateId); return getSmsResponse(arrayToString(phones), list.toArray(s), templateId);
} }
private SmsResponse getSmsResponse(String[] phones, String[] messages, String templateId) { private SmsResponse getSmsResponse(String[] phones, String[] messages, String templateId) {
String timestamp = String.valueOf(System.currentTimeMillis() / 1000); String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
String signature; String signature;
try { try {
signature = TencentUtils.generateSignature(this.tencentSmsConfig, templateId, messages, phones, timestamp); signature = TencentUtils.generateSignature(this.tencentSmsConfig, templateId, messages, phones, timestamp);
} catch (Exception e) { } catch (Exception e) {
log.error("tencent send message error", e); log.error("tencent send message error", e);
throw new SmsBlendException(e.getMessage()); throw new SmsBlendException(e.getMessage());
} }
Map<String, Object> headsMap = TencentUtils.generateHeadsMap(signature, timestamp, tencentSmsConfig.getAction(), Map<String, Object> headsMap = TencentUtils.generateHeadsMap(signature, timestamp, tencentSmsConfig.getAction(),
tencentSmsConfig.getVersion(), tencentSmsConfig.getTerritory(), tencentSmsConfig.getRequestUrl()); tencentSmsConfig.getVersion(), tencentSmsConfig.getTerritory(), tencentSmsConfig.getRequestUrl());
Map<String, Object> requestBody = TencentUtils.generateRequestBody(phones, tencentSmsConfig.getSdkAppId(), Map<String, Object> requestBody = TencentUtils.generateRequestBody(phones, tencentSmsConfig.getSdkAppId(),
tencentSmsConfig.getSignature(), templateId, messages); tencentSmsConfig.getSignature(), templateId, messages);
SmsResponse smsResponse = new SmsResponse(); SmsResponse smsResponse = new SmsResponse();
String url = Constant.HTTPS_PREFIX + tencentSmsConfig.getRequestUrl(); String url = Constant.HTTPS_PREFIX + tencentSmsConfig.getRequestUrl();
http.post(url) http.post(url)
.addHeader(headsMap) .addHeader(headsMap)
.addBody(requestBody) .addBody(requestBody)
.onSuccess(((data, req, res) -> { .onSuccess(((data, req, res) -> {
JSONObject jsonBody = res.get(JSONObject.class); JSONObject jsonBody = res.get(JSONObject.class);
JSONObject response = jsonBody.getJSONObject("Response"); JSONObject response = jsonBody.getJSONObject("Response");
JSONArray sendStatusSet = response.getJSONArray("SendStatusSet"); JSONArray sendStatusSet = response.getJSONArray("SendStatusSet");
smsResponse.setBizId(sendStatusSet.getJSONObject(0).getString("SerialNo")); smsResponse.setBizId(sendStatusSet.getJSONObject(0).getString("SerialNo"));
smsResponse.setMessage(sendStatusSet.getJSONObject(0).getString("Message")); smsResponse.setMessage(sendStatusSet.getJSONObject(0).getString("Message"));
smsResponse.setCode(sendStatusSet.getJSONObject(0).getString("Code")); smsResponse.setCode(sendStatusSet.getJSONObject(0).getString("Code"));
})) }))
.onError((ex, req, res) -> { .onError((ex, req, res) -> {
JSONObject jsonBody = res.get(JSONObject.class); JSONObject jsonBody = res.get(JSONObject.class);
JSONObject response = jsonBody.getJSONObject("Response"); JSONObject response = jsonBody.getJSONObject("Response");
JSONArray sendStatusSet = response.getJSONArray("SendStatusSet"); JSONArray sendStatusSet = response.getJSONArray("SendStatusSet");
smsResponse.setErrMessage(sendStatusSet.getJSONObject(0).getString("Message")); smsResponse.setErrMessage(sendStatusSet.getJSONObject(0).getString("Message"));
smsResponse.setErrorCode(sendStatusSet.getJSONObject(0).getString("Code")); smsResponse.setErrorCode(sendStatusSet.getJSONObject(0).getString("Code"));
}) })
.execute(); .execute();
return smsResponse; return smsResponse;
} }
@Override @Override
@Restricted @Restricted
public void sendMessageAsync(String phone, String message, CallBack callBack) { public void sendMessageAsync(String phone, String message, CallBack callBack) {
pool.execute(() -> { pool.execute(() -> {
SmsResponse smsResponse = sendMessage(phone, message); SmsResponse smsResponse = sendMessage(phone, message);
callBack.callBack(smsResponse); callBack.callBack(smsResponse);
}); });
} }
@Override @Override
@Restricted @Restricted
public void sendMessageAsync(String phone, String message) { public void sendMessageAsync(String phone, String message) {
pool.execute(() -> { pool.execute(() -> {
sendMessage(phone, message); sendMessage(phone, message);
}); });
} }
@Override @Override
@Restricted @Restricted
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) { public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
pool.execute(() -> { pool.execute(() -> {
SmsResponse smsResponse = sendMessage(phone, templateId, messages); SmsResponse smsResponse = sendMessage(phone, templateId, messages);
callBack.callBack(smsResponse); callBack.callBack(smsResponse);
}); });
} }
@Override @Override
@Restricted @Restricted
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) { public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
pool.execute(() -> { pool.execute(() -> {
sendMessage(phone, templateId, messages); sendMessage(phone, templateId, messages);
}); });
} }
@Override @Override
@Restricted @Restricted
public void delayedMessage(String phone, String message, Long delayedTime) { public void delayedMessage(String phone, String message, Long delayedTime) {
this.delayed.schedule(new TimerTask() { this.delayed.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
sendMessage(phone, message); sendMessage(phone, message);
} }
}, delayedTime); }, delayedTime);
} }
@Override @Override
@Restricted @Restricted
public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) { public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
this.delayed.schedule(new TimerTask() { this.delayed.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
sendMessage(phone, templateId, messages); sendMessage(phone, templateId, messages);
} }
}, delayedTime); }, delayedTime);
} }
@Override @Override
@Restricted @Restricted
public void delayMassTexting(List<String> phones, String message, Long delayedTime) { public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
this.delayed.schedule(new TimerTask() { this.delayed.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
massTexting(phones, message); massTexting(phones, message);
} }
}, delayedTime); }, delayedTime);
} }
@Override @Override
@Restricted @Restricted
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) { public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
this.delayed.schedule(new TimerTask() { this.delayed.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
massTexting(phones, templateId, messages); massTexting(phones, templateId, messages);
} }
}, delayedTime); }, delayedTime);
} }
private String[] arrayToString(List<String> list) { private String[] arrayToString(List<String> list) {
String[] strs = new String[list.size()]; String[] strs = new String[list.size()];
List<String> toStr = new ArrayList<>(); List<String> toStr = new ArrayList<>();
for (String s : list) { for (String s : list) {
toStr.add("+86" + s); toStr.add("+86" + s);
} }
return toStr.toArray(strs); return toStr.toArray(strs);
} }
} }

View File

@ -1,138 +1,138 @@
package org.dromara.sms4j.tencent.utils; package org.dromara.sms4j.tencent.utils;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.tencent.config.TencentConfig; import org.dromara.sms4j.tencent.config.TencentConfig;
import javax.crypto.Mac; import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter; import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
/** /**
* @author Richard * @author Richard
* @date 2023-04-18 19:50 * @date 2023-04-18 19:50
*/ */
@Slf4j @Slf4j
public class TencentUtils { public class TencentUtils {
/** /**
* 加密方式 * 加密方式
*/ */
private static final String ALGORITHM = "TC3-HMAC-SHA256"; private static final String ALGORITHM = "TC3-HMAC-SHA256";
/** /**
* 请求方式 * 请求方式
*/ */
private static final String HTTP_REQUEST_METHOD = "POST"; private static final String HTTP_REQUEST_METHOD = "POST";
private static final String CT_JSON = "application/json; charset=utf-8"; private static final String CT_JSON = "application/json; charset=utf-8";
private static byte[] hmac256(byte[] key, String msg) throws Exception { private static byte[] hmac256(byte[] key, String msg) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256"); Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm()); SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
mac.init(secretKeySpec); mac.init(secretKeySpec);
return mac.doFinal(msg.getBytes(StandardCharsets.UTF_8)); return mac.doFinal(msg.getBytes(StandardCharsets.UTF_8));
} }
private static String sha256Hex(String s) throws Exception { private static String sha256Hex(String s) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256"); MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] d = md.digest(s.getBytes(StandardCharsets.UTF_8)); byte[] d = md.digest(s.getBytes(StandardCharsets.UTF_8));
return DatatypeConverter.printHexBinary(d).toLowerCase(); return DatatypeConverter.printHexBinary(d).toLowerCase();
} }
/** /**
* 生成腾讯云发送短信接口签名 * 生成腾讯云发送短信接口签名
* *
* @param templateId 模板id * @param templateId 模板id
* @param messages 短信内容 * @param messages 短信内容
* @param phones 手机号 * @param phones 手机号
* @param timestamp 时间戳 * @param timestamp 时间戳
* @throws Exception * @throws Exception
*/ */
public static String generateSignature(TencentConfig tencentConfig, String templateId, String[] messages, String[] phones, public static String generateSignature(TencentConfig tencentConfig, String templateId, String[] messages, String[] phones,
String timestamp) throws Exception { String timestamp) throws Exception {
// ************* 步骤 1拼接规范请求串 ************* // ************* 步骤 1拼接规范请求串 *************
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC")); sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = sdf.format(new Date(Long.parseLong(timestamp + "000"))); String date = sdf.format(new Date(Long.parseLong(timestamp + "000")));
String canonicalUri = "/"; String canonicalUri = "/";
String canonicalQueryString = ""; String canonicalQueryString = "";
String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + tencentConfig.getRequestUrl() + "\n"; String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + tencentConfig.getRequestUrl() + "\n";
String signedHeaders = "content-type;host"; String signedHeaders = "content-type;host";
HashMap<String, Object> params = new HashMap<>(); HashMap<String, Object> params = new HashMap<>();
// 实际调用需要更新参数这里仅作为演示签名验证通过的例子 // 实际调用需要更新参数这里仅作为演示签名验证通过的例子
params.put("PhoneNumberSet", phones); params.put("PhoneNumberSet", phones);
params.put("SmsSdkAppId", tencentConfig.getSdkAppId()); params.put("SmsSdkAppId", tencentConfig.getSdkAppId());
params.put("SignName", tencentConfig.getSignature()); params.put("SignName", tencentConfig.getSignature());
params.put("TemplateId", templateId); params.put("TemplateId", templateId);
params.put("TemplateParamSet", messages); params.put("TemplateParamSet", messages);
String payload = JSON.toJSONString(params); String payload = JSON.toJSONString(params);
String hashedRequestPayload = sha256Hex(payload); String hashedRequestPayload = sha256Hex(payload);
String canonicalRequest = HTTP_REQUEST_METHOD + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n" String canonicalRequest = HTTP_REQUEST_METHOD + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload; + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
// ************* 步骤 2拼接待签名字符串 ************* // ************* 步骤 2拼接待签名字符串 *************
String credentialScope = date + "/" + tencentConfig.getService() + "/" + "tc3_request"; String credentialScope = date + "/" + tencentConfig.getService() + "/" + "tc3_request";
String hashedCanonicalRequest = sha256Hex(canonicalRequest); String hashedCanonicalRequest = sha256Hex(canonicalRequest);
String stringToSign = ALGORITHM + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest; String stringToSign = ALGORITHM + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
// ************* 步骤 3计算签名 ************* // ************* 步骤 3计算签名 *************
byte[] secretDate = hmac256(("TC3" + tencentConfig.getAccessKeySecret()).getBytes(StandardCharsets.UTF_8), date); byte[] secretDate = hmac256(("TC3" + tencentConfig.getAccessKeySecret()).getBytes(StandardCharsets.UTF_8), date);
byte[] secretService = hmac256(secretDate, tencentConfig.getService()); byte[] secretService = hmac256(secretDate, tencentConfig.getService());
byte[] secretSigning = hmac256(secretService, "tc3_request"); byte[] secretSigning = hmac256(secretService, "tc3_request");
String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase(); String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();
// ************* 步骤 4拼接 Authorization ************* // ************* 步骤 4拼接 Authorization *************
return ALGORITHM + " " + "Credential=" + tencentConfig.getAccessKeyId() + "/" + credentialScope + ", " return ALGORITHM + " " + "Credential=" + tencentConfig.getAccessKeyId() + "/" + credentialScope + ", "
+ "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature; + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
} }
/** /**
* 生成腾讯云短信请求头map * 生成腾讯云短信请求头map
* *
* @param authorization 签名信息 * @param authorization 签名信息
* @param timestamp 时间戳 * @param timestamp 时间戳
* @param action 接口名称 * @param action 接口名称
* @param version 接口版本 * @param version 接口版本
* @param territory 服务器地区 * @param territory 服务器地区
* @param requestUrl 请求地址 * @param requestUrl 请求地址
*/ */
public static Map<String, Object> generateHeadsMap(String authorization, String timestamp, String action, public static Map<String, Object> generateHeadsMap(String authorization, String timestamp, String action,
String version, String territory, String requestUrl) { String version, String territory, String requestUrl) {
Map<String, Object> headers = new HashMap<>(); Map<String, Object> headers = new HashMap<>();
headers.put("Authorization", authorization); headers.put("Authorization", authorization);
headers.put("Content-Type", CT_JSON); headers.put("Content-Type", CT_JSON);
headers.put("Host", requestUrl); headers.put("Host", requestUrl);
headers.put("X-TC-Action", action); headers.put("X-TC-Action", action);
headers.put("X-TC-Timestamp", timestamp); headers.put("X-TC-Timestamp", timestamp);
headers.put("X-TC-Version", version); headers.put("X-TC-Version", version);
headers.put("X-TC-Region", territory); headers.put("X-TC-Region", territory);
return headers; return headers;
} }
/** /**
* 生成腾讯云短信请求body * 生成腾讯云短信请求body
* *
* @param phones 手机号 * @param phones 手机号
* @param sdkAppId appid * @param sdkAppId appid
* @param signatureName 短信签名 * @param signatureName 短信签名
* @param templateId 模板id * @param templateId 模板id
* @param templateParamSet 模板参数 * @param templateParamSet 模板参数
* @return * @return
*/ */
public static Map<String, Object> generateRequestBody(String[] phones, String sdkAppId, String signatureName, public static Map<String, Object> generateRequestBody(String[] phones, String sdkAppId, String signatureName,
String templateId, String[] templateParamSet) { String templateId, String[] templateParamSet) {
Map<String, Object> requestBody = new HashMap<>(); Map<String, Object> requestBody = new HashMap<>();
requestBody.put("PhoneNumberSet", phones); requestBody.put("PhoneNumberSet", phones);
requestBody.put("SmsSdkAppId", sdkAppId); requestBody.put("SmsSdkAppId", sdkAppId);
requestBody.put("SignName", signatureName); requestBody.put("SignName", signatureName);
requestBody.put("TemplateId", templateId); requestBody.put("TemplateId", templateId);
requestBody.put("TemplateParamSet", templateParamSet); requestBody.put("TemplateParamSet", templateParamSet);
return requestBody; return requestBody;
} }
} }

View File

@ -9,7 +9,6 @@ import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.comm.annotation.Restricted; import org.dromara.sms4j.comm.annotation.Restricted;
import org.dromara.sms4j.comm.delayedTime.DelayedTime; import org.dromara.sms4j.comm.delayedTime.DelayedTime;
import org.dromara.sms4j.comm.exception.SmsBlendException; import org.dromara.sms4j.comm.exception.SmsBlendException;
import org.dromara.sms4j.comm.utils.http.HttpJsonTool;
import org.dromara.sms4j.unisms.config.UniConfig; import org.dromara.sms4j.unisms.config.UniConfig;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;

View File

@ -10,13 +10,10 @@
</parent> </parent>
<artifactId>sms4j-spring-boot-starter</artifactId> <artifactId>sms4j-spring-boot-starter</artifactId>
<name>sms4j-spring-boot-starter</name>
<description>sms4j-spring-boot-starter</description>
<version>${revision}</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<properties> <name>sms4j-spring-boot-starter</name>
</properties> <description>sms4j-spring-boot-starter</description>
<dependencies> <dependencies>
<dependency> <dependency>
@ -37,9 +34,4 @@
<artifactId>spring-boot-starter</artifactId> <artifactId>spring-boot-starter</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
</plugins>
</build>
</project> </project>

View File

@ -1,34 +0,0 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms4j-tencent</artifactId>
<name>sms4j-tencent</name>
<description>sms4j-tencent</description>
<version>${revision}</version>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-comm</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,41 +0,0 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms4j-unisms</artifactId>
<name>sms4j-unisms</name>
<description>sms4j-unisms</description>
<version>${revision}</version>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>com.apistd.uni</groupId>
<artifactId>uni-sdk</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-comm</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,30 +0,0 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>sms4j-yunpian</artifactId>
<name>sms4j-yunpian</name>
<description>sms4j-yunpian</description>
<version>${revision}</version>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-comm</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-api</artifactId>
</dependency>
</dependencies>
</project>