mirror of
https://gitee.com/dromara/sms4j.git
synced 2025-12-07 17:38:38 +08:00
commit
6570e43ad9
@ -1,9 +1,9 @@
|
|||||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sms4j v2.0.2</h1>
|
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sms4j v2.1.0</h1>
|
||||||
<h4 align="center" style="margin: 30px 0 30px; font-weight: bold;">sms4j -- 让发送短信变的更简单</h4>
|
<h4 align="center" style="margin: 30px 0 30px; font-weight: bold;">sms4j -- 让发送短信变的更简单</h4>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://gitee.com/dromara/sms4j/stargazers"><img src="https://gitee.com/dromara/sms4j/badge/star.svg?theme=gvp"></a>
|
<a href="https://gitee.com/dromara/sms4j/stargazers"><img src="https://gitee.com/dromara/sms4j/badge/star.svg?theme=gvp"></a>
|
||||||
<a href="https://gitee.com/dromara/sms4j/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-green"></a>
|
<a href="https://gitee.com/dromara/sms4j/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-green"></a>
|
||||||
<a href="https://gitee.com/dromara/sms4j"><img src="https://img.shields.io/badge/version-v2.0.2-blue"></a>
|
<a href="https://gitee.com/dromara/sms4j"><img src="https://img.shields.io/badge/version-v2.1.0-blue"></a>
|
||||||
</p>
|
</p>
|
||||||
<img src="/public/logo.png">
|
<img src="/public/logo.png">
|
||||||
|
|
||||||
@ -28,6 +28,7 @@
|
|||||||
- **京东云国内短信**
|
- **京东云国内短信**
|
||||||
- **容联云国内短信**
|
- **容联云国内短信**
|
||||||
- **亿美软通国内短信**
|
- **亿美软通国内短信**
|
||||||
|
- **天翼云短信**
|
||||||
- **合一短信**
|
- **合一短信**
|
||||||
- **云片短信**
|
- **云片短信**
|
||||||
|
|
||||||
|
|||||||
26
pom.xml
26
pom.xml
@ -18,6 +18,8 @@
|
|||||||
<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-solon-plugin</module>
|
||||||
|
<module>sms4j-spring-boot-example</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<!-- 开源协议 Apache 2.0 -->
|
<!-- 开源协议 Apache 2.0 -->
|
||||||
@ -47,17 +49,16 @@
|
|||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<spring.boot.version>2.7.11</spring.boot.version>
|
<revision>2.1.0-SNAPSHOT</revision>
|
||||||
<revision>2.0.2</revision>
|
|
||||||
<aliyun.version>2.0.23</aliyun.version>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<tencent.version>3.1.622</tencent.version>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<unisms.version>0.0.4</unisms.version>
|
<spring.boot.version>2.7.12</spring.boot.version>
|
||||||
|
<solon.version>2.2.0</solon.version>
|
||||||
|
<redisson.version>3.17.0</redisson.version>
|
||||||
<jdcloud.version>1.3.3</jdcloud.version>
|
<jdcloud.version>1.3.3</jdcloud.version>
|
||||||
<json.version>2.0.15</json.version>
|
|
||||||
<okhttp.version>3.14.9</okhttp.version>
|
|
||||||
<forest.version>1.5.30</forest.version>
|
<forest.version>1.5.30</forest.version>
|
||||||
<hutool.version>5.8.16</hutool.version>
|
<hutool.version>5.8.18</hutool.version>
|
||||||
<okhttp.version>3.14.9</okhttp.version>
|
|
||||||
<xmlblend.version>2.3.0</xmlblend.version>
|
<xmlblend.version>2.3.0</xmlblend.version>
|
||||||
<activation.version>1.1.1</activation.version>
|
<activation.version>1.1.1</activation.version>
|
||||||
</properties>
|
</properties>
|
||||||
@ -119,13 +120,6 @@
|
|||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 阿里JSON解析器 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.alibaba</groupId>
|
|
||||||
<artifactId>fastjson</artifactId>
|
|
||||||
<version>${json.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--Forest依赖 声明式HTTP客户端框架-->
|
<!--Forest依赖 声明式HTTP客户端框架-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.dtflys.forest</groupId>
|
<groupId>com.dtflys.forest</groupId>
|
||||||
|
|||||||
@ -0,0 +1,211 @@
|
|||||||
|
package org.dromara.sms4j.api;
|
||||||
|
|
||||||
|
import com.dtflys.forest.config.ForestConfiguration;
|
||||||
|
import org.dromara.sms4j.api.callback.CallBack;
|
||||||
|
import org.dromara.sms4j.api.entity.SmsResponse;
|
||||||
|
import org.dromara.sms4j.comm.annotation.Restricted;
|
||||||
|
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
|
||||||
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
public abstract class AbstractSmsBlend implements SmsBlend{
|
||||||
|
|
||||||
|
protected final Executor pool;
|
||||||
|
protected final DelayedTime delayed;
|
||||||
|
|
||||||
|
protected final ForestConfiguration http = BeanFactory.getForestConfiguration();
|
||||||
|
protected AbstractSmsBlend(Executor pool, DelayedTime delayed) {
|
||||||
|
this.pool = pool;
|
||||||
|
this.delayed = delayed;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractSmsBlend() {
|
||||||
|
this.pool = BeanFactory.getExecutor();
|
||||||
|
this.delayed = BeanFactory.getDelayedTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:发送固定消息模板短信
|
||||||
|
* <p>此方法将使用配置文件中预设的短信模板进行短信发送
|
||||||
|
* <p>该方法指定的模板变量只能存在一个(配置文件中)
|
||||||
|
* <p>如使用的是腾讯的短信,参数字符串中可以同时存在多个参数,使用 & 分隔例如:您的验证码为{1}在{2}分钟内有效,可以传为 message="xxxx"+"&"+"5"
|
||||||
|
* sendMessage
|
||||||
|
*
|
||||||
|
* @param phone 接收短信的手机号
|
||||||
|
* message 消息内容
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract SmsResponse sendMessage(String phone, String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:使用自定义模板发送短信
|
||||||
|
* sendMessage
|
||||||
|
*
|
||||||
|
* @param templateId 模板id
|
||||||
|
* @param messages key为模板变量名称 value为模板变量值
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:群发固定模板短信
|
||||||
|
* massTexting
|
||||||
|
*
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract SmsResponse massTexting(List<String> phones, String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:使用自定义模板群发短信
|
||||||
|
* massTexting
|
||||||
|
*
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:异步短信发送,固定消息模板短信
|
||||||
|
* sendMessageAsync
|
||||||
|
*
|
||||||
|
* @param phone 要发送的号码
|
||||||
|
* @param message 发送内容
|
||||||
|
* @param callBack 回调
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
@Restricted
|
||||||
|
public final void sendMessageAsync(String phone, String message, CallBack callBack){
|
||||||
|
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, message), pool);
|
||||||
|
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:异步发送短信,不关注发送结果
|
||||||
|
* sendMessageAsync
|
||||||
|
*
|
||||||
|
* @param phone 要发送的号码
|
||||||
|
* @param message 发送内容
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
@Restricted
|
||||||
|
public final void sendMessageAsync(String phone, String message){
|
||||||
|
pool.execute(() -> {
|
||||||
|
sendMessage(phone, message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:异步短信发送,使用自定义模板发送短信
|
||||||
|
* sendMessage
|
||||||
|
*
|
||||||
|
* @param templateId 模板id
|
||||||
|
* @param messages key为模板变量名称 value为模板变量值
|
||||||
|
* @param callBack 回调
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Restricted
|
||||||
|
public final void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack){
|
||||||
|
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone,templateId, messages), pool);
|
||||||
|
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:异步短信发送,使用自定义模板发送短信,不关注发送结果
|
||||||
|
* sendMessageAsync
|
||||||
|
*
|
||||||
|
* @param templateId 模板id
|
||||||
|
* @param messages key为模板变量名称 value为模板变量值
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
@Restricted
|
||||||
|
public final void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages){
|
||||||
|
pool.execute(() -> {
|
||||||
|
sendMessage(phone, templateId, messages);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:使用固定模板发送延时短信
|
||||||
|
* delayedMessage
|
||||||
|
*
|
||||||
|
* @param phone 接收短信的手机号
|
||||||
|
* @param message 要发送的短信
|
||||||
|
* @param delayedTime 延迟时间
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
@Restricted
|
||||||
|
public final void delayedMessage(String phone, String message, Long delayedTime){
|
||||||
|
this.delayed.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
sendMessage(phone, message);
|
||||||
|
}
|
||||||
|
}, delayedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:使用自定义模板发送定时短信 sendMessage
|
||||||
|
* delayedMessage
|
||||||
|
*
|
||||||
|
* @param templateId 模板id
|
||||||
|
* @param messages key为模板变量名称 value为模板变量值
|
||||||
|
* @param phone 要发送的手机号
|
||||||
|
* @param delayedTime 延迟的时间
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
@Restricted
|
||||||
|
public final void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime){
|
||||||
|
this.delayed.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
sendMessage(phone, templateId, messages);
|
||||||
|
}
|
||||||
|
}, delayedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:群发延迟短信
|
||||||
|
* delayMassTexting
|
||||||
|
*
|
||||||
|
* @param phones 要群体发送的手机号码
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
@Restricted
|
||||||
|
public final void delayMassTexting(List<String> phones, String message, Long delayedTime){
|
||||||
|
this.delayed.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
massTexting(phones, message);
|
||||||
|
}
|
||||||
|
}, delayedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:使用自定义模板发送群体延迟短信
|
||||||
|
* delayMassTexting
|
||||||
|
*
|
||||||
|
* @param phones 要群体发送的手机号码
|
||||||
|
* @param templateId 模板id
|
||||||
|
* @param messages key为模板变量名称 value为模板变量值
|
||||||
|
* @param delayedTime 延迟的时间
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
@Restricted
|
||||||
|
public final void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime){
|
||||||
|
this.delayed.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
massTexting(phones, templateId, messages);
|
||||||
|
}
|
||||||
|
}, delayedTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,136 +6,35 @@ import org.dromara.sms4j.api.entity.SmsResponse;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface SmsBlend {
|
/**
|
||||||
|
* SmsBlend
|
||||||
/**
|
* <p> 通用接口,定义国内短信方法
|
||||||
* <p>说明:发送固定消息模板短信
|
|
||||||
* <p>此方法将使用配置文件中预设的短信模板进行短信发送
|
|
||||||
* <p>该方法指定的模板变量只能存在一个(配置文件中)
|
|
||||||
* <p>如使用的是腾讯的短信,参数字符串中可以同时存在多个参数,使用 & 分隔例如:您的验证码为{1}在{2}分钟内有效,可以传为 message="xxxx"+"&"+"5"
|
|
||||||
* sendMessage
|
|
||||||
*
|
|
||||||
* @param phone 接收短信的手机号
|
|
||||||
* message 消息内容
|
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
* 2023/5/16 16:03
|
||||||
|
**/
|
||||||
|
public interface SmsBlend {
|
||||||
|
|
||||||
SmsResponse sendMessage(String phone, String message);
|
SmsResponse sendMessage(String phone, String message);
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>说明:使用自定义模板发送短信
|
|
||||||
* sendMessage
|
|
||||||
*
|
|
||||||
* @param templateId 模板id
|
|
||||||
* @param messages key为模板变量名称 value为模板变量值
|
|
||||||
* @author :Wind
|
|
||||||
*/
|
|
||||||
|
|
||||||
SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages);
|
SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages);
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>说明:群发固定模板短信
|
|
||||||
* massTexting
|
|
||||||
*
|
|
||||||
* @author :Wind
|
|
||||||
*/
|
|
||||||
|
|
||||||
SmsResponse massTexting(List<String> phones, String message);
|
SmsResponse massTexting(List<String> phones, String message);
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>说明:使用自定义模板群发短信
|
|
||||||
* massTexting
|
|
||||||
*
|
|
||||||
* @author :Wind
|
|
||||||
*/
|
|
||||||
|
|
||||||
SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages);
|
SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages);
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>说明:异步短信发送,固定消息模板短信
|
|
||||||
* sendMessageAsync
|
|
||||||
*
|
|
||||||
* @param phone 要发送的号码
|
|
||||||
* @param message 发送内容
|
|
||||||
* @param callBack 回调
|
|
||||||
* @author :Wind
|
|
||||||
*/
|
|
||||||
|
|
||||||
void sendMessageAsync(String phone, String message, CallBack callBack);
|
void sendMessageAsync(String phone, String message, CallBack callBack);
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>说明:异步发送短信,不关注发送结果
|
|
||||||
* sendMessageAsync
|
|
||||||
*
|
|
||||||
* @param phone 要发送的号码
|
|
||||||
* @param message 发送内容
|
|
||||||
* @author :Wind
|
|
||||||
*/
|
|
||||||
void sendMessageAsync(String phone, String message);
|
void sendMessageAsync(String phone, String message);
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>说明:异步短信发送,使用自定义模板发送短信
|
|
||||||
* sendMessage
|
|
||||||
*
|
|
||||||
* @param templateId 模板id
|
|
||||||
* @param messages key为模板变量名称 value为模板变量值
|
|
||||||
* @param callBack 回调
|
|
||||||
* @author :Wind
|
|
||||||
*/
|
|
||||||
|
|
||||||
void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack);
|
void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack);
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>说明:异步短信发送,使用自定义模板发送短信,不关注发送结果
|
|
||||||
* sendMessageAsync
|
|
||||||
*
|
|
||||||
* @param templateId 模板id
|
|
||||||
* @param messages key为模板变量名称 value为模板变量值
|
|
||||||
* @author :Wind
|
|
||||||
*/
|
|
||||||
void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages);
|
void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages);
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>说明:使用固定模板发送延时短信
|
|
||||||
* delayedMessage
|
|
||||||
*
|
|
||||||
* @param phone 接收短信的手机号
|
|
||||||
* @param message 要发送的短信
|
|
||||||
* @param delayedTime 延迟时间
|
|
||||||
* @author :Wind
|
|
||||||
*/
|
|
||||||
void delayedMessage(String phone, String message, Long delayedTime);
|
void delayedMessage(String phone, String message, Long delayedTime);
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>说明:使用自定义模板发送定时短信 sendMessage
|
|
||||||
* delayedMessage
|
|
||||||
*
|
|
||||||
* @param templateId 模板id
|
|
||||||
* @param messages key为模板变量名称 value为模板变量值
|
|
||||||
* @param phone 要发送的手机号
|
|
||||||
* @param delayedTime 延迟的时间
|
|
||||||
* @author :Wind
|
|
||||||
*/
|
|
||||||
void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime);
|
void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime);
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>说明:群发延迟短信
|
|
||||||
* delayMassTexting
|
|
||||||
*
|
|
||||||
* @param phones 要群体发送的手机号码
|
|
||||||
* @author :Wind
|
|
||||||
*/
|
|
||||||
void delayMassTexting(List<String> phones, String message, Long delayedTime);
|
void delayMassTexting(List<String> phones, String message, Long delayedTime);
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>说明:使用自定义模板发送群体延迟短信
|
|
||||||
* delayMassTexting
|
|
||||||
*
|
|
||||||
* @param phones 要群体发送的手机号码
|
|
||||||
* @param templateId 模板id
|
|
||||||
* @param messages key为模板变量名称 value为模板变量值
|
|
||||||
* @param delayedTime 延迟的时间
|
|
||||||
* @author :Wind
|
|
||||||
*/
|
|
||||||
void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime);
|
void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
package org.dromara.sms4j.api.smsProxy;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.comm.config.SmsConfig;
|
||||||
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsUtil;
|
||||||
|
import org.dromara.sms4j.comm.utils.TimeExpiredPoolCache;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class RestrictedProcess {
|
||||||
|
static Long minTimer = 60 * 1000L;
|
||||||
|
static Long accTimer = 24 * 60 * 60 * 1000L;
|
||||||
|
public SmsBlendException process(SmsConfig config, String args) throws Exception{
|
||||||
|
TimeExpiredPoolCache instance = TimeExpiredPoolCache.getInstance();//缓存实例
|
||||||
|
Integer accountMax = config.getAccountMax();//每日最大发送量
|
||||||
|
Integer minuteMax = config.getMinuteMax();//每分钟最大发送量
|
||||||
|
if (SmsUtil.isNotEmpty(accountMax)) { //是否配置了每日限制
|
||||||
|
Integer i = instance.get(args + "max");
|
||||||
|
if (SmsUtil.isEmpty(i)) {
|
||||||
|
instance.put(args + "max", 1, accTimer);
|
||||||
|
} else if (i > accountMax) {
|
||||||
|
log.info("The phone:" + args + ",number of short messages reached the maximum today");
|
||||||
|
return new SmsBlendException("The phone:" + args + ",number of short messages reached the maximum today");
|
||||||
|
} else {
|
||||||
|
instance.put(args + "max", i + 1, accTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (SmsUtil.isNotEmpty(minuteMax)) { //是否配置了每分钟最大限制
|
||||||
|
Integer o = instance.get(args);
|
||||||
|
if (SmsUtil.isNotEmpty(o)) {
|
||||||
|
if (o < minuteMax) {
|
||||||
|
instance.put(args, o + 1, minTimer);
|
||||||
|
} else {
|
||||||
|
log.info("The phone:", args + " Text messages are sent too often!");
|
||||||
|
return new SmsBlendException("The phone:", args + " Text messages are sent too often!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
instance.put(args, 1, minTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
package org.dromara.sms4j.api.smsProxy;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.api.SmsBlend;
|
||||||
|
import org.dromara.sms4j.comm.config.SmsConfig;
|
||||||
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class SmsInvocationHandler implements InvocationHandler {
|
||||||
|
private SmsBlend smsBlend;
|
||||||
|
private SmsConfig config;
|
||||||
|
private static RestrictedProcess restrictedProcess = new RestrictedProcess();
|
||||||
|
|
||||||
|
private SmsInvocationHandler(SmsBlend smsBlend, SmsConfig config) {
|
||||||
|
this.smsBlend = smsBlend;
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SmsInvocationHandler newSmsInvocationHandler(SmsBlend smsBlend, SmsConfig config){
|
||||||
|
return new SmsInvocationHandler(smsBlend,config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
|
||||||
|
Object result = null;
|
||||||
|
if ("sendMessage".equals(method.getName()) || "massTexting".equals(method.getName())) {
|
||||||
|
//取手机号作为参数
|
||||||
|
String phone = (String) objects[0];
|
||||||
|
SmsBlendException smsBlendException = restrictedProcess.process(config,phone);
|
||||||
|
if (!Objects.isNull(smsBlendException)) {
|
||||||
|
throw smsBlendException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = method.invoke(smsBlend, objects);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 restrictedProcess
|
||||||
|
*/
|
||||||
|
public static void setRestrictedProcess(RestrictedProcess restrictedProcess) {
|
||||||
|
SmsInvocationHandler.restrictedProcess = restrictedProcess;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package org.dromara.sms4j.api.universal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SupplierConfig
|
||||||
|
* <p> 空接口,无含义,只为标定配置类的额外类型
|
||||||
|
* @author :Wind
|
||||||
|
* 2023/5/16 15:14
|
||||||
|
**/
|
||||||
|
public interface SupplierConfig {
|
||||||
|
}
|
||||||
@ -1 +0,0 @@
|
|||||||
|
|
||||||
@ -1,136 +0,0 @@
|
|||||||
package org.dromara.sms4j.autoimmit.aop;
|
|
||||||
|
|
||||||
|
|
||||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
|
||||||
import org.dromara.sms4j.comm.config.SmsConfig;
|
|
||||||
import org.dromara.sms4j.autoimmit.utils.RedisUtils;
|
|
||||||
import org.dromara.sms4j.comm.utils.SmsUtil;
|
|
||||||
import org.dromara.sms4j.comm.utils.TimeExpiredPoolCache;
|
|
||||||
import org.dromara.sms4j.autoimmit.utils.SpringUtil;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
|
||||||
import org.aspectj.lang.annotation.Around;
|
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
|
||||||
import org.aspectj.lang.annotation.Pointcut;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
@Aspect
|
|
||||||
@Slf4j
|
|
||||||
public class AopAdvice {
|
|
||||||
|
|
||||||
private static final Long minTimer = 60 * 1000L;
|
|
||||||
private static final Long accTimer = 24 * 60 * 60 * 1000L;
|
|
||||||
|
|
||||||
private static final String REDIS_KEY = "sms:restricted:";
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private SmsConfig config;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private SpringUtil springUtil;
|
|
||||||
|
|
||||||
|
|
||||||
@Pointcut("@annotation(org.dromara.sms4j.comm.annotation.Restricted)")
|
|
||||||
public void restricted() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Around("restricted()")
|
|
||||||
public Object restrictedSendMessage(ProceedingJoinPoint p) throws Throwable {
|
|
||||||
|
|
||||||
String args = "";
|
|
||||||
ArrayList<String> argsList = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
args = (String) p.getArgs()[0];
|
|
||||||
} catch (Exception e) {
|
|
||||||
for (Object o : (ArrayList<?>) p.getArgs()[0]) {
|
|
||||||
argsList.add((String) o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SmsBlendException process = redisProcess(args);
|
|
||||||
if (process != null) {
|
|
||||||
throw process;
|
|
||||||
}
|
|
||||||
argsList.forEach(f -> {
|
|
||||||
SmsBlendException proce = null;
|
|
||||||
try {
|
|
||||||
proce = redisProcess(f);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error(e.getMessage());
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
if (proce != null) {
|
|
||||||
throw proce;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return p.proceed();
|
|
||||||
}
|
|
||||||
|
|
||||||
private SmsBlendException process(String args) throws Exception {
|
|
||||||
TimeExpiredPoolCache instance = TimeExpiredPoolCache.getInstance();//缓存实例
|
|
||||||
Integer accountMax = config.getAccountMax();//每日最大发送量
|
|
||||||
Integer minuteMax = config.getMinuteMax();//每分钟最大发送量
|
|
||||||
if (SmsUtil.isNotEmpty(accountMax)) { //是否配置了每日限制
|
|
||||||
Integer i = instance.get(args + "max");
|
|
||||||
if (SmsUtil.isEmpty(i)) {
|
|
||||||
instance.put(args + "max", 1, accTimer);
|
|
||||||
} else if (i > accountMax) {
|
|
||||||
log.info("The phone:"+args +",number of short messages reached the maximum today");
|
|
||||||
return new SmsBlendException("The phone:"+args +",number of short messages reached the maximum today");
|
|
||||||
} else {
|
|
||||||
instance.put(args + "max", i + 1, accTimer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (SmsUtil.isNotEmpty(minuteMax)) { //是否配置了每分钟最大限制
|
|
||||||
Integer o = instance.get(args);
|
|
||||||
if (SmsUtil.isNotEmpty(o)) {
|
|
||||||
if (o < minuteMax) {
|
|
||||||
instance.put(args, o + 1, minTimer);
|
|
||||||
} else {
|
|
||||||
log.info("The phone:"+args +",number of short messages reached the maximum today");
|
|
||||||
return new SmsBlendException("The phone:", args + " Text messages are sent too often!");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
instance.put(args, 1, minTimer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SmsBlendException redisProcess(String args) throws Exception{
|
|
||||||
if (config.getRedisCache().equals("false")){
|
|
||||||
return process(args);
|
|
||||||
}
|
|
||||||
RedisUtils redis = SpringUtil.getBean(RedisUtils.class);
|
|
||||||
|
|
||||||
Integer accountMax = config.getAccountMax();//每日最大发送量
|
|
||||||
Integer minuteMax = config.getMinuteMax();//每分钟最大发送量
|
|
||||||
if (SmsUtil.isNotEmpty(accountMax)) { //是否配置了每日限制
|
|
||||||
Integer i = (Integer) redis.getByKey(REDIS_KEY+args + "max");
|
|
||||||
if (SmsUtil.isEmpty(i)) {
|
|
||||||
redis.setOrTime(REDIS_KEY+args + "max", 1,accTimer/1000);
|
|
||||||
} else if (i > accountMax) {
|
|
||||||
log.info("The phone:"+args +",number of short messages reached the maximum today");
|
|
||||||
return new SmsBlendException("The phone:"+args +",number of short messages reached the maximum today");
|
|
||||||
} else {
|
|
||||||
redis.setOrTime(REDIS_KEY+args + "max", i + 1,accTimer/1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (SmsUtil.isNotEmpty(minuteMax)) { //是否配置了每分钟最大限制
|
|
||||||
Integer o = (Integer) redis.getByKey(REDIS_KEY+args);
|
|
||||||
if (SmsUtil.isNotEmpty(o)) {
|
|
||||||
if (o < minuteMax) {
|
|
||||||
redis.setOrTime(REDIS_KEY+args, o + 1,minTimer/1000);
|
|
||||||
} else {
|
|
||||||
log.info("The phone:"+args +",number of short messages reached the maximum today");
|
|
||||||
return new SmsBlendException("The phone:", args + " Text messages are sent too often!");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
redis.setOrTime(REDIS_KEY+args, 1,minTimer/1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
package org.dromara.sms4j.autoimmit.aop;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.api.smsProxy.RestrictedProcess;
|
||||||
|
import org.dromara.sms4j.autoimmit.utils.RedisUtils;
|
||||||
|
import org.dromara.sms4j.autoimmit.utils.SpringUtil;
|
||||||
|
import org.dromara.sms4j.comm.config.SmsConfig;
|
||||||
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsUtil;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class RestrictedProcessImpl extends RestrictedProcess {
|
||||||
|
private static final Long minTimer = 60 * 1000L;
|
||||||
|
private static final Long accTimer = 24 * 60 * 60 * 1000L;
|
||||||
|
private static final String REDIS_KEY = "sms:restricted:";
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsBlendException process(SmsConfig config,String args) throws Exception {
|
||||||
|
RedisUtils redis = SpringUtil.getBean(RedisUtils.class);
|
||||||
|
if (Objects.isNull(redis)){
|
||||||
|
throw new SmsBlendException("The redis tool could not be found");
|
||||||
|
}
|
||||||
|
Integer accountMax = config.getAccountMax();//每日最大发送量
|
||||||
|
Integer minuteMax = config.getMinuteMax();//每分钟最大发送量
|
||||||
|
if (SmsUtil.isNotEmpty(accountMax)) { //是否配置了每日限制
|
||||||
|
Integer i = (Integer) redis.getByKey(REDIS_KEY + args + "max");
|
||||||
|
if (SmsUtil.isEmpty(i)) {
|
||||||
|
redis.setOrTime(REDIS_KEY + args + "max", 1, accTimer / 1000);
|
||||||
|
} else if (i > accountMax) {
|
||||||
|
log.info("The phone:" + args + ",number of short messages reached the maximum today");
|
||||||
|
return new SmsBlendException("The phone:" + args + ",number of short messages reached the maximum today");
|
||||||
|
} else {
|
||||||
|
redis.setOrTime(REDIS_KEY + args + "max", i + 1, accTimer / 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (SmsUtil.isNotEmpty(minuteMax)) { //是否配置了每分钟最大限制
|
||||||
|
Integer o = (Integer) redis.getByKey(REDIS_KEY + args);
|
||||||
|
if (SmsUtil.isNotEmpty(o)) {
|
||||||
|
if (o < minuteMax) {
|
||||||
|
redis.setOrTime(REDIS_KEY + args, o + 1, minTimer / 1000);
|
||||||
|
} else {
|
||||||
|
log.info("The phone:" + args + ",number of short messages reached the maximum today");
|
||||||
|
return new SmsBlendException("The phone:", args + " Text messages are sent too often!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
redis.setOrTime(REDIS_KEY + args, 1, minTimer / 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,17 +1,17 @@
|
|||||||
package org.dromara.sms4j.autoimmit.config;
|
package org.dromara.sms4j.autoimmit.config;
|
||||||
|
|
||||||
import org.dromara.sms4j.autoimmit.aop.AopAdvice;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.api.smsProxy.SmsInvocationHandler;
|
||||||
|
import org.dromara.sms4j.autoimmit.aop.RestrictedProcessImpl;
|
||||||
import org.dromara.sms4j.autoimmit.utils.ConfigUtil;
|
import org.dromara.sms4j.autoimmit.utils.ConfigUtil;
|
||||||
import org.dromara.sms4j.autoimmit.utils.RedisUtils;
|
import org.dromara.sms4j.autoimmit.utils.RedisUtils;
|
||||||
import org.dromara.sms4j.autoimmit.utils.SpringUtil;
|
import org.dromara.sms4j.autoimmit.utils.SpringUtil;
|
||||||
import org.dromara.sms4j.comm.config.SmsBanner;
|
import org.dromara.sms4j.comm.config.SmsBanner;
|
||||||
import org.dromara.sms4j.comm.config.SmsConfig;
|
import org.dromara.sms4j.comm.config.SmsConfig;
|
||||||
import org.dromara.sms4j.comm.config.SmsSqlConfig;
|
import org.dromara.sms4j.comm.config.SmsSqlConfig;
|
||||||
|
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.enumerate.ConfigType;
|
|
||||||
import org.dromara.sms4j.comm.enumerate.SupplierType;
|
|
||||||
import org.dromara.sms4j.comm.factory.BeanFactory;
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.dromara.sms4j.core.SupplierSqlConfig;
|
import org.dromara.sms4j.core.SupplierSqlConfig;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
@ -71,21 +71,21 @@ public class SmsAutowiredConfig {
|
|||||||
return new SupplierSqlConfig();
|
return new SupplierSqlConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void init(){
|
void init(){
|
||||||
/* 如果配置中启用了redis,则注入redis工具*/
|
/* 如果配置中启用了redis,则注入redis工具*/
|
||||||
if (BeanFactory.getSmsConfig().getRedisCache()){
|
if (BeanFactory.getSmsConfig().getRedisCache()){
|
||||||
springUtil.createBean(RedisUtils.class);
|
springUtil.createBean(RedisUtils.class);
|
||||||
log.debug("The redis cache is enabled for sms-aggregation");
|
SmsInvocationHandler.setRestrictedProcess(new RestrictedProcessImpl());
|
||||||
|
log.debug("The redis cache is enabled for sms4j");
|
||||||
}
|
}
|
||||||
/* 如果启用了短信限制,则注入AOP组件*/
|
/* 如果启用了短信限制,则注入AOP组件*/
|
||||||
if (BeanFactory.getSmsConfig().getRestricted()){
|
// if (BeanFactory.getSmsConfig().getRestricted()){
|
||||||
springUtil.createBean(AopAdvice.class);
|
// springUtil.createBean(AopAdvice.class);
|
||||||
log.debug("SMS restriction is enabled");
|
// log.debug("SMS restriction is enabled");
|
||||||
}
|
// }
|
||||||
//打印banner
|
//打印banner
|
||||||
if (BeanFactory.getSmsConfig().getIsPrint()){
|
if (BeanFactory.getSmsConfig().getIsPrint()){
|
||||||
SmsBanner.PrintBanner("V 2.0.1");
|
SmsBanner.PrintBanner(Constant.VERSION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
package org.dromara.sms4j.autoimmit.config;
|
package org.dromara.sms4j.autoimmit.config;
|
||||||
|
|
||||||
import org.dromara.sms4j.emay.config.EmayConfig;
|
|
||||||
import org.dromara.sms4j.aliyun.config.AlibabaConfig;
|
import org.dromara.sms4j.aliyun.config.AlibabaConfig;
|
||||||
import org.dromara.sms4j.cloopen.config.CloopenConfig;
|
import org.dromara.sms4j.cloopen.config.CloopenConfig;
|
||||||
import org.dromara.sms4j.core.config.SupplierFactory;
|
import org.dromara.sms4j.core.config.SupplierFactory;
|
||||||
|
import org.dromara.sms4j.ctyun.config.CtyunConfig;
|
||||||
|
import org.dromara.sms4j.emay.config.EmayConfig;
|
||||||
import org.dromara.sms4j.huawei.config.HuaweiConfig;
|
import org.dromara.sms4j.huawei.config.HuaweiConfig;
|
||||||
import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
|
import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
|
||||||
import org.dromara.sms4j.tencent.config.TencentConfig;
|
import org.dromara.sms4j.tencent.config.TencentConfig;
|
||||||
@ -72,4 +73,13 @@ public class SupplierConfig {
|
|||||||
protected EmayConfig emayConfig(){
|
protected EmayConfig emayConfig(){
|
||||||
return SupplierFactory.getEmayConfig();
|
return SupplierFactory.getEmayConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天翼云短信差异化配置
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@ConfigurationProperties(prefix = "sms.ctyun")
|
||||||
|
protected CtyunConfig ctyunConfig(){
|
||||||
|
return SupplierFactory.getCtyunConfig();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,11 @@ import org.springframework.data.redis.core.StringRedisTemplate;
|
|||||||
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
|
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
|
||||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -15,11 +15,6 @@
|
|||||||
<description>sms4j-comm</description>
|
<description>sms4j-comm</description>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>com.alibaba</groupId>
|
|
||||||
<artifactId>fastjson</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.dtflys.forest</groupId>
|
<groupId>com.dtflys.forest</groupId>
|
||||||
<artifactId>forest-core</artifactId>
|
<artifactId>forest-core</artifactId>
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
package org.dromara.sms4j.comm.config;
|
package org.dromara.sms4j.comm.config;
|
||||||
|
|
||||||
|
|
||||||
import org.dromara.sms4j.comm.enumerate.ConfigType;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.dromara.sms4j.comm.enumerate.ConfigType;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class SmsConfig {
|
public class SmsConfig {
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
package org.dromara.sms4j.comm.constant;
|
package org.dromara.sms4j.comm.constant;
|
||||||
|
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constant
|
* Constant
|
||||||
* <p> 短信应用常量
|
* <p> 短信应用常量
|
||||||
@ -12,6 +9,8 @@ import java.nio.charset.StandardCharsets;
|
|||||||
* 2023/3/31 19:33
|
* 2023/3/31 19:33
|
||||||
**/
|
**/
|
||||||
public abstract class Constant {
|
public abstract class Constant {
|
||||||
|
/** 项目版本号*/
|
||||||
|
public static final String VERSION = "V 2.1.0";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用于格式化鉴权头域,给"Authorization"参数赋值
|
* 用于格式化鉴权头域,给"Authorization"参数赋值
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package org.dromara.sms4j.comm.delayedTime;
|
package org.dromara.sms4j.comm.delayedTime;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>类名: DelayedTime
|
* <p>类名: DelayedTime
|
||||||
|
|||||||
@ -1,41 +0,0 @@
|
|||||||
package org.dromara.sms4j.comm.enumerate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SupplierType
|
|
||||||
* <p> 短信供应商枚举
|
|
||||||
* @author :Wind
|
|
||||||
* 2023/4/7 20:55
|
|
||||||
**/
|
|
||||||
public enum SupplierType {
|
|
||||||
/** 阿里云*/
|
|
||||||
ALIBABA("阿里云短信"),
|
|
||||||
/** 华为云*/
|
|
||||||
HUAWEI("华为云短信"),
|
|
||||||
/** 云片*/
|
|
||||||
YUNPIAN("云片短信"),
|
|
||||||
/** 腾讯云*/
|
|
||||||
TENCENT("腾讯云短信"),
|
|
||||||
/** 合一短信*/
|
|
||||||
UNI_SMS("合一短信"),
|
|
||||||
/** 京东云 */
|
|
||||||
JD_CLOUD("京东云短信"),
|
|
||||||
/** 容联云 */
|
|
||||||
CLOOPEN("容联云短信"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 亿美软通
|
|
||||||
*/
|
|
||||||
EMAY("亿美软通"),
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
SupplierType(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,7 +5,11 @@ import org.dromara.sms4j.comm.config.SmsSqlConfig;
|
|||||||
import org.dromara.sms4j.comm.exception.SmsSqlException;
|
import org.dromara.sms4j.comm.exception.SmsSqlException;
|
||||||
import org.dromara.sms4j.comm.factory.BeanFactory;
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|||||||
@ -1,20 +1,22 @@
|
|||||||
package org.dromara.sms4j.comm.utils;
|
package org.dromara.sms4j.comm.utils;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import com.alibaba.fastjson.JSONException;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import org.dromara.sms4j.comm.exception.SmsSqlException;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.util.ArrayList;
|
||||||
import java.security.SecureRandom;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author wind
|
||||||
|
*/
|
||||||
public class SmsUtil {
|
public class SmsUtil {
|
||||||
private SmsUtil() {
|
private SmsUtil() {
|
||||||
} //私有构造防止实例化
|
} //私有构造防止实例化
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>说明:生成一个指定长度的随机字符串,包含大小写英文字母和数字但不包含符号
|
* <p>说明:生成一个指定长度的随机字符串,包含大小写英文字母和数字但不包含符号
|
||||||
*
|
*
|
||||||
@ -23,23 +25,13 @@ public class SmsUtil {
|
|||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public static String getRandomString(int len) {
|
public static String getRandomString(int len) {
|
||||||
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
return RandomUtil.randomString(RandomUtil.BASE_CHAR_NUMBER + RandomUtil.BASE_CHAR.toUpperCase(), len);
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
try {
|
|
||||||
Random random = SecureRandom.getInstanceStrong();
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
int number = random.nextInt(62);
|
|
||||||
sb.append(str.charAt(number));
|
|
||||||
}
|
|
||||||
} catch (NoSuchAlgorithmException e){
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>说明:获取一个长度为6的随机字符串
|
* <p>说明:获取一个长度为6的随机字符串
|
||||||
*getRandomString
|
* getRandomString
|
||||||
|
*
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public static String getRandomString() {
|
public static String getRandomString() {
|
||||||
@ -48,37 +40,29 @@ public class SmsUtil {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>说明:生成一个指定长度的只有数字组成的随机字符串
|
* <p>说明:生成一个指定长度的只有数字组成的随机字符串
|
||||||
|
*
|
||||||
* @param len 要生成的长度
|
* @param len 要生成的长度
|
||||||
* getRandomInt
|
* getRandomInt
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public static String getRandomInt(int len) {
|
public static String getRandomInt(int len) {
|
||||||
String str = "0123456789";
|
return RandomUtil.randomString(RandomUtil.BASE_NUMBER, len);
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
try {
|
|
||||||
Random random = SecureRandom.getInstanceStrong();
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
int number = random.nextInt(10);
|
|
||||||
sb.append(str.charAt(number));
|
|
||||||
}
|
|
||||||
} catch (NoSuchAlgorithmException e){
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指定元素是否为null或者空字符串
|
* 指定元素是否为null或者空字符串
|
||||||
|
*
|
||||||
* @param str 指定元素
|
* @param str 指定元素
|
||||||
* @return 是否为null或者空字符串
|
* @return 是否为null或者空字符串
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public static boolean isEmpty(Object str) {
|
public static boolean isEmpty(Object str) {
|
||||||
return str == null || "".equals(str);
|
return ObjectUtil.isEmpty(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指定元素是否不为 (null或者空字符串)
|
* 指定元素是否不为 (null或者空字符串)
|
||||||
|
*
|
||||||
* @param str 指定元素
|
* @param str 指定元素
|
||||||
* @return 是否为null或者空字符串
|
* @return 是否为null或者空字符串
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
@ -87,43 +71,72 @@ public class SmsUtil {
|
|||||||
return !isEmpty(str);
|
return !isEmpty(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String listToString(List<String> list) {
|
|
||||||
StringBuilder str = new StringBuilder();
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
if (i == list.size() - 1) {
|
|
||||||
str.append(list.get(i));
|
|
||||||
} else {
|
|
||||||
str.append(list.get(i));
|
|
||||||
str.append(",");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* jsonForObject
|
* jsonForObject
|
||||||
* <p>将json字符串转化为指定的对象
|
* <p>将json字符串转化为指定的对象
|
||||||
|
*
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public static <T> T jsonForObject(String json, Class<T> t) {
|
public static <T> T jsonForObject(String json, Class<T> t) {
|
||||||
try {
|
return JSONUtil.toBean(json, t);
|
||||||
return json == null||"".equals(json)?null: JSONObject.toJavaObject(JSONObject.parseObject(json), t);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
throw new SmsSqlException("json sequence exception" + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* copyBean
|
* copyBean
|
||||||
* <p>拷贝bean,只有源对象不为null才会拷贝
|
* <p>拷贝bean,只有源对象不为null才会拷贝
|
||||||
|
*
|
||||||
* @param t 源对象
|
* @param t 源对象
|
||||||
* @param m 目标对象
|
* @param m 目标对象
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public static <T,M>void copyBean(T t,M m){
|
public static <T, M> void copyBean(T t, M m) {
|
||||||
if (t != null){
|
|
||||||
BeanUtil.copyProperties(t, m);
|
BeanUtil.copyProperties(t, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getNewMap
|
||||||
|
* <p>获取一个新的空LinkedHashMap
|
||||||
|
*
|
||||||
|
* @return 空的 LinkedHashMap 实例
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
public static LinkedHashMap<String, String> getNewMap() {
|
||||||
|
return new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* listToString
|
||||||
|
* <p>将list转化为string,元素之间使用逗号分隔,此方法只支持list内部元素为String类型的
|
||||||
|
*
|
||||||
|
* @param list 要转换的list
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
public static String listToString(List<String> list) {
|
||||||
|
return CollUtil.join(list, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 以 conjunction 为分隔符将集合转换为字符串
|
||||||
|
*
|
||||||
|
* @param list 集合
|
||||||
|
* @return 结果字符串
|
||||||
|
*/
|
||||||
|
public static String arrayToString(List<String> list) {
|
||||||
|
return CollUtil.join(list, ",", "+86", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List +86后转 数组
|
||||||
|
*
|
||||||
|
* @param list 集合
|
||||||
|
* @return 结果字符串
|
||||||
|
*/
|
||||||
|
public static String[] listToArray(List<String> list) {
|
||||||
|
List<String> toStr = new ArrayList<>();
|
||||||
|
for (String s : list) {
|
||||||
|
toStr.add("+86" + s);
|
||||||
|
}
|
||||||
|
return toStr.toArray(new String[list.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,9 +1,9 @@
|
|||||||
package org.dromara.sms4j.comm.utils;
|
package org.dromara.sms4j.comm.utils;
|
||||||
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import cn.hutool.json.JSONUtil;
|
||||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -66,8 +66,7 @@ public class TimeExpiredPoolCache {
|
|||||||
private static boolean persistenceInit() {
|
private static boolean persistenceInit() {
|
||||||
String path = FileTool.getPath() + FILE_TYPE;
|
String path = FileTool.getPath() + FILE_TYPE;
|
||||||
try {
|
try {
|
||||||
|
DataWrapper d = JSONUtil.toBean(FileTool.readFile(path), DataWrapper.class);
|
||||||
DataWrapper d = JSONObject.parseObject(FileTool.readFile(path), DataWrapper.class);
|
|
||||||
if (dataPool != null) {
|
if (dataPool != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -95,7 +94,7 @@ public class TimeExpiredPoolCache {
|
|||||||
private static void persistence() {
|
private static void persistence() {
|
||||||
String path = FileTool.getPath() + FILE_TYPE;
|
String path = FileTool.getPath() + FILE_TYPE;
|
||||||
FileTool.createFile(path);
|
FileTool.createFile(path);
|
||||||
FileTool.writeFile(new File(path), JSONObject.toJSONString(dataPool), false);
|
FileTool.writeFile(new File(path), JSONUtil.toJsonStr(dataPool), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,21 +0,0 @@
|
|||||||
package org.dromara.sms4j.comm.utils.http;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class HttpJsonTool {
|
|
||||||
|
|
||||||
|
|
||||||
public static <T> T getJSONBody(Object response,Class<T>t){
|
|
||||||
return JSONObject.parseObject(response.toString(), t);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> T getJSONBody(String response,Class<T>t){
|
|
||||||
return JSONObject.parseObject(response, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JSONObject getJSONObject(Object obj){
|
|
||||||
return JSONObject.parseObject(obj.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
|
|
||||||
@ -2,13 +2,14 @@ package org.dromara.sms4j.core;
|
|||||||
|
|
||||||
import org.dromara.sms4j.aliyun.config.AlibabaConfig;
|
import org.dromara.sms4j.aliyun.config.AlibabaConfig;
|
||||||
import org.dromara.sms4j.cloopen.config.CloopenConfig;
|
import org.dromara.sms4j.cloopen.config.CloopenConfig;
|
||||||
import org.dromara.sms4j.comm.enumerate.SupplierType;
|
|
||||||
import org.dromara.sms4j.comm.utils.JDBCTool;
|
import org.dromara.sms4j.comm.utils.JDBCTool;
|
||||||
import org.dromara.sms4j.comm.utils.SmsUtil;
|
import org.dromara.sms4j.comm.utils.SmsUtil;
|
||||||
import org.dromara.sms4j.core.config.SupplierFactory;
|
import org.dromara.sms4j.core.config.SupplierFactory;
|
||||||
|
import org.dromara.sms4j.ctyun.config.CtyunConfig;
|
||||||
import org.dromara.sms4j.emay.config.EmayConfig;
|
import org.dromara.sms4j.emay.config.EmayConfig;
|
||||||
import org.dromara.sms4j.huawei.config.HuaweiConfig;
|
import org.dromara.sms4j.huawei.config.HuaweiConfig;
|
||||||
import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
|
import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
|
||||||
|
import org.dromara.sms4j.provider.enumerate.SupplierType;
|
||||||
import org.dromara.sms4j.tencent.config.TencentConfig;
|
import org.dromara.sms4j.tencent.config.TencentConfig;
|
||||||
import org.dromara.sms4j.unisms.config.UniConfig;
|
import org.dromara.sms4j.unisms.config.UniConfig;
|
||||||
import org.dromara.sms4j.yunpian.config.YunpianConfig;
|
import org.dromara.sms4j.yunpian.config.YunpianConfig;
|
||||||
@ -48,6 +49,7 @@ public class SupplierSqlConfig {
|
|||||||
yunPian();
|
yunPian();
|
||||||
cloopen();
|
cloopen();
|
||||||
emay();
|
emay();
|
||||||
|
ctyun();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SupplierSqlConfig() {
|
public SupplierSqlConfig() {
|
||||||
@ -136,4 +138,14 @@ public class SupplierSqlConfig {
|
|||||||
EmayConfig emayConfig = SmsUtil.jsonForObject(select.get(SupplierType.EMAY.getName()), EmayConfig.class);
|
EmayConfig emayConfig = SmsUtil.jsonForObject(select.get(SupplierType.EMAY.getName()), EmayConfig.class);
|
||||||
SupplierFactory.setEmayConfig(emayConfig);
|
SupplierFactory.setEmayConfig(emayConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ctyun
|
||||||
|
* <p>数据库读取并设置天翼云短信
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
public static void ctyun(){
|
||||||
|
CtyunConfig ctyunConfig = SmsUtil.jsonForObject(select.get(SupplierType.CTYUN.getName()), CtyunConfig.class);
|
||||||
|
SupplierFactory.setCtyunConfig(ctyunConfig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,26 @@
|
|||||||
package org.dromara.sms4j.core.config;
|
package org.dromara.sms4j.core.config;
|
||||||
|
|
||||||
import org.dromara.sms4j.comm.enumerate.SupplierType;
|
|
||||||
import org.dromara.sms4j.core.factory.SmsFactory;
|
|
||||||
import org.dromara.sms4j.emay.config.EmayConfig;
|
|
||||||
import org.dromara.sms4j.aliyun.config.AlibabaConfig;
|
import org.dromara.sms4j.aliyun.config.AlibabaConfig;
|
||||||
|
import org.dromara.sms4j.aliyun.config.AlibabaFactory;
|
||||||
|
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||||
import org.dromara.sms4j.cloopen.config.CloopenConfig;
|
import org.dromara.sms4j.cloopen.config.CloopenConfig;
|
||||||
|
import org.dromara.sms4j.cloopen.config.CloopenFactory;
|
||||||
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
import org.dromara.sms4j.core.factory.SmsFactory;
|
||||||
|
import org.dromara.sms4j.ctyun.config.CtyunConfig;
|
||||||
|
import org.dromara.sms4j.ctyun.config.CtyunFactory;
|
||||||
|
import org.dromara.sms4j.emay.config.EmayConfig;
|
||||||
|
import org.dromara.sms4j.emay.config.EmayFactory;
|
||||||
import org.dromara.sms4j.huawei.config.HuaweiConfig;
|
import org.dromara.sms4j.huawei.config.HuaweiConfig;
|
||||||
|
import org.dromara.sms4j.huawei.config.HuaweiFactory;
|
||||||
import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
|
import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
|
||||||
|
import org.dromara.sms4j.jdcloud.config.JdCloudFactory;
|
||||||
|
import org.dromara.sms4j.provider.enumerate.SupplierType;
|
||||||
import org.dromara.sms4j.tencent.config.TencentConfig;
|
import org.dromara.sms4j.tencent.config.TencentConfig;
|
||||||
|
import org.dromara.sms4j.tencent.config.TencentFactory;
|
||||||
import org.dromara.sms4j.unisms.config.UniConfig;
|
import org.dromara.sms4j.unisms.config.UniConfig;
|
||||||
|
import org.dromara.sms4j.unisms.config.UniFactory;
|
||||||
|
import org.dromara.sms4j.yunpian.config.YunPianFactory;
|
||||||
import org.dromara.sms4j.yunpian.config.YunpianConfig;
|
import org.dromara.sms4j.yunpian.config.YunpianConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,103 +33,104 @@ public class SupplierFactory {
|
|||||||
private SupplierFactory() {
|
private SupplierFactory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 阿里云差异化配置*/
|
/**
|
||||||
private static AlibabaConfig alibabaConfig;
|
* 阿里云配置获取
|
||||||
|
*/
|
||||||
/** 华为云差异化配置*/
|
public static AlibabaConfig getAlibabaConfig() {
|
||||||
private static HuaweiConfig huaweiConfig;
|
return AlibabaFactory.instance().getConfig();
|
||||||
|
}
|
||||||
/** 合一短信差异化配置*/
|
|
||||||
private static UniConfig uniConfig;
|
|
||||||
|
|
||||||
/** 腾讯云短信差异化配置*/
|
|
||||||
private static TencentConfig tencentConfig;
|
|
||||||
|
|
||||||
/** 云片短信差异配置*/
|
|
||||||
private static YunpianConfig yunpianConfig;
|
|
||||||
|
|
||||||
/** 京东云短信差异配置 */
|
|
||||||
private static JdCloudConfig jdCloudConfig;
|
|
||||||
|
|
||||||
/** 容联云短信差异配置 */
|
|
||||||
private static CloopenConfig cloopenConfig;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 亿美软通短信差异配置
|
* 华为云配置获取
|
||||||
*/
|
*/
|
||||||
private static EmayConfig emayConfig;
|
|
||||||
|
|
||||||
/** 阿里云配置获取*/
|
|
||||||
public static AlibabaConfig getAlibabaConfig() {
|
|
||||||
if (alibabaConfig == null){
|
|
||||||
alibabaConfig = AlibabaConfig.builder().build();
|
|
||||||
}
|
|
||||||
return alibabaConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 华为云配置获取*/
|
|
||||||
public static HuaweiConfig getHuaweiConfig() {
|
public static HuaweiConfig getHuaweiConfig() {
|
||||||
if (huaweiConfig == null){
|
return HuaweiFactory.instance().getConfig();
|
||||||
huaweiConfig = HuaweiConfig.builder().build();
|
|
||||||
}
|
|
||||||
return huaweiConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 合一短信配置获取*/
|
/**
|
||||||
|
* 合一短信配置获取
|
||||||
|
*/
|
||||||
public static UniConfig getUniConfig() {
|
public static UniConfig getUniConfig() {
|
||||||
if (uniConfig == null){
|
return UniFactory.instance().getConfig();
|
||||||
uniConfig = UniConfig.builder().build();
|
|
||||||
}
|
|
||||||
return uniConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 腾讯短信配置获取*/
|
/**
|
||||||
|
* 腾讯短信配置获取
|
||||||
|
*/
|
||||||
public static TencentConfig getTencentConfig() {
|
public static TencentConfig getTencentConfig() {
|
||||||
if (tencentConfig == null){
|
return TencentFactory.instance().getConfig();
|
||||||
tencentConfig = TencentConfig.builder().build();
|
|
||||||
}
|
|
||||||
return tencentConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 云片短信配置获取*/
|
/**
|
||||||
|
* 云片短信配置获取
|
||||||
|
*/
|
||||||
public static YunpianConfig getYunpianConfig() {
|
public static YunpianConfig getYunpianConfig() {
|
||||||
if (yunpianConfig == null){
|
return YunPianFactory.instance().getConfig();
|
||||||
yunpianConfig = YunpianConfig.builder().build();
|
|
||||||
}
|
|
||||||
return yunpianConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 京东云短信配置获取 */
|
/**
|
||||||
|
* 京东云短信配置获取
|
||||||
|
*/
|
||||||
public static JdCloudConfig getJdCloudConfig() {
|
public static JdCloudConfig getJdCloudConfig() {
|
||||||
if (jdCloudConfig == null){
|
return JdCloudFactory.instance().getConfig();
|
||||||
jdCloudConfig = JdCloudConfig.builder().build();
|
|
||||||
}
|
|
||||||
return jdCloudConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 容联云短信配置获取 */
|
/**
|
||||||
|
* 容联云短信配置获取
|
||||||
|
*/
|
||||||
public static CloopenConfig getCloopenConfig() {
|
public static CloopenConfig getCloopenConfig() {
|
||||||
if (cloopenConfig == null){
|
return CloopenFactory.instance().getConfig();
|
||||||
cloopenConfig = CloopenConfig.builder().build();
|
|
||||||
}
|
|
||||||
return cloopenConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 亿美软通配置获取
|
* 亿美软通配置获取
|
||||||
*/
|
*/
|
||||||
public static EmayConfig getEmayConfig() {
|
public static EmayConfig getEmayConfig() {
|
||||||
if (emayConfig == null) {
|
return EmayFactory.instance().getConfig();
|
||||||
emayConfig = EmayConfig.builder().build();
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天翼云配置获取
|
||||||
|
*/
|
||||||
|
public static CtyunConfig getCtyunConfig() {
|
||||||
|
return CtyunFactory.instance().getConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setSupplierConfig
|
||||||
|
* <p>通用化set,用于设置
|
||||||
|
* @param t 配置对象
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
public static <T extends SupplierConfig> void setSupplierConfig(T t) {
|
||||||
|
if (t instanceof AlibabaConfig) {
|
||||||
|
setAlibabaConfig((AlibabaConfig) t);
|
||||||
|
} else if (t instanceof HuaweiConfig) {
|
||||||
|
setHuaweiConfig((HuaweiConfig) t);
|
||||||
|
} else if (t instanceof UniConfig) {
|
||||||
|
setUniConfig((UniConfig) t);
|
||||||
|
} else if (t instanceof TencentConfig) {
|
||||||
|
setTencentConfig((TencentConfig) t);
|
||||||
|
} else if (t instanceof YunpianConfig) {
|
||||||
|
setYunpianConfig((YunpianConfig) t);
|
||||||
|
} else if (t instanceof JdCloudConfig) {
|
||||||
|
setJdCloudConfig((JdCloudConfig) t);
|
||||||
|
} else if (t instanceof CloopenConfig) {
|
||||||
|
setCloopenConfig((CloopenConfig) t);
|
||||||
|
} else if (t instanceof EmayConfig) {
|
||||||
|
setEmayConfig((EmayConfig) t);
|
||||||
|
} else if (t instanceof CtyunConfig) {
|
||||||
|
setCtyunConfig((CtyunConfig) t);
|
||||||
|
}else {
|
||||||
|
throw new SmsBlendException("Loading failure! Please check the configuration type.");
|
||||||
}
|
}
|
||||||
return emayConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置 alibabaConfig
|
* 设置 alibabaConfig
|
||||||
*/
|
*/
|
||||||
public static void setAlibabaConfig(AlibabaConfig alibabaConfig) {
|
public static void setAlibabaConfig(AlibabaConfig alibabaConfig) {
|
||||||
SupplierFactory.alibabaConfig = alibabaConfig;
|
AlibabaFactory.instance().setConfig(alibabaConfig);
|
||||||
SmsFactory.refresh(SupplierType.ALIBABA);
|
SmsFactory.refresh(SupplierType.ALIBABA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +138,7 @@ public class SupplierFactory {
|
|||||||
* 设置 huaweiConfig
|
* 设置 huaweiConfig
|
||||||
*/
|
*/
|
||||||
public static void setHuaweiConfig(HuaweiConfig huaweiConfig) {
|
public static void setHuaweiConfig(HuaweiConfig huaweiConfig) {
|
||||||
SupplierFactory.huaweiConfig = huaweiConfig;
|
HuaweiFactory.instance().setConfig(huaweiConfig);
|
||||||
SmsFactory.refresh(SupplierType.HUAWEI);
|
SmsFactory.refresh(SupplierType.HUAWEI);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +146,7 @@ public class SupplierFactory {
|
|||||||
* 设置 uniConfig
|
* 设置 uniConfig
|
||||||
*/
|
*/
|
||||||
public static void setUniConfig(UniConfig uniConfig) {
|
public static void setUniConfig(UniConfig uniConfig) {
|
||||||
SupplierFactory.uniConfig = uniConfig;
|
UniFactory.instance().setConfig(uniConfig);
|
||||||
SmsFactory.refresh(SupplierType.UNI_SMS);
|
SmsFactory.refresh(SupplierType.UNI_SMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +154,7 @@ public class SupplierFactory {
|
|||||||
* 设置 tencentConfig
|
* 设置 tencentConfig
|
||||||
*/
|
*/
|
||||||
public static void setTencentConfig(TencentConfig tencentConfig) {
|
public static void setTencentConfig(TencentConfig tencentConfig) {
|
||||||
SupplierFactory.tencentConfig = tencentConfig;
|
TencentFactory.instance().setConfig(tencentConfig);
|
||||||
SmsFactory.refresh(SupplierType.TENCENT);
|
SmsFactory.refresh(SupplierType.TENCENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +162,7 @@ public class SupplierFactory {
|
|||||||
* 设置 yunpianConfig
|
* 设置 yunpianConfig
|
||||||
*/
|
*/
|
||||||
public static void setYunpianConfig(YunpianConfig yunpianConfig) {
|
public static void setYunpianConfig(YunpianConfig yunpianConfig) {
|
||||||
SupplierFactory.yunpianConfig = yunpianConfig;
|
YunPianFactory.instance().setConfig(yunpianConfig);
|
||||||
SmsFactory.refresh(SupplierType.YUNPIAN);
|
SmsFactory.refresh(SupplierType.YUNPIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +170,7 @@ public class SupplierFactory {
|
|||||||
* 设置 jdCloudConfig
|
* 设置 jdCloudConfig
|
||||||
*/
|
*/
|
||||||
public static void setJdCloudConfig(JdCloudConfig jdCloudConfig) {
|
public static void setJdCloudConfig(JdCloudConfig jdCloudConfig) {
|
||||||
SupplierFactory.jdCloudConfig = jdCloudConfig;
|
JdCloudFactory.instance().setConfig(jdCloudConfig);
|
||||||
SmsFactory.refresh(SupplierType.JD_CLOUD);
|
SmsFactory.refresh(SupplierType.JD_CLOUD);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +178,7 @@ public class SupplierFactory {
|
|||||||
* 设置 cloopenConfig
|
* 设置 cloopenConfig
|
||||||
*/
|
*/
|
||||||
public static void setCloopenConfig(CloopenConfig cloopenConfig) {
|
public static void setCloopenConfig(CloopenConfig cloopenConfig) {
|
||||||
SupplierFactory.cloopenConfig = cloopenConfig;
|
CloopenFactory.instance().setConfig(cloopenConfig);
|
||||||
SmsFactory.refresh(SupplierType.CLOOPEN);
|
SmsFactory.refresh(SupplierType.CLOOPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +186,15 @@ public class SupplierFactory {
|
|||||||
* 设置 emayConfig
|
* 设置 emayConfig
|
||||||
*/
|
*/
|
||||||
public static void setEmayConfig(EmayConfig emayConfig) {
|
public static void setEmayConfig(EmayConfig emayConfig) {
|
||||||
SupplierFactory.emayConfig = emayConfig;
|
EmayFactory.instance().setConfig(emayConfig);
|
||||||
SmsFactory.refresh(SupplierType.EMAY);
|
SmsFactory.refresh(SupplierType.EMAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 ctyunConfig
|
||||||
|
*/
|
||||||
|
public static void setCtyunConfig(CtyunConfig ctyunConfig) {
|
||||||
|
CtyunFactory.instance().setConfig(ctyunConfig);
|
||||||
|
SmsFactory.refresh(SupplierType.CTYUN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,16 @@
|
|||||||
package org.dromara.sms4j.core.factory;
|
package org.dromara.sms4j.core.factory;
|
||||||
|
|
||||||
import org.dromara.sms4j.aliyun.config.AlibabaSmsConfig;
|
|
||||||
import org.dromara.sms4j.api.SmsBlend;
|
import org.dromara.sms4j.api.SmsBlend;
|
||||||
import org.dromara.sms4j.cloopen.config.CloopenSmsConfig;
|
import org.dromara.sms4j.api.smsProxy.SmsInvocationHandler;
|
||||||
import org.dromara.sms4j.comm.enumerate.SupplierType;
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
|
||||||
import org.dromara.sms4j.core.SupplierSqlConfig;
|
import org.dromara.sms4j.core.SupplierSqlConfig;
|
||||||
import org.dromara.sms4j.core.config.SupplierFactory;
|
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
||||||
import org.dromara.sms4j.emay.config.EmaySmsConfig;
|
import org.dromara.sms4j.provider.enumerate.SupplierType;
|
||||||
import org.dromara.sms4j.huawei.config.HuaweiSmsConfig;
|
|
||||||
import org.dromara.sms4j.jdcloud.config.JdCloudSmsConfig;
|
import java.lang.reflect.Proxy;
|
||||||
import org.dromara.sms4j.tencent.config.TencentSmsConfig;
|
import java.util.HashMap;
|
||||||
import org.dromara.sms4j.unisms.config.UniSmsConfig;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SmsFactory
|
* SmsFactory
|
||||||
@ -23,6 +22,9 @@ import org.dromara.sms4j.unisms.config.UniSmsConfig;
|
|||||||
* 2023/4/8 15:55
|
* 2023/4/8 15:55
|
||||||
**/
|
**/
|
||||||
public abstract class SmsFactory {
|
public abstract class SmsFactory {
|
||||||
|
|
||||||
|
private static Map<SupplierType, SmsBlend> beans = new HashMap<>();
|
||||||
|
|
||||||
private SmsFactory() {
|
private SmsFactory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,23 +36,8 @@ public abstract class SmsFactory {
|
|||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public static SmsBlend createSmsBlend(SupplierType supplierType) {
|
public static SmsBlend createSmsBlend(SupplierType supplierType) {
|
||||||
switch (supplierType) {
|
BaseProviderFactory providerFactory = supplierType.getProviderFactory();
|
||||||
case ALIBABA:
|
return providerFactory.createSms(providerFactory.getConfig());
|
||||||
return AlibabaSmsConfig.createAlibabaSms(SupplierFactory.getAlibabaConfig());
|
|
||||||
case HUAWEI:
|
|
||||||
return HuaweiSmsConfig.createHuaweiSms(SupplierFactory.getHuaweiConfig());
|
|
||||||
case UNI_SMS:
|
|
||||||
return UniSmsConfig.createUniSms(SupplierFactory.getUniConfig());
|
|
||||||
case TENCENT:
|
|
||||||
return TencentSmsConfig.createTencentSms(SupplierFactory.getTencentConfig());
|
|
||||||
case JD_CLOUD:
|
|
||||||
return JdCloudSmsConfig.createJdCloudSms(SupplierFactory.getJdCloudConfig());
|
|
||||||
case CLOOPEN:
|
|
||||||
return CloopenSmsConfig.createCloopenSms(SupplierFactory.getCloopenConfig());
|
|
||||||
case EMAY:
|
|
||||||
return EmaySmsConfig.createEmaySms(SupplierFactory.getEmayConfig());
|
|
||||||
}
|
|
||||||
throw new SmsBlendException("An attempt to construct a SmsBlend object failed. Please check that the enumeration is valid");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,13 +48,9 @@ public abstract class SmsFactory {
|
|||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public static void refresh() {
|
public static void refresh() {
|
||||||
AlibabaSmsConfig.refresh(SupplierFactory.getAlibabaConfig());
|
for(SupplierType type : SupplierType.values()) {
|
||||||
HuaweiSmsConfig.refresh(SupplierFactory.getHuaweiConfig());
|
refresh(type);
|
||||||
UniSmsConfig.refresh(SupplierFactory.getUniConfig());
|
}
|
||||||
TencentSmsConfig.refresh(SupplierFactory.getTencentConfig());
|
|
||||||
JdCloudSmsConfig.refresh(SupplierFactory.getJdCloudConfig());
|
|
||||||
CloopenSmsConfig.refresh(SupplierFactory.getCloopenConfig());
|
|
||||||
EmaySmsConfig.refresh(SupplierFactory.getEmayConfig());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,31 +61,8 @@ public abstract class SmsFactory {
|
|||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public static void refresh(SupplierType supplierType) {
|
public static void refresh(SupplierType supplierType) {
|
||||||
switch (supplierType) {
|
BaseProviderFactory providerFactory = supplierType.getProviderFactory();
|
||||||
case ALIBABA:
|
providerFactory.refresh(providerFactory.getConfig());
|
||||||
AlibabaSmsConfig.refresh(SupplierFactory.getAlibabaConfig());
|
|
||||||
break;
|
|
||||||
case HUAWEI:
|
|
||||||
HuaweiSmsConfig.refresh(SupplierFactory.getHuaweiConfig());
|
|
||||||
break;
|
|
||||||
case UNI_SMS:
|
|
||||||
UniSmsConfig.refresh(SupplierFactory.getUniConfig());
|
|
||||||
break;
|
|
||||||
case TENCENT:
|
|
||||||
TencentSmsConfig.refresh(SupplierFactory.getTencentConfig());
|
|
||||||
break;
|
|
||||||
case JD_CLOUD:
|
|
||||||
JdCloudSmsConfig.refresh(SupplierFactory.getJdCloudConfig());
|
|
||||||
break;
|
|
||||||
case CLOOPEN:
|
|
||||||
CloopenSmsConfig.refresh(SupplierFactory.getCloopenConfig());
|
|
||||||
break;
|
|
||||||
case EMAY:
|
|
||||||
EmaySmsConfig.refresh(SupplierFactory.getEmayConfig());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new SmsBlendException("An attempt to construct a SmsBlend object failed. Please check that the enumeration is valid");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,4 +75,44 @@ public abstract class SmsFactory {
|
|||||||
SupplierSqlConfig.refreshSqlConfig();
|
SupplierSqlConfig.refreshSqlConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getRestrictedSmsBlend
|
||||||
|
* <p>获取某个厂商的带有短信拦截的实现
|
||||||
|
*
|
||||||
|
* @param supplierType 厂商枚举
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
public static SmsBlend getRestrictedSmsBlend(SupplierType supplierType) {
|
||||||
|
SmsBlend smsBlend = beans.get(supplierType);
|
||||||
|
if (Objects.isNull(smsBlend)) {
|
||||||
|
smsBlend = getSmsBlend(supplierType);
|
||||||
|
beans.put(supplierType, smsBlend);
|
||||||
|
}
|
||||||
|
return smsBlend;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* refreshRestrictedSmsBlend
|
||||||
|
* <p>刷新带有短信拦截的对象实现
|
||||||
|
* @param supplierType 厂商枚举
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
public static void refreshRestrictedSmsBlend(SupplierType supplierType) {
|
||||||
|
refresh(supplierType);
|
||||||
|
beans.put(supplierType,getSmsBlend(supplierType));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SmsBlend getSmsBlend(SupplierType supplierType) {
|
||||||
|
SmsBlend sms = createSmsBlend(supplierType);
|
||||||
|
SmsInvocationHandler smsInvocationHandler = SmsInvocationHandler.newSmsInvocationHandler(
|
||||||
|
sms,
|
||||||
|
BeanFactory.getSmsConfig()
|
||||||
|
);
|
||||||
|
return (SmsBlend) Proxy.newProxyInstance(
|
||||||
|
sms.getClass().getClassLoader(),
|
||||||
|
new Class[]{SmsBlend.class},
|
||||||
|
smsInvocationHandler
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,8 @@ package org.dromara.sms4j.core.load;
|
|||||||
|
|
||||||
import org.dromara.sms4j.api.SmsBlend;
|
import org.dromara.sms4j.api.SmsBlend;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SmsLoad
|
* SmsLoad
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
|
|
||||||
@ -5,13 +5,14 @@ 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.api.universal.SupplierConfig;
|
||||||
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 implements SupplierConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模板变量名称
|
* 模板变量名称
|
||||||
|
|||||||
@ -0,0 +1,87 @@
|
|||||||
|
package org.dromara.sms4j.aliyun.config;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.aliyun.service.AlibabaSmsImpl;
|
||||||
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
|
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AlibabaSmsConfig
|
||||||
|
* <p> 阿里巴巴对象建造者
|
||||||
|
*
|
||||||
|
* @author :Wind
|
||||||
|
* 2023/4/8 14:54
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
public class AlibabaFactory implements BaseProviderFactory<AlibabaSmsImpl, AlibabaConfig> {
|
||||||
|
|
||||||
|
private static AlibabaSmsImpl alibabaSms;
|
||||||
|
|
||||||
|
private static final AlibabaFactory INSTANCE = new AlibabaFactory();
|
||||||
|
|
||||||
|
private static final class ConfigHolder {
|
||||||
|
private static AlibabaConfig config = AlibabaConfig.builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AlibabaFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取建造者实例
|
||||||
|
* @return 建造者实例
|
||||||
|
*/
|
||||||
|
public static AlibabaFactory instance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建短信实现对象
|
||||||
|
* @param alibabaConfig 短信配置对象
|
||||||
|
* @return 短信实现对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AlibabaSmsImpl createSms(AlibabaConfig alibabaConfig) {
|
||||||
|
if (alibabaSms == null) {
|
||||||
|
alibabaSms = new AlibabaSmsImpl(
|
||||||
|
alibabaConfig,
|
||||||
|
BeanFactory.getExecutor(),
|
||||||
|
BeanFactory.getDelayedTime());
|
||||||
|
}
|
||||||
|
return alibabaSms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新短信实现对象
|
||||||
|
* @param alibabaConfig 短信配置对象
|
||||||
|
* @return 刷新后的短信实现对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AlibabaSmsImpl refresh(AlibabaConfig alibabaConfig) {
|
||||||
|
//重新构造一个实现对象
|
||||||
|
alibabaSms = new AlibabaSmsImpl(
|
||||||
|
alibabaConfig,
|
||||||
|
BeanFactory.getExecutor(),
|
||||||
|
BeanFactory.getDelayedTime());
|
||||||
|
return alibabaSms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置
|
||||||
|
* @return 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AlibabaConfig getConfig() {
|
||||||
|
return ConfigHolder.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置配置
|
||||||
|
* @param config 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setConfig(AlibabaConfig config) {
|
||||||
|
ConfigHolder.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,62 +0,0 @@
|
|||||||
package org.dromara.sms4j.aliyun.config;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.dromara.sms4j.aliyun.service.AlibabaSmsImpl;
|
|
||||||
import org.dromara.sms4j.comm.factory.BeanFactory;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AlibabaSmsConfig
|
|
||||||
* <p> 阿里巴巴对象建造者
|
|
||||||
*
|
|
||||||
* @author :Wind
|
|
||||||
* 2023/4/8 14:54
|
|
||||||
**/
|
|
||||||
@Slf4j
|
|
||||||
public class AlibabaSmsConfig {
|
|
||||||
|
|
||||||
private static AlibabaSmsImpl alibabaSms;
|
|
||||||
|
|
||||||
private static AlibabaSmsConfig alibabaSmsConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getAlibabaSms
|
|
||||||
* <p> 建造一个短信实现对像
|
|
||||||
*
|
|
||||||
* @author :Wind
|
|
||||||
*/
|
|
||||||
public static AlibabaSmsImpl createAlibabaSms(AlibabaConfig alibabaConfig) {
|
|
||||||
if (alibabaSmsConfig == null) {
|
|
||||||
alibabaSmsConfig = new AlibabaSmsConfig();
|
|
||||||
}
|
|
||||||
if (alibabaSms == null) {
|
|
||||||
alibabaSms = new AlibabaSmsImpl(
|
|
||||||
alibabaConfig,
|
|
||||||
BeanFactory.getExecutor(),
|
|
||||||
BeanFactory.getDelayedTime());
|
|
||||||
}
|
|
||||||
return alibabaSms;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* refresh
|
|
||||||
* <p> 刷新对象
|
|
||||||
*
|
|
||||||
* @author :Wind
|
|
||||||
*/
|
|
||||||
public static AlibabaSmsImpl refresh(AlibabaConfig alibabaConfig) {
|
|
||||||
// 如果配置对象为空则创建一个
|
|
||||||
if (alibabaSmsConfig == null) {
|
|
||||||
alibabaSmsConfig = new AlibabaSmsConfig();
|
|
||||||
}
|
|
||||||
//重新构造一个实现对象
|
|
||||||
alibabaSms = new AlibabaSmsImpl(
|
|
||||||
alibabaConfig,
|
|
||||||
BeanFactory.getExecutor(),
|
|
||||||
BeanFactory.getDelayedTime());
|
|
||||||
return alibabaSms;
|
|
||||||
}
|
|
||||||
|
|
||||||
private AlibabaSmsConfig() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,24 +1,21 @@
|
|||||||
package org.dromara.sms4j.aliyun.service;
|
package org.dromara.sms4j.aliyun.service;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import cn.hutool.json.JSONObject;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import cn.hutool.json.JSONUtil;
|
||||||
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.AbstractSmsBlend;
|
||||||
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.utils.SmsUtil;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>类名: AlibabaSmsImpl
|
* <p>类名: AlibabaSmsImpl
|
||||||
@ -29,27 +26,19 @@ import java.util.concurrent.Executor;
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AlibabaSmsImpl implements SmsBlend {
|
public class AlibabaSmsImpl extends AbstractSmsBlend {
|
||||||
|
|
||||||
private final AlibabaConfig alibabaSmsConfig;
|
private final AlibabaConfig alibabaSmsConfig;
|
||||||
|
|
||||||
private final Executor pool;
|
|
||||||
|
|
||||||
private final DelayedTime delayed;
|
|
||||||
|
|
||||||
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) {
|
||||||
|
super(pool, delayedTime);
|
||||||
this.alibabaSmsConfig = alibabaSmsConfig;
|
this.alibabaSmsConfig = alibabaSmsConfig;
|
||||||
this.pool = pool;
|
|
||||||
this.delayed = delayedTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -63,7 +52,7 @@ public class AlibabaSmsImpl implements SmsBlend {
|
|||||||
@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 = JSONUtil.toJsonStr(messages);
|
||||||
return getSmsResponse(phone, messageStr, templateId);
|
return getSmsResponse(phone, messageStr, templateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,12 +67,12 @@ public class AlibabaSmsImpl implements SmsBlend {
|
|||||||
@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 = JSONUtil.toJsonStr(messages);
|
||||||
return getSmsResponse(arrayToString(phones), messageStr, templateId);
|
return getSmsResponse(SmsUtil.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();
|
AtomicReference<SmsResponse> reference = new AtomicReference<>();
|
||||||
String requestUrl;
|
String requestUrl;
|
||||||
String paramStr;
|
String paramStr;
|
||||||
try {
|
try {
|
||||||
@ -94,100 +83,32 @@ public class AlibabaSmsImpl implements SmsBlend {
|
|||||||
throw new SmsBlendException(e.getMessage());
|
throw new SmsBlendException(e.getMessage());
|
||||||
}
|
}
|
||||||
log.debug("requestUrl {}", requestUrl);
|
log.debug("requestUrl {}", requestUrl);
|
||||||
http.post(requestUrl)
|
super.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);
|
reference.set(this.getResponse(res.get(JSONObject.class)));
|
||||||
log.info(jsonBody.toJSONString());
|
|
||||||
}))
|
}))
|
||||||
.onError((ex, req, res) -> {
|
.onError((ex, req, res) -> {
|
||||||
JSONObject jsonBody = res.get(JSONObject.class);
|
reference.set(this.getResponse(res.get(JSONObject.class)));
|
||||||
log.info(jsonBody.toJSONString());
|
|
||||||
})
|
})
|
||||||
.execute();
|
.execute();
|
||||||
|
return reference.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SmsResponse getResponse(JSONObject resJson) {
|
||||||
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
|
if (resJson == null) {
|
||||||
|
smsResponse.setErrorCode("500");
|
||||||
|
smsResponse.setErrMessage("aliyun send sms response is null.check param");
|
||||||
|
return smsResponse;
|
||||||
|
}
|
||||||
|
smsResponse.setCode(resJson.getStr("Code"));
|
||||||
|
smsResponse.setMessage(resJson.getStr("Message"));
|
||||||
|
if ("OK".equals(smsResponse.getCode())) {
|
||||||
|
smsResponse.setBizId(resJson.getStr("BizId"));
|
||||||
|
}
|
||||||
return smsResponse;
|
return smsResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, message), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message) {
|
|
||||||
pool.execute(() -> {
|
|
||||||
sendMessage(phone, message);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone,templateId, messages), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
|
||||||
pool.execute(() -> {
|
|
||||||
sendMessage(phone, templateId, messages);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String arrayToString(List<String> list) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (String s : list) {
|
|
||||||
sb.append(",").append("+86").append(s);
|
|
||||||
}
|
|
||||||
return sb.substring(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -1,14 +1,20 @@
|
|||||||
package org.dromara.sms4j.aliyun.utils;
|
package org.dromara.sms4j.aliyun.utils;
|
||||||
|
|
||||||
import cn.hutool.core.codec.Base64;
|
import cn.hutool.crypto.digest.HMac;
|
||||||
|
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||||
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 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.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.SimpleTimeZone;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Richard
|
* @author Richard
|
||||||
@ -21,18 +27,18 @@ 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 final 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());
|
||||||
@ -80,10 +86,8 @@ public class AliyunUtils {
|
|||||||
* @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");
|
HMac hMac = new HMac(HmacAlgorithm.HmacSHA1, accessSecret.getBytes());
|
||||||
mac.init(new javax.crypto.spec.SecretKeySpec(accessSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA1"));
|
return hMac.digestBase64(stringToSign,StandardCharsets.UTF_8, false);
|
||||||
byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
|
|
||||||
return Base64.encode(signData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -5,6 +5,7 @@ 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.api.universal.SupplierConfig;
|
||||||
import org.dromara.sms4j.comm.config.BaseConfig;
|
import org.dromara.sms4j.comm.config.BaseConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,7 +18,7 @@ import org.dromara.sms4j.comm.config.BaseConfig;
|
|||||||
@SuperBuilder
|
@SuperBuilder
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class CloopenConfig extends BaseConfig {
|
public class CloopenConfig extends BaseConfig implements SupplierConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用 ID
|
* 应用 ID
|
||||||
|
|||||||
@ -0,0 +1,77 @@
|
|||||||
|
package org.dromara.sms4j.cloopen.config;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.dromara.sms4j.cloopen.service.CloopenSmsImpl;
|
||||||
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
|
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 容联云短信配置
|
||||||
|
*
|
||||||
|
* @author Charles7c
|
||||||
|
* @since 2023/4/10 22:10
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class CloopenFactory implements BaseProviderFactory<CloopenSmsImpl, CloopenConfig> {
|
||||||
|
|
||||||
|
private static CloopenSmsImpl cloopenSms;
|
||||||
|
|
||||||
|
private static final CloopenFactory INSTANCE = new CloopenFactory();
|
||||||
|
|
||||||
|
private static final class ConfigHolder {
|
||||||
|
private static CloopenConfig config = CloopenConfig.builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取建造者实例
|
||||||
|
* @return 建造者实例
|
||||||
|
*/
|
||||||
|
public static CloopenFactory instance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建容连云短信实现对象
|
||||||
|
* @param cloopenConfig 短信配置对象
|
||||||
|
* @return 短信实现对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CloopenSmsImpl createSms(CloopenConfig cloopenConfig) {
|
||||||
|
if (cloopenSms == null) {
|
||||||
|
cloopenSms = new CloopenSmsImpl(cloopenConfig, BeanFactory.getExecutor(), BeanFactory.getDelayedTime());
|
||||||
|
}
|
||||||
|
return cloopenSms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新容连云短信实现对象
|
||||||
|
* @param cloopenConfig 短信配置对象
|
||||||
|
* @return 刷新后的短信实现对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CloopenSmsImpl refresh(CloopenConfig cloopenConfig) {
|
||||||
|
//重新构造一个实现对象
|
||||||
|
cloopenSms = new CloopenSmsImpl(cloopenConfig, BeanFactory.getExecutor(), BeanFactory.getDelayedTime());
|
||||||
|
return cloopenSms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置
|
||||||
|
* @return 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CloopenConfig getConfig() {
|
||||||
|
return ConfigHolder.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置配置
|
||||||
|
* @param config 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setConfig(CloopenConfig config) {
|
||||||
|
ConfigHolder.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,44 +0,0 @@
|
|||||||
package org.dromara.sms4j.cloopen.config;
|
|
||||||
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import org.dromara.sms4j.cloopen.service.CloopenSmsImpl;
|
|
||||||
import org.dromara.sms4j.comm.factory.BeanFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 容联云短信配置
|
|
||||||
*
|
|
||||||
* @author Charles7c
|
|
||||||
* @since 2023/4/10 22:10
|
|
||||||
*/
|
|
||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
|
||||||
public class CloopenSmsConfig {
|
|
||||||
|
|
||||||
private static CloopenSmsImpl cloopenSms;
|
|
||||||
|
|
||||||
private static CloopenSmsConfig cloopenSmsConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建容联云短信实现
|
|
||||||
*/
|
|
||||||
public static CloopenSmsImpl createCloopenSms(CloopenConfig cloopenConfig) {
|
|
||||||
if (cloopenSmsConfig == null) {
|
|
||||||
cloopenSmsConfig = new CloopenSmsConfig();
|
|
||||||
}
|
|
||||||
if (cloopenSms == null) {
|
|
||||||
cloopenSms = new CloopenSmsImpl(cloopenConfig, BeanFactory.getExecutor(), BeanFactory.getDelayedTime());
|
|
||||||
}
|
|
||||||
return cloopenSms;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新对象
|
|
||||||
*/
|
|
||||||
public static CloopenSmsImpl refresh(CloopenConfig cloopenConfig) {
|
|
||||||
if (cloopenSmsConfig == null) {
|
|
||||||
cloopenSmsConfig = new CloopenSmsConfig();
|
|
||||||
}
|
|
||||||
cloopenSms = new CloopenSmsImpl(cloopenConfig, BeanFactory.getExecutor(), BeanFactory.getDelayedTime());
|
|
||||||
return cloopenSms;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -4,8 +4,7 @@ import cn.hutool.core.map.MapUtil;
|
|||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
import com.dtflys.forest.Forest;
|
import com.dtflys.forest.Forest;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.sms4j.api.SmsBlend;
|
import org.dromara.sms4j.api.AbstractSmsBlend;
|
||||||
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.cloopen.api.CloopenRestApi;
|
import org.dromara.sms4j.cloopen.api.CloopenRestApi;
|
||||||
import org.dromara.sms4j.cloopen.config.CloopenConfig;
|
import org.dromara.sms4j.cloopen.config.CloopenConfig;
|
||||||
@ -13,8 +12,10 @@ import org.dromara.sms4j.cloopen.util.CloopenHelper;
|
|||||||
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 java.util.*;
|
import java.util.Collections;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,20 +25,15 @@ import java.util.concurrent.Executor;
|
|||||||
* @since 2023/4/10 22:10
|
* @since 2023/4/10 22:10
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CloopenSmsImpl implements SmsBlend {
|
public class CloopenSmsImpl extends AbstractSmsBlend {
|
||||||
|
|
||||||
private final CloopenRestApi restApi;
|
private final CloopenRestApi restApi;
|
||||||
|
|
||||||
private final CloopenConfig config;
|
private final CloopenConfig config;
|
||||||
|
|
||||||
private final Executor pool;
|
|
||||||
|
|
||||||
private final DelayedTime delayed;
|
|
||||||
|
|
||||||
public CloopenSmsImpl(CloopenConfig config, Executor pool, DelayedTime delayed) {
|
public CloopenSmsImpl(CloopenConfig config, Executor pool, DelayedTime delayed) {
|
||||||
|
super(pool,delayed);
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.pool = pool;
|
|
||||||
this.delayed = delayed;
|
|
||||||
restApi = Forest.client(CloopenRestApi.class);
|
restApi = Forest.client(CloopenRestApi.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,74 +68,4 @@ public class CloopenSmsImpl implements SmsBlend {
|
|||||||
paramMap.put("datas", messages.keySet().stream().map(messages::get).toArray(String[]::new));
|
paramMap.put("datas", messages.keySet().stream().map(messages::get).toArray(String[]::new));
|
||||||
return helper.request(restApi::sendSms, paramMap);
|
return helper.request(restApi::sendSms, paramMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, message), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message) {
|
|
||||||
pool.execute(() -> sendMessage(phone, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone,templateId, messages), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
|
||||||
pool.execute(() -> sendMessage(phone, templateId, messages));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,40 @@
|
|||||||
|
package org.dromara.sms4j.ctyun.config;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||||
|
import org.dromara.sms4j.comm.config.BaseConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: CtyunConfig
|
||||||
|
* <p>说明: 天翼云短信差异配置
|
||||||
|
*
|
||||||
|
* @author :bleachhtred
|
||||||
|
* 2023/5/12 15:06
|
||||||
|
**/
|
||||||
|
@Data
|
||||||
|
@SuperBuilder
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class CtyunConfig extends BaseConfig implements SupplierConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板变量名称
|
||||||
|
*/
|
||||||
|
private String templateName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求地址
|
||||||
|
*/
|
||||||
|
@Builder.Default
|
||||||
|
private String requestUrl = "https://sms-global.ctapi.ctyun.cn/sms/api/v1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口名称
|
||||||
|
*/
|
||||||
|
@Builder.Default
|
||||||
|
private String action = "SendSms";
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
package org.dromara.sms4j.ctyun.config;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
|
import org.dromara.sms4j.ctyun.service.CtyunSmsImpl;
|
||||||
|
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: CtyunSmsConfig
|
||||||
|
* <p>说明: 天翼云 云通信短信配置器
|
||||||
|
*
|
||||||
|
* @author :bleachhtred
|
||||||
|
* 2023/5/12 15:06
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
public class CtyunFactory implements BaseProviderFactory<CtyunSmsImpl, CtyunConfig> {
|
||||||
|
|
||||||
|
private static CtyunSmsImpl ctyunSms;
|
||||||
|
|
||||||
|
private static final CtyunFactory INSTANCE = new CtyunFactory();
|
||||||
|
|
||||||
|
private static final class ConfigHolder {
|
||||||
|
private static CtyunConfig config = CtyunConfig.builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private CtyunFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取建造者实例
|
||||||
|
* @return 建造者实例
|
||||||
|
*/
|
||||||
|
public static CtyunFactory instance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getCtyunSms
|
||||||
|
* <p> 建造一个短信实现对像
|
||||||
|
*
|
||||||
|
* @author :bleachhtred
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CtyunSmsImpl createSms(CtyunConfig ctyunConfig) {
|
||||||
|
if (ctyunSms == null) {
|
||||||
|
ctyunSms = new CtyunSmsImpl(
|
||||||
|
ctyunConfig,
|
||||||
|
BeanFactory.getExecutor(),
|
||||||
|
BeanFactory.getDelayedTime());
|
||||||
|
}
|
||||||
|
return ctyunSms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* refresh
|
||||||
|
* <p> 刷新对象
|
||||||
|
*
|
||||||
|
* @author :bleachhtred
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CtyunSmsImpl refresh(CtyunConfig ctyunConfig) {
|
||||||
|
//重新构造一个实现对象
|
||||||
|
ctyunSms = new CtyunSmsImpl(
|
||||||
|
ctyunConfig,
|
||||||
|
BeanFactory.getExecutor(),
|
||||||
|
BeanFactory.getDelayedTime());
|
||||||
|
return ctyunSms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置
|
||||||
|
* @return 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CtyunConfig getConfig() {
|
||||||
|
return ConfigHolder.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置配置
|
||||||
|
* @param config 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setConfig(CtyunConfig config) {
|
||||||
|
ConfigHolder.config = config;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,101 @@
|
|||||||
|
package org.dromara.sms4j.ctyun.service;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.api.AbstractSmsBlend;
|
||||||
|
import org.dromara.sms4j.api.entity.SmsResponse;
|
||||||
|
import org.dromara.sms4j.comm.annotation.Restricted;
|
||||||
|
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
|
||||||
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsUtil;
|
||||||
|
import org.dromara.sms4j.ctyun.config.CtyunConfig;
|
||||||
|
import org.dromara.sms4j.ctyun.utils.CtyunUtils;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>类名: CtyunSmsImpl
|
||||||
|
* <p>说明: 天翼云短信实现
|
||||||
|
*
|
||||||
|
* @author :bleachhtred
|
||||||
|
* 2023/5/12 15:06
|
||||||
|
**/
|
||||||
|
@Slf4j
|
||||||
|
public class CtyunSmsImpl extends AbstractSmsBlend {
|
||||||
|
|
||||||
|
private final CtyunConfig ctyunConfig;
|
||||||
|
|
||||||
|
|
||||||
|
public CtyunSmsImpl(CtyunConfig ctyunConfig, Executor pool, DelayedTime delayedTime) {
|
||||||
|
super(pool, delayedTime);
|
||||||
|
this.ctyunConfig = ctyunConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Restricted
|
||||||
|
public SmsResponse sendMessage(String phone, String message) {
|
||||||
|
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||||
|
map.put(ctyunConfig.getTemplateName(), message);
|
||||||
|
return sendMessage(phone, ctyunConfig.getTemplateId(), map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Restricted
|
||||||
|
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
|
String messageStr = JSONUtil.toJsonStr(messages);
|
||||||
|
return getSmsResponse(phone, messageStr, templateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Restricted
|
||||||
|
public SmsResponse massTexting(List<String> phones, String message) {
|
||||||
|
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||||
|
map.put(ctyunConfig.getTemplateName(), message);
|
||||||
|
return massTexting(phones, ctyunConfig.getTemplateId(), map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Restricted
|
||||||
|
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
|
String messageStr = JSONUtil.toJsonStr(messages);
|
||||||
|
return getSmsResponse(SmsUtil.arrayToString(phones), messageStr, templateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
|
||||||
|
AtomicReference<SmsResponse> smsResponse = new AtomicReference<>();
|
||||||
|
String requestUrl;
|
||||||
|
String paramStr;
|
||||||
|
try {
|
||||||
|
requestUrl = ctyunConfig.getRequestUrl();
|
||||||
|
paramStr = CtyunUtils.generateParamJsonStr(ctyunConfig, phone, message, templateId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("ctyun send message error", e);
|
||||||
|
throw new SmsBlendException(e.getMessage());
|
||||||
|
}
|
||||||
|
log.debug("requestUrl {}", requestUrl);
|
||||||
|
http.post(requestUrl)
|
||||||
|
.addHeader(CtyunUtils.signHeader(paramStr, ctyunConfig.getAccessKeyId(), ctyunConfig.getAccessKeySecret()))
|
||||||
|
.addBody(paramStr)
|
||||||
|
.onSuccess(((data, req, res) -> {
|
||||||
|
smsResponse.set(this.getResponse(res.get(JSONObject.class)));
|
||||||
|
}))
|
||||||
|
.onError((ex, req, res) -> {
|
||||||
|
smsResponse.set(this.getResponse(res.get(JSONObject.class)));
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
return smsResponse.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SmsResponse getResponse(JSONObject resJson) {
|
||||||
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
|
smsResponse.setCode(resJson.getStr("code"));
|
||||||
|
smsResponse.setMessage(resJson.getStr("message"));
|
||||||
|
smsResponse.setBizId(resJson.getStr("requestId"));
|
||||||
|
return smsResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,118 @@
|
|||||||
|
package org.dromara.sms4j.ctyun.utils;
|
||||||
|
|
||||||
|
import cn.hutool.crypto.digest.HMac;
|
||||||
|
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
import org.dromara.sms4j.ctyun.config.CtyunConfig;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class CtyunUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取签名时间戳
|
||||||
|
*/
|
||||||
|
private static String signatureTime(){
|
||||||
|
SimpleDateFormat timeFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
|
||||||
|
return timeFormat.format(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取签名请求头
|
||||||
|
*/
|
||||||
|
public static Map<String, String> signHeader(String body, String key, String secret){
|
||||||
|
Map<String, String> map = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 构造时间戳
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
|
||||||
|
Date now = new Date();
|
||||||
|
String signatureDate = dateFormat.format(now);
|
||||||
|
String signatureTime = signatureTime();
|
||||||
|
// 构造请求流水号
|
||||||
|
String uuid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
String calculateContentHash = getSHA256(body);
|
||||||
|
|
||||||
|
byte[] kTime = hmacSHA256(signatureTime.getBytes(), secret.getBytes());
|
||||||
|
byte[] kAk = hmacSHA256(key.getBytes(), kTime);
|
||||||
|
byte[] kDate = hmacSHA256(signatureDate.getBytes(), kAk);
|
||||||
|
|
||||||
|
// 构造待签名字符串
|
||||||
|
|
||||||
|
// 报文原封不动进行sha256摘要
|
||||||
|
String signatureStr = String.format("ctyun-eop-request-id:%s\neop-date:%s\n", uuid, signatureTime) + "\n\n" + calculateContentHash;
|
||||||
|
// 构造签名
|
||||||
|
String signature = Base64.getEncoder().encodeToString(hmacSHA256(signatureStr.getBytes(StandardCharsets.UTF_8), kDate));
|
||||||
|
String signHeader = String.format("%s Headers=ctyun-eop-request-id;eop-date Signature=%s", key, signature);
|
||||||
|
map.put("Content-Type", "application/json;charset=UTF-8");
|
||||||
|
map.put("ctyun-eop-request-id", uuid);
|
||||||
|
map.put("Eop-date", signatureTime);
|
||||||
|
map.put("Eop-Authorization", signHeader);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成请求body参数
|
||||||
|
*
|
||||||
|
* @param ctyunConfig 配置数据
|
||||||
|
* @param phone 手机号
|
||||||
|
* @param message 短信内容
|
||||||
|
* @param templateId 模板id
|
||||||
|
*/
|
||||||
|
public static String generateParamJsonStr(CtyunConfig ctyunConfig, String phone, String message, String templateId) {
|
||||||
|
Map<String, String> paramMap = new HashMap<>();
|
||||||
|
paramMap.put("action", ctyunConfig.getAction());
|
||||||
|
paramMap.put("phoneNumber", phone);
|
||||||
|
paramMap.put("signName", ctyunConfig.getSignature());
|
||||||
|
paramMap.put("templateParam", message);
|
||||||
|
paramMap.put("templateCode", templateId);
|
||||||
|
return JSONUtil.toJsonStr(paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toHex(byte[] data) {
|
||||||
|
StringBuilder sb = new StringBuilder(data.length * 2);
|
||||||
|
for (byte b : data) {
|
||||||
|
String hex = Integer.toHexString(b);
|
||||||
|
if (hex.length() == 1) {
|
||||||
|
sb.append("0");
|
||||||
|
} else if (hex.length() == 8) {
|
||||||
|
hex = hex.substring(6);
|
||||||
|
}
|
||||||
|
sb.append(hex);
|
||||||
|
}
|
||||||
|
return sb.toString().toLowerCase(Locale.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getSHA256(String text) {
|
||||||
|
try {
|
||||||
|
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||||
|
md.update(text.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return toHex(md.digest());
|
||||||
|
} catch (NoSuchAlgorithmException var3) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] hmacSHA256(byte[] data, byte[] key){
|
||||||
|
try {
|
||||||
|
HMac hMac = new HMac(HmacAlgorithm.HmacSHA256, key);
|
||||||
|
return hMac.digest(data);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new SmsBlendException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@ package org.dromara.sms4j.emay.config;
|
|||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Richard
|
* @author Richard
|
||||||
@ -9,7 +10,7 @@ import lombok.Data;
|
|||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
public class EmayConfig {
|
public class EmayConfig implements SupplierConfig {
|
||||||
/** appKey*/
|
/** appKey*/
|
||||||
private String appId ;
|
private String appId ;
|
||||||
/** appSecret */
|
/** appSecret */
|
||||||
|
|||||||
@ -0,0 +1,75 @@
|
|||||||
|
package org.dromara.sms4j.emay.config;
|
||||||
|
|
||||||
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
|
import org.dromara.sms4j.emay.service.EmaySmsImpl;
|
||||||
|
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EmaySmsConfig
|
||||||
|
* <p> Emay短信对象建造
|
||||||
|
*
|
||||||
|
* @author Richard
|
||||||
|
* @date 2023/04/11 12:00
|
||||||
|
* */
|
||||||
|
public class EmayFactory implements BaseProviderFactory<EmaySmsImpl, EmayConfig> {
|
||||||
|
private static EmaySmsImpl emaySms;
|
||||||
|
private static final EmayFactory INSTANCE = new EmayFactory();
|
||||||
|
|
||||||
|
private static final class ConfigHolder {
|
||||||
|
private static EmayConfig config = EmayConfig.builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmayFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取建造者实例
|
||||||
|
* @return 建造者实例
|
||||||
|
*/
|
||||||
|
public static EmayFactory instance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建亿美软通短信实现对象
|
||||||
|
* @param emayConfig 短信配置对象
|
||||||
|
* @return 短信实现对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public EmaySmsImpl createSms(EmayConfig emayConfig) {
|
||||||
|
if (emaySms == null){
|
||||||
|
emaySms = new EmaySmsImpl(emayConfig, BeanFactory.getExecutor(),BeanFactory.getDelayedTime());
|
||||||
|
}
|
||||||
|
return emaySms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新短信实现对象
|
||||||
|
* @param emayConfig 短信配置对象
|
||||||
|
* @return 刷新后的短信实现对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public EmaySmsImpl refresh(EmayConfig emayConfig){
|
||||||
|
emaySms = new EmaySmsImpl(emayConfig, BeanFactory.getExecutor(),BeanFactory.getDelayedTime());
|
||||||
|
return emaySms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置
|
||||||
|
* @return 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public EmayConfig getConfig() {
|
||||||
|
return ConfigHolder.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置配置
|
||||||
|
* @param config 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setConfig(EmayConfig config) {
|
||||||
|
ConfigHolder.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,40 +0,0 @@
|
|||||||
package org.dromara.sms4j.emay.config;
|
|
||||||
|
|
||||||
import org.dromara.sms4j.emay.service.EmaySmsImpl;
|
|
||||||
import org.dromara.sms4j.comm.factory.BeanFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EmaySmsConfig
|
|
||||||
* <p> Emay短信对象建造
|
|
||||||
*
|
|
||||||
* @author Richard
|
|
||||||
* @date 2023/04/11 12:00
|
|
||||||
* */
|
|
||||||
public class EmaySmsConfig {
|
|
||||||
private static EmaySmsImpl emaySms;
|
|
||||||
private static EmaySmsConfig emaySmsConfig;
|
|
||||||
|
|
||||||
private EmaySmsConfig() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 建造一个亿美软通短信实现*/
|
|
||||||
public static EmaySmsImpl createEmaySms(EmayConfig emayConfig) {
|
|
||||||
if (emaySmsConfig == null){
|
|
||||||
emaySmsConfig = new EmaySmsConfig();
|
|
||||||
}
|
|
||||||
if (emaySms == null){
|
|
||||||
emaySms = new EmaySmsImpl(emayConfig, BeanFactory.getExecutor(),BeanFactory.getDelayedTime());
|
|
||||||
}
|
|
||||||
return emaySms;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 刷新对象*/
|
|
||||||
public static EmaySmsImpl refresh(EmayConfig emayConfig){
|
|
||||||
if (emaySmsConfig == null){
|
|
||||||
emaySmsConfig = new EmaySmsConfig();
|
|
||||||
}
|
|
||||||
emaySms = new EmaySmsImpl(emayConfig, BeanFactory.getExecutor(),BeanFactory.getDelayedTime());
|
|
||||||
return emaySms;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,45 +1,38 @@
|
|||||||
package org.dromara.sms4j.emay.service;
|
package org.dromara.sms4j.emay.service;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import cn.hutool.json.JSONArray;
|
||||||
import com.dtflys.forest.config.ForestConfiguration;
|
import cn.hutool.json.JSONObject;
|
||||||
import org.dromara.sms4j.emay.config.EmayConfig;
|
|
||||||
import org.dromara.sms4j.emay.util.EmayBuilder;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.sms4j.api.SmsBlend;
|
import org.dromara.sms4j.api.AbstractSmsBlend;
|
||||||
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.utils.SmsUtil;
|
||||||
|
import org.dromara.sms4j.emay.config.EmayConfig;
|
||||||
|
import org.dromara.sms4j.emay.util.EmayBuilder;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import static org.dromara.sms4j.comm.utils.SmsUtil.listToString;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Richard
|
* @author Richard
|
||||||
* @date 2023-04-11 12:00
|
* @date 2023-04-11 12:00
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class EmaySmsImpl implements SmsBlend {
|
public class EmaySmsImpl extends AbstractSmsBlend {
|
||||||
public EmaySmsImpl(EmayConfig config, Executor pool, DelayedTime delayed) {
|
public EmaySmsImpl(EmayConfig config, Executor pool, DelayedTime delayed) {
|
||||||
|
super(pool, delayed);
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.pool = pool;
|
|
||||||
this.delayed = delayed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private EmayConfig config;
|
private EmayConfig config;
|
||||||
|
|
||||||
private Executor pool;
|
|
||||||
|
|
||||||
private DelayedTime delayed;
|
|
||||||
|
|
||||||
private final ForestConfiguration http = BeanFactory.getForestConfiguration();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Restricted
|
@Restricted
|
||||||
public SmsResponse sendMessage(String phone, String message) {
|
public SmsResponse sendMessage(String phone, String message) {
|
||||||
@ -71,7 +64,7 @@ public class EmaySmsImpl implements SmsBlend {
|
|||||||
if (phones.size() > 500) {
|
if (phones.size() > 500) {
|
||||||
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于500");
|
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于500");
|
||||||
}
|
}
|
||||||
return sendMessage(listToString(phones), message);
|
return sendMessage(SmsUtil.listToString(phones), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -84,77 +77,7 @@ public class EmaySmsImpl implements SmsBlend {
|
|||||||
for (Map.Entry<String, String> entry : messages.entrySet()) {
|
for (Map.Entry<String, String> entry : messages.entrySet()) {
|
||||||
list.add(entry.getValue());
|
list.add(entry.getValue());
|
||||||
}
|
}
|
||||||
return sendMessage(listToString(phones), EmayBuilder.listToString(list));
|
return sendMessage(SmsUtil.listToString(phones), EmayBuilder.listToString(list));
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, message), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message) {
|
|
||||||
pool.execute(() -> sendMessage(phone, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, templateId, messages), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
|
||||||
pool.execute(() -> sendMessage(phone, templateId, messages));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmsResponse getSendResponse(Map<String, Object> body, String requestUrl) {
|
private SmsResponse getSendResponse(Map<String, Object> body, String requestUrl) {
|
||||||
@ -177,14 +100,25 @@ public class EmaySmsImpl implements SmsBlend {
|
|||||||
|
|
||||||
private static SmsResponse getSmsResponse(JSONObject execute) {
|
private static SmsResponse getSmsResponse(JSONObject execute) {
|
||||||
SmsResponse smsResponse = new SmsResponse();
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
String code = execute.getString("code");
|
if (execute == null) {
|
||||||
|
smsResponse.setErrorCode("500");
|
||||||
|
smsResponse.setErrMessage("emay send sms response is null.check param");
|
||||||
|
return smsResponse;
|
||||||
|
}
|
||||||
|
String code = execute.getStr("code");
|
||||||
|
if (SmsUtil.isEmpty(code)) {
|
||||||
|
smsResponse.setErrorCode("emay response code is null");
|
||||||
|
smsResponse.setErrMessage("emay is error");
|
||||||
|
} else {
|
||||||
smsResponse.setCode(code);
|
smsResponse.setCode(code);
|
||||||
if ("success".equalsIgnoreCase(code)) {
|
if ("success".equalsIgnoreCase(code)) {
|
||||||
JSONObject data = execute.getJSONObject("data");
|
JSONArray data = execute.getJSONArray("data");
|
||||||
String smsId = data.getString("smsId");
|
JSONObject result = (JSONObject) data.get(0);
|
||||||
|
String smsId = result.getStr("smsId");
|
||||||
smsResponse.setBizId(smsId);
|
smsResponse.setBizId(smsId);
|
||||||
}
|
}
|
||||||
smsResponse.setData(execute);
|
smsResponse.setData(execute);
|
||||||
|
}
|
||||||
return smsResponse;
|
return smsResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,11 @@ package org.dromara.sms4j.huawei.config;
|
|||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
public class HuaweiConfig {
|
public class HuaweiConfig implements SupplierConfig {
|
||||||
|
|
||||||
/** appKey*/
|
/** appKey*/
|
||||||
private String appKey ;
|
private String appKey ;
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
package org.dromara.sms4j.huawei.config;
|
||||||
|
|
||||||
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
|
import org.dromara.sms4j.huawei.service.HuaweiSmsImpl;
|
||||||
|
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HuaweiSmsConfig
|
||||||
|
* <p> 华为短信对象建造
|
||||||
|
*
|
||||||
|
* @author :Wind
|
||||||
|
* 2023/4/8 15:27
|
||||||
|
**/
|
||||||
|
public class HuaweiFactory implements BaseProviderFactory<HuaweiSmsImpl, HuaweiConfig> {
|
||||||
|
private static HuaweiSmsImpl huaweiSms;
|
||||||
|
private static final HuaweiFactory INSTANCE = new HuaweiFactory();
|
||||||
|
|
||||||
|
private static final class ConfigHolder {
|
||||||
|
private static HuaweiConfig config = HuaweiConfig.builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private HuaweiFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取建造者实例
|
||||||
|
* @return 建造者实例
|
||||||
|
*/
|
||||||
|
public static HuaweiFactory instance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 建造一个华为短信实现*/
|
||||||
|
@Override
|
||||||
|
public HuaweiSmsImpl createSms(HuaweiConfig huaweiConfig) {
|
||||||
|
if (huaweiSms == null){
|
||||||
|
huaweiSms = new HuaweiSmsImpl(huaweiConfig, BeanFactory.getExecutor(),BeanFactory.getDelayedTime());
|
||||||
|
}
|
||||||
|
return huaweiSms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 刷新对象*/
|
||||||
|
@Override
|
||||||
|
public HuaweiSmsImpl refresh(HuaweiConfig huaweiConfig){
|
||||||
|
huaweiSms = new HuaweiSmsImpl(huaweiConfig, BeanFactory.getExecutor(),BeanFactory.getDelayedTime());
|
||||||
|
return huaweiSms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置
|
||||||
|
* @return 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public HuaweiConfig getConfig() {
|
||||||
|
return ConfigHolder.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置配置
|
||||||
|
* @param config 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setConfig(HuaweiConfig config) {
|
||||||
|
ConfigHolder.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,39 +0,0 @@
|
|||||||
package org.dromara.sms4j.huawei.config;
|
|
||||||
import org.dromara.sms4j.comm.factory.BeanFactory;
|
|
||||||
import org.dromara.sms4j.huawei.service.HuaweiSmsImpl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HuaweiSmsConfig
|
|
||||||
* <p> 华为短信对象建造
|
|
||||||
*
|
|
||||||
* @author :Wind
|
|
||||||
* 2023/4/8 15:27
|
|
||||||
**/
|
|
||||||
public class HuaweiSmsConfig {
|
|
||||||
private static HuaweiSmsImpl huaweiSms;
|
|
||||||
private static HuaweiSmsConfig huaweiSmsConfig;
|
|
||||||
|
|
||||||
private HuaweiSmsConfig() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 建造一个华为短信实现*/
|
|
||||||
public static HuaweiSmsImpl createHuaweiSms(HuaweiConfig huaweiConfig) {
|
|
||||||
if (huaweiSmsConfig == null){
|
|
||||||
huaweiSmsConfig = new HuaweiSmsConfig();
|
|
||||||
}
|
|
||||||
if (huaweiSms == null){
|
|
||||||
huaweiSms = new HuaweiSmsImpl(huaweiConfig, BeanFactory.getExecutor(),BeanFactory.getDelayedTime());
|
|
||||||
}
|
|
||||||
return huaweiSms;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 刷新对象*/
|
|
||||||
public static HuaweiSmsImpl refresh(HuaweiConfig huaweiConfig){
|
|
||||||
if (huaweiSmsConfig == null){
|
|
||||||
huaweiSmsConfig = new HuaweiSmsConfig();
|
|
||||||
}
|
|
||||||
huaweiSms = new HuaweiSmsImpl(huaweiConfig, BeanFactory.getExecutor(),BeanFactory.getDelayedTime());
|
|
||||||
return huaweiSms;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -2,8 +2,6 @@ package org.dromara.sms4j.huawei.entity;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SmsId
|
* SmsId
|
||||||
* <p> 短信ID列表
|
* <p> 短信ID列表
|
||||||
|
|||||||
@ -1,48 +1,40 @@
|
|||||||
package org.dromara.sms4j.huawei.service;
|
package org.dromara.sms4j.huawei.service;
|
||||||
|
|
||||||
import com.dtflys.forest.config.ForestConfiguration;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.api.AbstractSmsBlend;
|
||||||
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.factory.BeanFactory;
|
|
||||||
import org.dromara.sms4j.huawei.config.HuaweiConfig;
|
import org.dromara.sms4j.huawei.config.HuaweiConfig;
|
||||||
import org.dromara.sms4j.huawei.entity.HuaweiResponse;
|
import org.dromara.sms4j.huawei.entity.HuaweiResponse;
|
||||||
import org.dromara.sms4j.huawei.utils.HuaweiBuilder;
|
import org.dromara.sms4j.huawei.utils.HuaweiBuilder;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.dromara.sms4j.api.SmsBlend;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import static org.dromara.sms4j.huawei.utils.HuaweiBuilder.listToString;
|
import static org.dromara.sms4j.huawei.utils.HuaweiBuilder.listToString;
|
||||||
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class HuaweiSmsImpl implements SmsBlend {
|
public class HuaweiSmsImpl extends AbstractSmsBlend {
|
||||||
public HuaweiSmsImpl(HuaweiConfig config, Executor pool, DelayedTime delayed) {
|
public HuaweiSmsImpl(HuaweiConfig config, Executor pool, DelayedTime delayed) {
|
||||||
|
super(pool,delayed);
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.pool = pool;
|
|
||||||
this.delayed = delayed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HuaweiConfig config;
|
private HuaweiConfig config;
|
||||||
|
|
||||||
private Executor pool;
|
|
||||||
|
|
||||||
private DelayedTime delayed;
|
|
||||||
|
|
||||||
private final ForestConfiguration http = BeanFactory.getForestConfiguration();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Restricted
|
@Restricted
|
||||||
public SmsResponse sendMessage(String phone, String message) {
|
public SmsResponse sendMessage(String phone, String message) {
|
||||||
LinkedHashMap<String,String> mes = new LinkedHashMap<>();
|
LinkedHashMap<String, String> mes = new LinkedHashMap<>();
|
||||||
mes.put(UUID.randomUUID().toString().replaceAll("-",""),message);
|
mes.put(UUID.randomUUID().toString().replaceAll("-", ""), message);
|
||||||
return sendMessage(phone,config.getTemplateId(),mes);
|
return sendMessage(phone, config.getTemplateId(), mes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -55,26 +47,30 @@ public class HuaweiSmsImpl implements SmsBlend {
|
|||||||
}
|
}
|
||||||
String mess = listToString(list);
|
String mess = listToString(list);
|
||||||
String requestBody = HuaweiBuilder.buildRequestBody(config.getSender(), phone, templateId, mess, config.getStatusCallBack(), config.getSignature());
|
String requestBody = HuaweiBuilder.buildRequestBody(config.getSender(), phone, templateId, mess, config.getStatusCallBack(), config.getSignature());
|
||||||
Map<String,String> headers = new LinkedHashMap<>();
|
Map<String, String> headers = new LinkedHashMap<>();
|
||||||
headers.put("Authorization",Constant.HUAWEI_AUTH_HEADER_VALUE);
|
headers.put("Authorization", Constant.HUAWEI_AUTH_HEADER_VALUE);
|
||||||
headers.put("X-WSSE",HuaweiBuilder.buildWsseHeader(config.getAppKey(), config.getAppSecret()));
|
headers.put("X-WSSE", HuaweiBuilder.buildWsseHeader(config.getAppKey(), config.getAppSecret()));
|
||||||
headers.put("Content-Type",Constant.FROM_URLENCODED);
|
headers.put("Content-Type", Constant.FROM_URLENCODED);
|
||||||
SmsResponse smsResponse = new SmsResponse();
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
http.post(url)
|
http.post(url)
|
||||||
.addHeader(headers)
|
.addHeader(headers)
|
||||||
.addBody(requestBody)
|
.addBody(requestBody)
|
||||||
.onSuccess(((data,req,res)->{
|
.onSuccess(((data, req, res) -> {
|
||||||
HuaweiResponse jsonBody = res.get(HuaweiResponse.class);
|
HuaweiResponse jsonBody = res.get(HuaweiResponse.class);
|
||||||
smsResponse.setCode(jsonBody.getCode());
|
smsResponse.setCode(jsonBody.getCode());
|
||||||
smsResponse.setMessage(jsonBody.getDescription());
|
smsResponse.setMessage(jsonBody.getDescription());
|
||||||
smsResponse.setBizId(jsonBody.getResult().get(0).getSmsMsgId());
|
smsResponse.setBizId(jsonBody.getResult().get(0).getSmsMsgId());
|
||||||
smsResponse.setData(jsonBody.getResult());
|
smsResponse.setData(jsonBody.getResult());
|
||||||
}))
|
}))
|
||||||
.onError((ex,req,res)->{
|
.onError((ex, req, res) -> {
|
||||||
HuaweiResponse huaweiResponse = res.get(HuaweiResponse.class);
|
HuaweiResponse huaweiResponse = res.get(HuaweiResponse.class);
|
||||||
|
if (huaweiResponse == null) {
|
||||||
|
smsResponse.setErrorCode("500");
|
||||||
|
smsResponse.setErrMessage("huawei send sms response is null.check param");
|
||||||
|
} else {
|
||||||
smsResponse.setErrMessage(huaweiResponse.getDescription());
|
smsResponse.setErrMessage(huaweiResponse.getDescription());
|
||||||
smsResponse.setErrorCode(huaweiResponse.getCode());
|
smsResponse.setErrorCode(huaweiResponse.getCode());
|
||||||
log.debug(huaweiResponse.getDescription());
|
}
|
||||||
})
|
})
|
||||||
.execute();
|
.execute();
|
||||||
return smsResponse;
|
return smsResponse;
|
||||||
@ -83,7 +79,7 @@ public class HuaweiSmsImpl implements SmsBlend {
|
|||||||
@Override
|
@Override
|
||||||
@Restricted
|
@Restricted
|
||||||
public SmsResponse massTexting(List<String> phones, String message) {
|
public SmsResponse massTexting(List<String> phones, String message) {
|
||||||
return sendMessage(listToString(phones),message);
|
return sendMessage(listToString(phones), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -91,76 +87,4 @@ public class HuaweiSmsImpl implements SmsBlend {
|
|||||||
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
return sendMessage(listToString(phones), templateId, messages);
|
return sendMessage(listToString(phones), templateId, messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, message), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message) {
|
|
||||||
pool.execute(() -> sendMessage(phone, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, templateId, messages), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
|
||||||
pool.execute(() -> {
|
|
||||||
sendMessage(phone, templateId, messages);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,12 @@ import java.security.cert.CertificateException;
|
|||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.Base64;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class HuaweiBuilder {
|
public class HuaweiBuilder {
|
||||||
private HuaweiBuilder(){}
|
private HuaweiBuilder(){}
|
||||||
@ -122,8 +127,9 @@ public class HuaweiBuilder {
|
|||||||
stringBuffer.append(s);
|
stringBuffer.append(s);
|
||||||
stringBuffer.append("\"");
|
stringBuffer.append("\"");
|
||||||
stringBuffer.append(",");
|
stringBuffer.append(",");
|
||||||
|
stringBuffer.append("\"");
|
||||||
}
|
}
|
||||||
stringBuffer.deleteCharAt(stringBuffer.length()-1);
|
stringBuffer.delete(stringBuffer.length()-3,stringBuffer.length()-1);
|
||||||
stringBuffer.append("]");
|
stringBuffer.append("]");
|
||||||
return stringBuffer.toString();
|
return stringBuffer.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ 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.api.universal.SupplierConfig;
|
||||||
import org.dromara.sms4j.comm.config.BaseConfig;
|
import org.dromara.sms4j.comm.config.BaseConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,7 +18,7 @@ import org.dromara.sms4j.comm.config.BaseConfig;
|
|||||||
@SuperBuilder
|
@SuperBuilder
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class JdCloudConfig extends BaseConfig {
|
public class JdCloudConfig extends BaseConfig implements SupplierConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 地域信息
|
* 地域信息
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import com.jdcloud.sdk.http.Protocol;
|
|||||||
import com.jdcloud.sdk.service.sms.client.SmsClient;
|
import com.jdcloud.sdk.service.sms.client.SmsClient;
|
||||||
import org.dromara.sms4j.comm.factory.BeanFactory;
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
import org.dromara.sms4j.jdcloud.service.JdCloudSmsImpl;
|
import org.dromara.sms4j.jdcloud.service.JdCloudSmsImpl;
|
||||||
|
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 京东云短信配置
|
* 京东云短信配置
|
||||||
@ -14,11 +15,26 @@ import org.dromara.sms4j.jdcloud.service.JdCloudSmsImpl;
|
|||||||
* @author Charles7c
|
* @author Charles7c
|
||||||
* @since 2023/4/10 20:01
|
* @since 2023/4/10 20:01
|
||||||
*/
|
*/
|
||||||
public class JdCloudSmsConfig {
|
public class JdCloudFactory implements BaseProviderFactory<JdCloudSmsImpl, JdCloudConfig> {
|
||||||
|
|
||||||
private static JdCloudSmsImpl jdCloudSms;
|
private static JdCloudSmsImpl jdCloudSms;
|
||||||
|
|
||||||
private static JdCloudSmsConfig jdCloudSmsConfig;
|
private static final JdCloudFactory INSTANCE = new JdCloudFactory();
|
||||||
|
|
||||||
|
private static final class ConfigHolder {
|
||||||
|
private static JdCloudConfig config = JdCloudConfig.builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private JdCloudFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取建造者实例
|
||||||
|
* @return 建造者实例
|
||||||
|
*/
|
||||||
|
public static JdCloudFactory instance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户端对象
|
* 客户端对象
|
||||||
@ -36,13 +52,11 @@ public class JdCloudSmsConfig {
|
|||||||
/**
|
/**
|
||||||
* 创建京东云短信实现
|
* 创建京东云短信实现
|
||||||
*/
|
*/
|
||||||
public static JdCloudSmsImpl createJdCloudSms(JdCloudConfig jdCloudConfig) {
|
@Override
|
||||||
if (jdCloudSmsConfig == null) {
|
public JdCloudSmsImpl createSms(JdCloudConfig jdCloudConfig) {
|
||||||
jdCloudSmsConfig = new JdCloudSmsConfig();
|
|
||||||
}
|
|
||||||
if (jdCloudSms == null) {
|
if (jdCloudSms == null) {
|
||||||
jdCloudSms = new JdCloudSmsImpl(
|
jdCloudSms = new JdCloudSmsImpl(
|
||||||
jdCloudSmsConfig.client(jdCloudConfig),
|
this.client(jdCloudConfig),
|
||||||
jdCloudConfig,
|
jdCloudConfig,
|
||||||
BeanFactory.getExecutor(),
|
BeanFactory.getExecutor(),
|
||||||
BeanFactory.getDelayedTime()
|
BeanFactory.getDelayedTime()
|
||||||
@ -54,16 +68,33 @@ public class JdCloudSmsConfig {
|
|||||||
/**
|
/**
|
||||||
* 刷新对象
|
* 刷新对象
|
||||||
*/
|
*/
|
||||||
public static JdCloudSmsImpl refresh(JdCloudConfig jdCloudConfig) {
|
@Override
|
||||||
if (jdCloudSmsConfig == null) {
|
public JdCloudSmsImpl refresh(JdCloudConfig jdCloudConfig) {
|
||||||
jdCloudSmsConfig = new JdCloudSmsConfig();
|
|
||||||
}
|
|
||||||
jdCloudSms = new JdCloudSmsImpl(
|
jdCloudSms = new JdCloudSmsImpl(
|
||||||
jdCloudSmsConfig.client(jdCloudConfig),
|
this.client(jdCloudConfig),
|
||||||
jdCloudConfig,
|
jdCloudConfig,
|
||||||
BeanFactory.getExecutor(),
|
BeanFactory.getExecutor(),
|
||||||
BeanFactory.getDelayedTime()
|
BeanFactory.getDelayedTime()
|
||||||
);
|
);
|
||||||
return jdCloudSms;
|
return jdCloudSms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置
|
||||||
|
* @return 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public JdCloudConfig getConfig() {
|
||||||
|
return ConfigHolder.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置配置
|
||||||
|
* @param config 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setConfig(JdCloudConfig config) {
|
||||||
|
ConfigHolder.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -5,8 +5,7 @@ import com.jdcloud.sdk.service.sms.client.SmsClient;
|
|||||||
import com.jdcloud.sdk.service.sms.model.BatchSendRequest;
|
import com.jdcloud.sdk.service.sms.model.BatchSendRequest;
|
||||||
import com.jdcloud.sdk.service.sms.model.BatchSendResult;
|
import com.jdcloud.sdk.service.sms.model.BatchSendResult;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.sms4j.api.SmsBlend;
|
import org.dromara.sms4j.api.AbstractSmsBlend;
|
||||||
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;
|
||||||
@ -16,8 +15,6 @@ import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -28,21 +25,16 @@ import java.util.stream.Collectors;
|
|||||||
* @since 2023/4/10 20:01
|
* @since 2023/4/10 20:01
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class JdCloudSmsImpl implements SmsBlend {
|
public class JdCloudSmsImpl extends AbstractSmsBlend {
|
||||||
|
|
||||||
private final SmsClient client;
|
private final SmsClient client;
|
||||||
|
|
||||||
private final JdCloudConfig config;
|
private final JdCloudConfig config;
|
||||||
|
|
||||||
private final Executor pool;
|
|
||||||
|
|
||||||
private final DelayedTime delayed;
|
|
||||||
|
|
||||||
public JdCloudSmsImpl(SmsClient client, JdCloudConfig config, Executor pool, DelayedTime delayed) {
|
public JdCloudSmsImpl(SmsClient client, JdCloudConfig config, Executor pool, DelayedTime delayed) {
|
||||||
|
super(pool,delayed);
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.pool = pool;
|
|
||||||
this.delayed = delayed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -85,76 +77,6 @@ public class JdCloudSmsImpl implements SmsBlend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, message), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message) {
|
|
||||||
pool.execute(() -> sendMessage(phone, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, templateId, messages), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
|
||||||
pool.execute(() -> sendMessage(phone, templateId, messages));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取短信返回信息
|
* 获取短信返回信息
|
||||||
*
|
*
|
||||||
|
|||||||
@ -0,0 +1,40 @@
|
|||||||
|
package org.dromara.sms4j.provider.base;
|
||||||
|
|
||||||
|
import org.dromara.sms4j.api.SmsBlend;
|
||||||
|
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AlibabaSmsConfig
|
||||||
|
* <p>短信对象建造者</p>
|
||||||
|
* @param <S> 短信对象
|
||||||
|
* @param <C> 短信配置对象
|
||||||
|
*/
|
||||||
|
public interface BaseProviderFactory<S extends SmsBlend, C extends SupplierConfig> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建短信实现对象
|
||||||
|
* @param c 短信配置对象
|
||||||
|
* @return 短信实现对象
|
||||||
|
*/
|
||||||
|
S createSms(C c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新短信实现对象
|
||||||
|
* @param c 短信配置对象
|
||||||
|
* @return 刷新后的短信实现对象
|
||||||
|
*/
|
||||||
|
S refresh(C c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置
|
||||||
|
* @return 配置对象
|
||||||
|
*/
|
||||||
|
C getConfig();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置配置
|
||||||
|
* @param config 配置对象
|
||||||
|
*/
|
||||||
|
void setConfig(C config);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
package org.dromara.sms4j.provider.enumerate;
|
||||||
|
|
||||||
|
import org.dromara.sms4j.aliyun.config.AlibabaFactory;
|
||||||
|
import org.dromara.sms4j.api.SmsBlend;
|
||||||
|
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||||
|
import org.dromara.sms4j.cloopen.config.CloopenFactory;
|
||||||
|
import org.dromara.sms4j.ctyun.config.CtyunFactory;
|
||||||
|
import org.dromara.sms4j.emay.config.EmayFactory;
|
||||||
|
import org.dromara.sms4j.huawei.config.HuaweiFactory;
|
||||||
|
import org.dromara.sms4j.jdcloud.config.JdCloudFactory;
|
||||||
|
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
||||||
|
import org.dromara.sms4j.tencent.config.TencentFactory;
|
||||||
|
import org.dromara.sms4j.unisms.config.UniFactory;
|
||||||
|
import org.dromara.sms4j.yunpian.config.YunPianFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SupplierType
|
||||||
|
* <p> 短信供应商枚举
|
||||||
|
* @author :Wind
|
||||||
|
* 2023/4/7 20:55
|
||||||
|
**/
|
||||||
|
public enum SupplierType {
|
||||||
|
/** 阿里云*/
|
||||||
|
ALIBABA("阿里云短信", AlibabaFactory.instance()),
|
||||||
|
/** 华为云*/
|
||||||
|
HUAWEI("华为云短信", HuaweiFactory.instance()),
|
||||||
|
/** 云片*/
|
||||||
|
YUNPIAN("云片短信", YunPianFactory.instance()),
|
||||||
|
/** 腾讯云*/
|
||||||
|
TENCENT("腾讯云短信", TencentFactory.instance()),
|
||||||
|
/** 合一短信*/
|
||||||
|
UNI_SMS("合一短信", UniFactory.instance()),
|
||||||
|
/** 京东云 */
|
||||||
|
JD_CLOUD("京东云短信", JdCloudFactory.instance()),
|
||||||
|
/** 容联云 */
|
||||||
|
CLOOPEN("容联云短信", CloopenFactory.instance()),
|
||||||
|
/** 亿美软通*/
|
||||||
|
EMAY("亿美软通", EmayFactory.instance()),
|
||||||
|
/** 天翼云 */
|
||||||
|
CTYUN("天翼云短信", CtyunFactory.instance()),
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渠道名称
|
||||||
|
*/
|
||||||
|
private final String name;
|
||||||
|
/**
|
||||||
|
* 短信对象配置
|
||||||
|
*/
|
||||||
|
private final BaseProviderFactory<? extends SmsBlend, ? extends SupplierConfig> providerFactory;
|
||||||
|
|
||||||
|
|
||||||
|
SupplierType(String name, BaseProviderFactory<? extends SmsBlend, ? extends SupplierConfig> providerFactory) {
|
||||||
|
this.name = name;
|
||||||
|
this.providerFactory = providerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseProviderFactory<? extends SmsBlend, ? extends SupplierConfig> getProviderFactory() {
|
||||||
|
return providerFactory;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,13 +5,14 @@ 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.api.universal.SupplierConfig;
|
||||||
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 implements SupplierConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 短信sdkAppId
|
* 短信sdkAppId
|
||||||
|
|||||||
@ -0,0 +1,81 @@
|
|||||||
|
package org.dromara.sms4j.tencent.config;
|
||||||
|
|
||||||
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
|
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
||||||
|
import org.dromara.sms4j.tencent.service.TencentSmsImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TencentSmsConfig
|
||||||
|
* <p> 建造腾讯云短信
|
||||||
|
*
|
||||||
|
* @author :Wind
|
||||||
|
* 2023/4/8 16:05
|
||||||
|
**/
|
||||||
|
public class TencentFactory implements BaseProviderFactory<TencentSmsImpl, TencentConfig> {
|
||||||
|
|
||||||
|
private static TencentSmsImpl tencentSms;
|
||||||
|
|
||||||
|
private static final TencentFactory INSTANCE = new TencentFactory();
|
||||||
|
|
||||||
|
private static final class ConfigHolder {
|
||||||
|
private static TencentConfig config = TencentConfig.builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private TencentFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取建造者实例
|
||||||
|
* @return 建造者实例
|
||||||
|
*/
|
||||||
|
public static TencentFactory instance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 建造一个腾讯云的短信实现
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TencentSmsImpl createSms(TencentConfig tencentConfig) {
|
||||||
|
if (tencentSms == null) {
|
||||||
|
tencentSms = new TencentSmsImpl(
|
||||||
|
tencentConfig,
|
||||||
|
BeanFactory.getExecutor(),
|
||||||
|
BeanFactory.getDelayedTime()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return tencentSms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TencentSmsImpl refresh(TencentConfig tencentConfig) {
|
||||||
|
tencentSms = new TencentSmsImpl(
|
||||||
|
tencentConfig,
|
||||||
|
BeanFactory.getExecutor(),
|
||||||
|
BeanFactory.getDelayedTime()
|
||||||
|
);
|
||||||
|
return tencentSms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置
|
||||||
|
* @return 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TencentConfig getConfig() {
|
||||||
|
return ConfigHolder.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置配置
|
||||||
|
* @param config 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setConfig(TencentConfig config) {
|
||||||
|
ConfigHolder.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,52 +0,0 @@
|
|||||||
package org.dromara.sms4j.tencent.config;
|
|
||||||
|
|
||||||
import org.dromara.sms4j.comm.factory.BeanFactory;
|
|
||||||
import org.dromara.sms4j.tencent.service.TencentSmsImpl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TencentSmsConfig
|
|
||||||
* <p> 建造腾讯云短信
|
|
||||||
*
|
|
||||||
* @author :Wind
|
|
||||||
* 2023/4/8 16:05
|
|
||||||
**/
|
|
||||||
public class TencentSmsConfig {
|
|
||||||
private TencentSmsConfig() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TencentSmsImpl tencentSms;
|
|
||||||
|
|
||||||
private static TencentSmsConfig tencentSmsConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 建造一个腾讯云的短信实现
|
|
||||||
*/
|
|
||||||
public static TencentSmsImpl createTencentSms(TencentConfig tencentConfig) {
|
|
||||||
if (tencentSmsConfig == null) {
|
|
||||||
tencentSmsConfig = new TencentSmsConfig();
|
|
||||||
}
|
|
||||||
if (tencentSms == null) {
|
|
||||||
tencentSms = new TencentSmsImpl(
|
|
||||||
tencentConfig,
|
|
||||||
BeanFactory.getExecutor(),
|
|
||||||
BeanFactory.getDelayedTime()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return tencentSms;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新对象
|
|
||||||
*/
|
|
||||||
public static TencentSmsImpl refresh(TencentConfig tencentConfig) {
|
|
||||||
if (tencentSmsConfig == null) {
|
|
||||||
tencentSmsConfig = new TencentSmsConfig();
|
|
||||||
}
|
|
||||||
tencentSms = new TencentSmsImpl(
|
|
||||||
tencentConfig,
|
|
||||||
BeanFactory.getExecutor(),
|
|
||||||
BeanFactory.getDelayedTime()
|
|
||||||
);
|
|
||||||
return tencentSms;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,39 +1,36 @@
|
|||||||
package org.dromara.sms4j.tencent.service;
|
package org.dromara.sms4j.tencent.service;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import cn.hutool.json.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import com.dtflys.forest.config.ForestConfiguration;
|
import com.jdcloud.sdk.utils.StringUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.sms4j.api.SmsBlend;
|
import org.dromara.sms4j.api.AbstractSmsBlend;
|
||||||
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.utils.SmsUtil;
|
||||||
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.ArrayList;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author wind
|
||||||
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class TencentSmsImpl implements SmsBlend {
|
public class TencentSmsImpl extends AbstractSmsBlend {
|
||||||
|
|
||||||
private TencentConfig tencentSmsConfig;
|
private TencentConfig tencentSmsConfig;
|
||||||
|
|
||||||
private Executor pool;
|
|
||||||
|
|
||||||
private DelayedTime delayed;
|
|
||||||
|
|
||||||
private final ForestConfiguration http = BeanFactory.getForestConfiguration();
|
|
||||||
|
|
||||||
public TencentSmsImpl(TencentConfig tencentSmsConfig, Executor pool, DelayedTime delayed) {
|
public TencentSmsImpl(TencentConfig tencentSmsConfig, Executor pool, DelayedTime delayed) {
|
||||||
|
super(pool, delayed);
|
||||||
this.tencentSmsConfig = tencentSmsConfig;
|
this.tencentSmsConfig = tencentSmsConfig;
|
||||||
this.pool = pool;
|
|
||||||
this.delayed = delayed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -77,7 +74,7 @@ public class TencentSmsImpl implements SmsBlend {
|
|||||||
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(SmsUtil.listToArray(phones), list.toArray(s), templateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmsResponse getSmsResponse(String[] phones, String[] messages, String templateId) {
|
private SmsResponse getSmsResponse(String[] phones, String[] messages, String templateId) {
|
||||||
@ -101,102 +98,31 @@ public class TencentSmsImpl implements SmsBlend {
|
|||||||
.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");
|
||||||
|
String error = response.getStr("Error");
|
||||||
|
if (StringUtils.isNotBlank(error)){
|
||||||
|
smsResponse.setErrorCode("500");
|
||||||
|
smsResponse.setErrMessage(error);
|
||||||
|
}else {
|
||||||
JSONArray sendStatusSet = response.getJSONArray("SendStatusSet");
|
JSONArray sendStatusSet = response.getJSONArray("SendStatusSet");
|
||||||
smsResponse.setBizId(sendStatusSet.getJSONObject(0).getString("SerialNo"));
|
smsResponse.setBizId(sendStatusSet.getJSONObject(0).getStr("SerialNo"));
|
||||||
smsResponse.setMessage(sendStatusSet.getJSONObject(0).getString("Message"));
|
smsResponse.setMessage(sendStatusSet.getJSONObject(0).getStr("Message"));
|
||||||
smsResponse.setCode(sendStatusSet.getJSONObject(0).getString("Code"));
|
smsResponse.setCode(sendStatusSet.getJSONObject(0).getStr("Code"));
|
||||||
|
}
|
||||||
}))
|
}))
|
||||||
.onError((ex, req, res) -> {
|
.onError((ex, req, res) -> {
|
||||||
JSONObject jsonBody = res.get(JSONObject.class);
|
JSONObject jsonBody = res.get(JSONObject.class);
|
||||||
|
if (jsonBody == null) {
|
||||||
|
smsResponse.setErrorCode("500");
|
||||||
|
smsResponse.setErrMessage("tencent send sms response is null.check param");
|
||||||
|
} else {
|
||||||
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).getStr("Message"));
|
||||||
smsResponse.setErrorCode(sendStatusSet.getJSONObject(0).getString("Code"));
|
smsResponse.setErrorCode(sendStatusSet.getJSONObject(0).getStr("Code"));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.execute();
|
.execute();
|
||||||
return smsResponse;
|
return smsResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, message), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message) {
|
|
||||||
pool.execute(() -> {
|
|
||||||
sendMessage(phone, message);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, templateId, messages), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
|
||||||
pool.execute(() -> {
|
|
||||||
sendMessage(phone, templateId, messages);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String[] arrayToString(List<String> list) {
|
|
||||||
String[] strs = new String[list.size()];
|
|
||||||
List<String> toStr = new ArrayList<>();
|
|
||||||
for (String s : list) {
|
|
||||||
toStr.add("+86" + s);
|
|
||||||
}
|
|
||||||
return toStr.toArray(strs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -58,16 +58,14 @@ public class TencentUtils {
|
|||||||
*/
|
*/
|
||||||
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:拼接规范请求串 *************
|
|
||||||
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\nhost:" + tencentConfig.getRequestUrl() + "\n";
|
||||||
String signedHeaders = "content-type;host";
|
String signedHeaders = "content-type;host";
|
||||||
HashMap<String, Object> params = new HashMap<>();
|
Map<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());
|
||||||
@ -75,20 +73,15 @@ public class TencentUtils {
|
|||||||
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;
|
String credentialScope = date + "/" + tencentConfig.getService() + "/tc3_request";
|
||||||
// ************* 步骤 2:拼接待签名字符串 *************
|
|
||||||
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:计算签名 *************
|
|
||||||
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 *************
|
return ALGORITHM + " Credential=" + tencentConfig.getAccessKeyId() + "/" + credentialScope + ", SignedHeaders=" + signedHeaders + ", Signature=" + signature;
|
||||||
return ALGORITHM + " " + "Credential=" + tencentConfig.getAccessKeyId() + "/" + credentialScope + ", "
|
|
||||||
+ "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -5,13 +5,14 @@ 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.api.universal.SupplierConfig;
|
||||||
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 UniConfig extends BaseConfig {
|
public class UniConfig extends BaseConfig implements SupplierConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否为简易模式
|
* 是否为简易模式
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package org.dromara.sms4j.unisms.config;
|
package org.dromara.sms4j.unisms.config;
|
||||||
|
|
||||||
import org.dromara.sms4j.comm.factory.BeanFactory;
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
|
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
||||||
import org.dromara.sms4j.unisms.core.Uni;
|
import org.dromara.sms4j.unisms.core.Uni;
|
||||||
import org.dromara.sms4j.unisms.service.UniSmsImpl;
|
import org.dromara.sms4j.unisms.service.UniSmsImpl;
|
||||||
|
|
||||||
@ -10,14 +11,27 @@ import org.dromara.sms4j.unisms.service.UniSmsImpl;
|
|||||||
* @author :Wind
|
* @author :Wind
|
||||||
* 2023/4/8 15:46
|
* 2023/4/8 15:46
|
||||||
**/
|
**/
|
||||||
public class UniSmsConfig {
|
public class UniFactory implements BaseProviderFactory<UniSmsImpl, UniConfig> {
|
||||||
|
|
||||||
private UniSmsConfig(){}
|
|
||||||
|
|
||||||
private static UniSmsConfig uniSmsConfig;
|
|
||||||
|
|
||||||
private static UniSmsImpl uniSmsImpl;
|
private static UniSmsImpl uniSmsImpl;
|
||||||
|
|
||||||
|
private static final UniFactory INSTANCE = new UniFactory();
|
||||||
|
|
||||||
|
private static final class ConfigHolder {
|
||||||
|
private static UniConfig config = UniConfig.builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private UniFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取建造者实例
|
||||||
|
* @return 建造者实例
|
||||||
|
*/
|
||||||
|
public static UniFactory instance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** 短信配置*/
|
/** 短信配置*/
|
||||||
private void buildSms(UniConfig uniConfig){
|
private void buildSms(UniConfig uniConfig){
|
||||||
@ -33,12 +47,10 @@ public class UniSmsConfig {
|
|||||||
* <p>建造一个短信实现对像
|
* <p>建造一个短信实现对像
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public static UniSmsImpl createUniSms(UniConfig uniConfig){
|
@Override
|
||||||
if (uniSmsConfig == null){
|
public UniSmsImpl createSms(UniConfig uniConfig){
|
||||||
uniSmsConfig = new UniSmsConfig();
|
|
||||||
}
|
|
||||||
if (uniSmsImpl == null){
|
if (uniSmsImpl == null){
|
||||||
uniSmsConfig.buildSms(uniConfig);
|
this.buildSms(uniConfig);
|
||||||
uniSmsImpl = new UniSmsImpl(
|
uniSmsImpl = new UniSmsImpl(
|
||||||
uniConfig,
|
uniConfig,
|
||||||
BeanFactory.getExecutor(),
|
BeanFactory.getExecutor(),
|
||||||
@ -53,11 +65,9 @@ public class UniSmsConfig {
|
|||||||
* <p>刷新对象
|
* <p>刷新对象
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public static UniSmsImpl refresh(UniConfig uniConfig){
|
@Override
|
||||||
if (uniSmsConfig == null){
|
public UniSmsImpl refresh(UniConfig uniConfig){
|
||||||
uniSmsConfig = new UniSmsConfig();
|
this.buildSms(uniConfig);
|
||||||
}
|
|
||||||
uniSmsConfig.buildSms(uniConfig);
|
|
||||||
uniSmsImpl = new UniSmsImpl(
|
uniSmsImpl = new UniSmsImpl(
|
||||||
uniConfig,
|
uniConfig,
|
||||||
BeanFactory.getExecutor(),
|
BeanFactory.getExecutor(),
|
||||||
@ -65,4 +75,23 @@ public class UniSmsConfig {
|
|||||||
);
|
);
|
||||||
return uniSmsImpl;
|
return uniSmsImpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置
|
||||||
|
* @return 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public UniConfig getConfig() {
|
||||||
|
return ConfigHolder.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置配置
|
||||||
|
* @param config 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setConfig(UniConfig config) {
|
||||||
|
ConfigHolder.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package org.dromara.sms4j.unisms.core;
|
package org.dromara.sms4j.unisms.core;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.dtflys.forest.config.ForestConfiguration;
|
import com.dtflys.forest.config.ForestConfiguration;
|
||||||
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;
|
||||||
@ -79,6 +79,7 @@ public class UniClient {
|
|||||||
/**
|
/**
|
||||||
* request
|
* request
|
||||||
* <p>向 uni-sms发送请求
|
* <p>向 uni-sms发送请求
|
||||||
|
*
|
||||||
* @param action 接口名称
|
* @param action 接口名称
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
@ -91,12 +92,10 @@ public class UniClient {
|
|||||||
headers.put("User-Agent", USER_AGENT);
|
headers.put("User-Agent", USER_AGENT);
|
||||||
headers.put("Content-Type", "application/json;charset=utf-8");
|
headers.put("Content-Type", "application/json;charset=utf-8");
|
||||||
headers.put("Accept", "application/json");
|
headers.put("Accept", "application/json");
|
||||||
return new UniResponse(
|
String str = http.post(this.endpoint)
|
||||||
JSONObject.parseObject(
|
|
||||||
http.post(this.endpoint)
|
|
||||||
.addHeader(headers)
|
.addHeader(headers)
|
||||||
.addQuery(this.sign(query))
|
.addQuery(this.sign(query))
|
||||||
.addBody(JSONObject.toJSONString(data))
|
.addBody(JSONUtil.toJsonStr(data))
|
||||||
.successWhen(((req, res) -> {
|
.successWhen(((req, res) -> {
|
||||||
return res.noException() && // 请求过程没有异常
|
return res.noException() && // 请求过程没有异常
|
||||||
res.statusIsNot(500); // 不能是 500
|
res.statusIsNot(500); // 不能是 500
|
||||||
@ -104,8 +103,8 @@ public class UniClient {
|
|||||||
.onError((ex, req, res) -> {
|
.onError((ex, req, res) -> {
|
||||||
throw new SmsBlendException(ex.getMessage());
|
throw new SmsBlendException(ex.getMessage());
|
||||||
})
|
})
|
||||||
.executeAsString()
|
.executeAsString();
|
||||||
));
|
return new UniResponse(JSONUtil.parseObj(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
package org.dromara.sms4j.unisms.core;
|
package org.dromara.sms4j.unisms.core;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
||||||
public class UniResponse {
|
public class UniResponse {
|
||||||
public static final String REQUEST_ID_HEADER_KEY = "x-uni-request-id";
|
public static final String REQUEST_ID_HEADER_KEY = "x-uni-request-id";
|
||||||
@ -20,22 +22,23 @@ public class UniResponse {
|
|||||||
*/
|
*/
|
||||||
public UniResponse(final JSONObject response) throws SmsBlendException {
|
public UniResponse(final JSONObject response) throws SmsBlendException {
|
||||||
JSONObject body = response.getJSONObject("data");
|
JSONObject body = response.getJSONObject("data");
|
||||||
this.status = body.getJSONArray("messages").getJSONObject(0).getString("status");
|
if (!Objects.isNull(body)) {
|
||||||
this.requestId = body.getJSONArray("messages").getJSONObject(0).getString("id");
|
this.status = body.getJSONArray("messages").getJSONObject(0).getStr("status");
|
||||||
|
this.requestId = body.getJSONArray("messages").getJSONObject(0).getStr("id");
|
||||||
this.raw = body;
|
this.raw = body;
|
||||||
|
|
||||||
if (this.status != "400") {
|
|
||||||
String code = response.getString("code");
|
|
||||||
String message = body.getJSONArray("messages").getString(0);
|
|
||||||
if (!"0".equals(code)) {
|
|
||||||
throw new SmsBlendException(message, code, this.requestId);
|
|
||||||
}
|
|
||||||
this.code = code;
|
|
||||||
this.message = message;
|
|
||||||
this.data = body;
|
this.data = body;
|
||||||
}
|
}
|
||||||
else {
|
if (this.status != "400") {
|
||||||
throw new SmsBlendException(response.getString("message"), "-1");
|
String code = response.getStr("code");
|
||||||
|
if (!"0".equals(code)) {
|
||||||
|
this.message = response.getStr("message");
|
||||||
|
} else {
|
||||||
|
this.message = body.getJSONArray("messages").getStr(0);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
this.code = code;
|
||||||
|
} else {
|
||||||
|
throw new SmsBlendException(response.getStr("message"), "-1");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
package org.dromara.sms4j.unisms.service;
|
package org.dromara.sms4j.unisms.service;
|
||||||
|
|
||||||
import org.dromara.sms4j.api.SmsBlend;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.sms4j.api.callback.CallBack;
|
import org.dromara.sms4j.api.AbstractSmsBlend;
|
||||||
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.unisms.config.UniConfig;
|
import org.dromara.sms4j.unisms.config.UniConfig;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.dromara.sms4j.unisms.core.Uni;
|
import org.dromara.sms4j.unisms.core.Uni;
|
||||||
import org.dromara.sms4j.unisms.core.UniResponse;
|
import org.dromara.sms4j.unisms.core.UniResponse;
|
||||||
|
|
||||||
@ -16,11 +15,7 @@ import java.util.HashMap;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,16 +26,13 @@ import java.util.function.Supplier;
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class UniSmsImpl implements SmsBlend {
|
public class UniSmsImpl extends AbstractSmsBlend {
|
||||||
|
|
||||||
private UniConfig config;
|
private UniConfig config;
|
||||||
private Executor pool;
|
|
||||||
private DelayedTime delayed;
|
|
||||||
|
|
||||||
public UniSmsImpl(UniConfig config, Executor pool, DelayedTime delayed) {
|
public UniSmsImpl(UniConfig config, Executor pool, DelayedTime delayed) {
|
||||||
|
super(pool,delayed);
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.pool = pool;
|
|
||||||
this.delayed = delayed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -90,76 +82,6 @@ public class UniSmsImpl implements SmsBlend {
|
|||||||
return getSmsResponse(data);
|
return getSmsResponse(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, message), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendMessageAsync(String phone, String message) {
|
|
||||||
pool.execute(()->{
|
|
||||||
sendMessage(phone, message);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, templateId, messages), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
|
||||||
pool.execute(()->{
|
|
||||||
sendMessage(phone,templateId,messages);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone,message);
|
|
||||||
}
|
|
||||||
},delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone,templateId,messages);
|
|
||||||
}
|
|
||||||
},delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones,message);
|
|
||||||
}
|
|
||||||
},delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones,templateId,messages);
|
|
||||||
}
|
|
||||||
},delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SmsResponse getSmsResponse( Map<String, Object> data) {
|
private SmsResponse getSmsResponse( Map<String, Object> data) {
|
||||||
SmsResponse smsResponse = new SmsResponse();
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -0,0 +1,72 @@
|
|||||||
|
package org.dromara.sms4j.yunpian.config;
|
||||||
|
|
||||||
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
|
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
||||||
|
import org.dromara.sms4j.yunpian.service.YunPianSmsImpl;
|
||||||
|
|
||||||
|
public class YunPianFactory implements BaseProviderFactory<YunPianSmsImpl, YunpianConfig> {
|
||||||
|
|
||||||
|
private static YunPianSmsImpl yunpianSmsImpl;
|
||||||
|
|
||||||
|
private static final YunPianFactory INSTANCE = new YunPianFactory();
|
||||||
|
|
||||||
|
private static final class ConfigHolder {
|
||||||
|
private static YunpianConfig config = YunpianConfig.builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private YunPianFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取建造者实例
|
||||||
|
* @return 建造者实例
|
||||||
|
*/
|
||||||
|
public static YunPianFactory instance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 建造一个云片短信实现
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public YunPianSmsImpl createSms(YunpianConfig yunpianConfig){
|
||||||
|
if (yunpianSmsImpl == null){
|
||||||
|
yunpianSmsImpl = new YunPianSmsImpl(
|
||||||
|
BeanFactory.getExecutor(),
|
||||||
|
BeanFactory.getDelayedTime(),
|
||||||
|
yunpianConfig
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return yunpianSmsImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 刷新对象*/
|
||||||
|
@Override
|
||||||
|
public YunPianSmsImpl refresh(YunpianConfig yunpianConfig){
|
||||||
|
yunpianSmsImpl = new YunPianSmsImpl(
|
||||||
|
BeanFactory.getExecutor(),
|
||||||
|
BeanFactory.getDelayedTime(),
|
||||||
|
yunpianConfig
|
||||||
|
);
|
||||||
|
return yunpianSmsImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置
|
||||||
|
* @return 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public YunpianConfig getConfig() {
|
||||||
|
return ConfigHolder.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置配置
|
||||||
|
* @param config 配置对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setConfig(YunpianConfig config) {
|
||||||
|
ConfigHolder.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,24 +0,0 @@
|
|||||||
package org.dromara.sms4j.yunpian.config;
|
|
||||||
|
|
||||||
import com.dtflys.forest.Forest;
|
|
||||||
import com.dtflys.forest.config.ForestConfiguration;
|
|
||||||
import org.dromara.sms4j.api.SmsBlend;
|
|
||||||
import org.dromara.sms4j.yunpian.service.YunPianSmsImpl;
|
|
||||||
|
|
||||||
public class YunPianSmsConfig {
|
|
||||||
|
|
||||||
|
|
||||||
public YunpianConfig yunpianConfig(){
|
|
||||||
return YunpianConfig.builder().build();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ForestConfiguration forestConfiguration(YunpianConfig yunpianConfig) {
|
|
||||||
return Forest.config().setBackendName("httpclient");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public SmsBlend smsBlend() {
|
|
||||||
return new YunPianSmsImpl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,26 +1,22 @@
|
|||||||
package org.dromara.sms4j.yunpian.config;
|
package org.dromara.sms4j.yunpian.config;
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||||
|
import org.dromara.sms4j.comm.config.BaseConfig;
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@SuperBuilder
|
||||||
public class YunpianConfig {
|
@ToString(callSuper = true)
|
||||||
/**
|
@EqualsAndHashCode(callSuper = true)
|
||||||
* 账号唯一标识
|
public class YunpianConfig extends BaseConfig implements SupplierConfig {
|
||||||
*/
|
|
||||||
private String apikey;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 短信发送后将向这个地址推送(运营商返回的)发送报告
|
* 短信发送后将向这个地址推送(运营商返回的)发送报告
|
||||||
*/
|
*/
|
||||||
private String callbackUrl;
|
private String callbackUrl;
|
||||||
|
|
||||||
/**
|
|
||||||
* 模板Id
|
|
||||||
*/
|
|
||||||
private String templateId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模板变量名称
|
* 模板变量名称
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,40 +1,46 @@
|
|||||||
package org.dromara.sms4j.yunpian.service;
|
package org.dromara.sms4j.yunpian.service;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import com.dtflys.forest.config.ForestConfiguration;
|
import org.dromara.sms4j.api.AbstractSmsBlend;
|
||||||
import org.dromara.sms4j.api.SmsBlend;
|
|
||||||
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.utils.SmsUtil;
|
||||||
import org.dromara.sms4j.yunpian.config.YunpianConfig;
|
import org.dromara.sms4j.yunpian.config.YunpianConfig;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import static org.dromara.sms4j.comm.utils.SmsUtil.listToString;
|
/**
|
||||||
|
* @author wind
|
||||||
|
*/
|
||||||
|
public class YunPianSmsImpl extends AbstractSmsBlend {
|
||||||
|
|
||||||
public class YunPianSmsImpl implements SmsBlend {
|
public YunPianSmsImpl(Executor pool, DelayedTime delayed, YunpianConfig config) {
|
||||||
|
super(pool, delayed);
|
||||||
private Executor pool;
|
this.config = config;
|
||||||
|
}
|
||||||
private DelayedTime delayed;
|
|
||||||
|
|
||||||
private YunpianConfig config;
|
private YunpianConfig config;
|
||||||
|
|
||||||
private ForestConfiguration http;
|
|
||||||
|
|
||||||
private static SmsResponse getSmsResponse(JSONObject execute) {
|
private static SmsResponse getSmsResponse(JSONObject execute) {
|
||||||
SmsResponse smsResponse = new SmsResponse();
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
smsResponse.setCode(execute.getString("code"));
|
if (execute == null) {
|
||||||
smsResponse.setMessage(execute.getString("msg"));
|
smsResponse.setErrorCode("500");
|
||||||
smsResponse.setBizId(execute.getString("sid"));
|
smsResponse.setErrMessage("yunpian send sms response is null.check param");
|
||||||
if (execute.getInteger("code") != 0) {
|
return smsResponse;
|
||||||
smsResponse.setErrMessage(execute.getString("msg"));
|
}
|
||||||
|
smsResponse.setCode(execute.getStr("code"));
|
||||||
|
smsResponse.setMessage(execute.getStr("msg"));
|
||||||
|
smsResponse.setBizId(execute.getStr("sid"));
|
||||||
|
if (execute.getInt("code") != 0) {
|
||||||
|
smsResponse.setErrMessage(execute.getStr("msg"));
|
||||||
}
|
}
|
||||||
smsResponse.setData(execute);
|
smsResponse.setData(execute);
|
||||||
return smsResponse;
|
return smsResponse;
|
||||||
@ -50,7 +56,7 @@ public class YunPianSmsImpl implements SmsBlend {
|
|||||||
@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) {
|
||||||
Map<String, String> body = setBody(phone, "", messages,templateId);
|
Map<String, String> body = setBody(phone, "", messages, templateId);
|
||||||
return getSendResponse(body);
|
return getSendResponse(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +66,7 @@ public class YunPianSmsImpl implements SmsBlend {
|
|||||||
if (phones.size() > 1000) {
|
if (phones.size() > 1000) {
|
||||||
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于1000");
|
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于1000");
|
||||||
}
|
}
|
||||||
return sendMessage(listToString(phones), message);
|
return sendMessage(SmsUtil.listToString(phones), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -69,79 +75,7 @@ public class YunPianSmsImpl implements SmsBlend {
|
|||||||
if (phones.size() > 1000) {
|
if (phones.size() > 1000) {
|
||||||
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于1000");
|
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于1000");
|
||||||
}
|
}
|
||||||
return sendMessage(listToString(phones), templateId, messages);
|
return sendMessage(SmsUtil.listToString(phones), templateId, messages);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, message), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String message) {
|
|
||||||
pool.execute(() -> sendMessage(phone, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages, CallBack callBack) {
|
|
||||||
CompletableFuture<SmsResponse> smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, templateId, messages), pool);
|
|
||||||
smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
|
||||||
pool.execute(() -> {
|
|
||||||
sendMessage(phone, templateId, messages);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayedMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
sendMessage(phone, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String message, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, message);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Restricted
|
|
||||||
public void delayMassTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime) {
|
|
||||||
this.delayed.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
massTexting(phones, templateId, messages);
|
|
||||||
}
|
|
||||||
}, delayedTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formattingMap(Map<String, String> messages) {
|
private String formattingMap(Map<String, String> messages) {
|
||||||
@ -165,11 +99,12 @@ public class YunPianSmsImpl implements SmsBlend {
|
|||||||
message.put(config.getTemplateName(), mes);
|
message.put(config.getTemplateName(), mes);
|
||||||
}
|
}
|
||||||
Map<String, String> body = new HashMap<>();
|
Map<String, String> body = new HashMap<>();
|
||||||
body.put("apikey", config.getApikey());
|
body.put("apikey", config.getAccessKeyId());
|
||||||
body.put("mobile", phone);
|
body.put("mobile", phone);
|
||||||
body.put("tpl_id", tplId);
|
body.put("tpl_id", tplId);
|
||||||
body.put("tpl_value", formattingMap(message));
|
body.put("tpl_value", formattingMap(message));
|
||||||
if (!config.getCallbackUrl().isEmpty()) body.put("callback_url", config.getCallbackUrl());
|
if (config.getCallbackUrl() != null && !config.getCallbackUrl().isEmpty())
|
||||||
|
body.put("callback_url", config.getCallbackUrl());
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +117,7 @@ public class YunPianSmsImpl implements SmsBlend {
|
|||||||
|
|
||||||
private SmsResponse getSendResponse(Map<String, String> body) {
|
private SmsResponse getSendResponse(Map<String, String> body) {
|
||||||
Map<String, String> headers = getHeaders();
|
Map<String, String> headers = getHeaders();
|
||||||
AtomicReference<SmsResponse> smsResponse = null;
|
AtomicReference<SmsResponse> smsResponse = new AtomicReference<>();
|
||||||
http.post(Constant.YUNPIAN_URL + "/sms/tpl_single_send.json")
|
http.post(Constant.YUNPIAN_URL + "/sms/tpl_single_send.json")
|
||||||
.addHeader(headers)
|
.addHeader(headers)
|
||||||
.addBody(body)
|
.addBody(body)
|
||||||
|
|||||||
43
sms4j-solon-plugin/pom.xml
Normal file
43
sms4j-solon-plugin/pom.xml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?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-solon-plugin</artifactId>
|
||||||
|
|
||||||
|
<name>sms4j-solon-plugin</name>
|
||||||
|
<description>sms4j-solon-plugin</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!--aop依赖-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.noear</groupId>
|
||||||
|
<artifactId>solon</artifactId>
|
||||||
|
<version>${solon.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara.sms4j</groupId>
|
||||||
|
<artifactId>sms4j-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<artifactId>redisson</artifactId>
|
||||||
|
<version>${redisson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.noear</groupId>
|
||||||
|
<artifactId>solon-test</artifactId>
|
||||||
|
<version>${solon.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package org.dromara.sms4j.solon;
|
||||||
|
|
||||||
|
import org.dromara.sms4j.solon.config.SmsAutowiredConfig;
|
||||||
|
import org.noear.solon.core.AopContext;
|
||||||
|
import org.noear.solon.core.Plugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author noear 2023/5/16 created
|
||||||
|
*/
|
||||||
|
public class XPluginImpl implements Plugin {
|
||||||
|
@Override
|
||||||
|
public void start(AopContext context) throws Throwable {
|
||||||
|
context.beanMake(SmsAutowiredConfig.class);
|
||||||
|
SmsAutowiredConfig.aopContext = context;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
package org.dromara.sms4j.solon.aop;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.api.smsProxy.RestrictedProcess;
|
||||||
|
import org.dromara.sms4j.comm.config.SmsConfig;
|
||||||
|
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsUtil;
|
||||||
|
import org.dromara.sms4j.solon.utils.RedisUtils;
|
||||||
|
import org.noear.solon.core.AopContext;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class SolonRestrictedProcess extends RestrictedProcess {
|
||||||
|
|
||||||
|
private RedisUtils redis;
|
||||||
|
private static final Long minTimer = 60 * 1000L;
|
||||||
|
private static final Long accTimer = 24 * 60 * 60 * 1000L;
|
||||||
|
private static final String REDIS_KEY = "sms:restricted:";
|
||||||
|
|
||||||
|
public SolonRestrictedProcess(AopContext context){
|
||||||
|
context.getBeanAsync(RedisUtils.class, bean->{
|
||||||
|
redis = bean;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsBlendException process(SmsConfig config, String args) throws Exception {
|
||||||
|
Integer accountMax = config.getAccountMax();//每日最大发送量
|
||||||
|
Integer minuteMax = config.getMinuteMax();//每分钟最大发送量
|
||||||
|
if (SmsUtil.isNotEmpty(accountMax)) { //是否配置了每日限制
|
||||||
|
Integer i = (Integer) redis.getByKey(REDIS_KEY+args + "max");
|
||||||
|
if (SmsUtil.isEmpty(i)) {
|
||||||
|
redis.setOrTime(REDIS_KEY+args + "max", 1,accTimer/1000);
|
||||||
|
} else if (i > accountMax) {
|
||||||
|
log.info("The phone:"+args +",number of short messages reached the maximum today");
|
||||||
|
return new SmsBlendException("The phone:"+args +",number of short messages reached the maximum today");
|
||||||
|
} else {
|
||||||
|
redis.setOrTime(REDIS_KEY+args + "max", i + 1,accTimer/1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (SmsUtil.isNotEmpty(minuteMax)) { //是否配置了每分钟最大限制
|
||||||
|
Integer o = (Integer) redis.getByKey(REDIS_KEY+args);
|
||||||
|
if (SmsUtil.isNotEmpty(o)) {
|
||||||
|
if (o < minuteMax) {
|
||||||
|
redis.setOrTime(REDIS_KEY+args, o + 1,minTimer/1000);
|
||||||
|
} else {
|
||||||
|
log.info("The phone:"+args +",number of short messages reached the maximum today");
|
||||||
|
return new SmsBlendException("The phone:", args + " Text messages are sent too often!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
redis.setOrTime(REDIS_KEY+args, 1,minTimer/1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
package org.dromara.sms4j.solon.config;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.api.smsProxy.SmsInvocationHandler;
|
||||||
|
import org.dromara.sms4j.comm.config.SmsBanner;
|
||||||
|
import org.dromara.sms4j.comm.config.SmsConfig;
|
||||||
|
import org.dromara.sms4j.comm.config.SmsSqlConfig;
|
||||||
|
import org.dromara.sms4j.comm.constant.Constant;
|
||||||
|
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
|
||||||
|
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||||
|
import org.dromara.sms4j.core.SupplierSqlConfig;
|
||||||
|
import org.dromara.sms4j.solon.aop.SolonRestrictedProcess;
|
||||||
|
import org.dromara.sms4j.solon.utils.RedisUtils;
|
||||||
|
import org.noear.solon.Solon;
|
||||||
|
import org.noear.solon.Utils;
|
||||||
|
import org.noear.solon.annotation.Bean;
|
||||||
|
import org.noear.solon.annotation.Condition;
|
||||||
|
import org.noear.solon.annotation.Configuration;
|
||||||
|
import org.noear.solon.annotation.Inject;
|
||||||
|
import org.noear.solon.core.AopContext;
|
||||||
|
import org.noear.solon.core.Props;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
public class SmsAutowiredConfig {
|
||||||
|
|
||||||
|
public static AopContext aopContext;
|
||||||
|
|
||||||
|
private <T> T injectObj(String prefix, T obj) {
|
||||||
|
//@Inject 只支持在字段、参数、类型上注入
|
||||||
|
Props props = Solon.cfg().getProp(prefix);
|
||||||
|
Utils.injectProperties(obj, props);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SmsSqlConfig smsSqlConfig() {
|
||||||
|
return injectObj("sms.sql", BeanFactory.getSmsSqlConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SmsConfig smsConfig(){
|
||||||
|
SmsConfig smsConfig = injectObj("sms", BeanFactory.getSmsConfig());
|
||||||
|
|
||||||
|
smsConfigCheck();
|
||||||
|
|
||||||
|
return smsConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 注入一个定时器*/
|
||||||
|
@Bean
|
||||||
|
public DelayedTime delayedTime(){
|
||||||
|
return BeanFactory.getDelayedTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 注入线程池*/
|
||||||
|
@Bean("smsExecutor")
|
||||||
|
public Executor taskExecutor(@Inject SmsConfig config){
|
||||||
|
return BeanFactory.setExecutor(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** smsConfig参数意义为确保注入时smsConfig已经存在*/
|
||||||
|
@Bean
|
||||||
|
@Condition(onProperty ="${sms.config-type}=config_file")
|
||||||
|
public SupplierConfig supplierConfig(@Inject SmsConfig smsConfig){
|
||||||
|
return new SupplierConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Condition(onProperty ="${sms.config-type}=sql_config")
|
||||||
|
public SupplierSqlConfig supplierSqlConfig(@Inject SmsSqlConfig smsSqlConfig){
|
||||||
|
return new SupplierSqlConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void smsConfigCheck(){
|
||||||
|
/* 如果配置中启用了redis,则注入redis工具*/
|
||||||
|
if (BeanFactory.getSmsConfig().getRedisCache()){
|
||||||
|
Solon.context().wrapAndPut(RedisUtils.class);
|
||||||
|
SmsInvocationHandler.setRestrictedProcess(new SolonRestrictedProcess(aopContext));
|
||||||
|
log.debug("The redis cache is enabled for sms4j");
|
||||||
|
}
|
||||||
|
|
||||||
|
//打印banner
|
||||||
|
if (BeanFactory.getSmsConfig().getIsPrint()){
|
||||||
|
SmsBanner.PrintBanner(Constant.VERSION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
package org.dromara.sms4j.solon.config;
|
||||||
|
|
||||||
|
import org.dromara.sms4j.aliyun.config.AlibabaConfig;
|
||||||
|
import org.dromara.sms4j.cloopen.config.CloopenConfig;
|
||||||
|
import org.dromara.sms4j.core.config.SupplierFactory;
|
||||||
|
import org.dromara.sms4j.ctyun.config.CtyunConfig;
|
||||||
|
import org.dromara.sms4j.emay.config.EmayConfig;
|
||||||
|
import org.dromara.sms4j.huawei.config.HuaweiConfig;
|
||||||
|
import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
|
||||||
|
import org.dromara.sms4j.tencent.config.TencentConfig;
|
||||||
|
import org.dromara.sms4j.unisms.config.UniConfig;
|
||||||
|
import org.dromara.sms4j.yunpian.config.YunpianConfig;
|
||||||
|
import org.noear.solon.Solon;
|
||||||
|
import org.noear.solon.Utils;
|
||||||
|
import org.noear.solon.annotation.Bean;
|
||||||
|
import org.noear.solon.annotation.Configuration;
|
||||||
|
import org.noear.solon.core.Props;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class SupplierConfig {
|
||||||
|
private <T> T injectObj(String prefix, T obj) {
|
||||||
|
//@Inject 只支持在字段、参数、类型上注入
|
||||||
|
Props props = Solon.cfg().getProp(prefix);
|
||||||
|
Utils.injectProperties(obj, props);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 阿里差异化配置*/
|
||||||
|
@Bean
|
||||||
|
public AlibabaConfig alibabaConfig(){
|
||||||
|
return injectObj("sms.alibaba", SupplierFactory.getAlibabaConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 华为差异化配置*/
|
||||||
|
@Bean
|
||||||
|
public HuaweiConfig huaweiConfig(){
|
||||||
|
return injectObj("sms.huawei", SupplierFactory.getHuaweiConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 云片短信差异化配置*/
|
||||||
|
@Bean
|
||||||
|
public YunpianConfig yunpianConfig(){
|
||||||
|
return injectObj("sms.yunpian", SupplierFactory.getYunpianConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 合一短信差异化配置*/
|
||||||
|
@Bean
|
||||||
|
public UniConfig uniConfig(){
|
||||||
|
return injectObj("sms.uni", SupplierFactory.getUniConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 腾讯短信差异化配置*/
|
||||||
|
@Bean
|
||||||
|
public TencentConfig tencentConfig(){
|
||||||
|
return injectObj("sms.tencent", SupplierFactory.getTencentConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 京东云短信差异化配置 */
|
||||||
|
@Bean
|
||||||
|
public JdCloudConfig jdCloudConfig(){
|
||||||
|
return injectObj("sms.jdcloud", SupplierFactory.getJdCloudConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 容联云短信差异化配置 */
|
||||||
|
@Bean
|
||||||
|
public CloopenConfig cloopenConfig(){
|
||||||
|
return injectObj("sms.cloopen", SupplierFactory.getCloopenConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 亿美软通短信差异化配置
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public EmayConfig emayConfig(){
|
||||||
|
return injectObj("sms.emay", SupplierFactory.getEmayConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 天翼云短信差异化配置 */
|
||||||
|
@Bean
|
||||||
|
public CtyunConfig ctyunConfig(){
|
||||||
|
return injectObj("sms.ctyun", SupplierFactory.getCtyunConfig());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,468 @@
|
|||||||
|
package org.dromara.sms4j.solon.utils;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.noear.solon.Solon;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class RedisUtils {
|
||||||
|
|
||||||
|
private RedissonClient redisTemplate;
|
||||||
|
|
||||||
|
public RedisUtils() {
|
||||||
|
Thread t = new Thread(()->{
|
||||||
|
//如果获取到的bean为null则等待后重试,最多重试五次
|
||||||
|
for(int i = 0; i < 5 ;i++){
|
||||||
|
RedissonClient bean = Solon.context().getBean(RedissonClient.class);
|
||||||
|
if (Objects.isNull(bean)){
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
redisTemplate = bean;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RedisUtils(RedissonClient redisTemplate) {
|
||||||
|
this.redisTemplate = redisTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 说明:设置redis的key的到期时间
|
||||||
|
*
|
||||||
|
* @param key redis的key
|
||||||
|
* @param time 到期时间
|
||||||
|
* @name: setTimeByKey
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
public boolean setTimeByKey(String key, Long time) {
|
||||||
|
try {
|
||||||
|
if (time > 0) {
|
||||||
|
redisTemplate.getBucket(key).expire(time, TimeUnit.SECONDS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 说明:放入redis
|
||||||
|
*
|
||||||
|
* @param key 要放入的key
|
||||||
|
* @param value 要放入的value
|
||||||
|
* @name: set
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
public boolean set(String key, Object value) {
|
||||||
|
redisTemplate.getBucket(key).set(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 说明:放入带过期时间的缓存
|
||||||
|
*
|
||||||
|
* @param time 到期时间(秒)
|
||||||
|
* @name: setOrTime
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
public boolean setOrTime(String key, Object value, Long time) {
|
||||||
|
try {
|
||||||
|
redisTemplate.getBucket(key).set(value, time, TimeUnit.SECONDS);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:将Map中的数据批量放置到redis中
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* @param valueMap 要放入的数据
|
||||||
|
* @name: multiSet
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
public boolean multiSet(Map valueMap) {
|
||||||
|
try {
|
||||||
|
valueMap.forEach((key, val) -> {
|
||||||
|
redisTemplate.getBucket((String) key).set(val);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.toString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 说明:获取key对应的值
|
||||||
|
*
|
||||||
|
* @param key 要查询的key
|
||||||
|
* @name: getByKey
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
public Object getByKey(String key) {
|
||||||
|
return redisTemplate.getBucket(key).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>说明:获取字符串型值
|
||||||
|
*
|
||||||
|
* @param
|
||||||
|
* @name: getKyeString
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
public String getKyeString(String key) {
|
||||||
|
return (String) getByKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 说明:判断key是否存在
|
||||||
|
*
|
||||||
|
* @param key 要判断的key
|
||||||
|
* @name: hasKey
|
||||||
|
* @author :Wind
|
||||||
|
*/
|
||||||
|
public Boolean hasKey(String key) {
|
||||||
|
return redisTemplate.getBucket(key).isExists();
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 说明:根据key删除redis缓存可以批量删除
|
||||||
|
// *
|
||||||
|
// * @param key 要删除的key
|
||||||
|
// * @name: deleteKey
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Boolean deleteKey(String... key) {
|
||||||
|
// if (key != null && key.length > 0) {
|
||||||
|
// if (key.length == 1) {
|
||||||
|
// return redisTemplate.getBucket(key[0]).delete();
|
||||||
|
// } else {
|
||||||
|
// Long delete = redisTemplate.(Arrays.asList(key));
|
||||||
|
// return delete >= 1L;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public Boolean delete(String key) {
|
||||||
|
// Set<String> keys = redisTemplate.keys(key + "*");
|
||||||
|
// redisTemplate.removeByKeys(keys);
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 根据key 获取key的过期时间
|
||||||
|
// *
|
||||||
|
// * @param key 键 不能为null
|
||||||
|
// * @return 时间(秒) 返回-1, 代表为永久有效
|
||||||
|
// */
|
||||||
|
// public Long getKeyExpire(String key) {
|
||||||
|
// return redisTemplate.ttl(key);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 修改redis中key的名称
|
||||||
|
// *
|
||||||
|
// * @param oldKey 旧的key值
|
||||||
|
// * @param newKey 新的key值
|
||||||
|
// */
|
||||||
|
// public void renameKey(String oldKey, String newKey) {
|
||||||
|
// redisTemplate..ren(oldKey, newKey);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * <p>说明:将map对象存入redis
|
||||||
|
// * <p>
|
||||||
|
// *
|
||||||
|
// * @param map 要存入redis中的map
|
||||||
|
// * @name: setMap
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public <T, M> void MapSetMap(String key, Map<T, M> map) {
|
||||||
|
// redisClient.getHash(key).putAll(map);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * <p>说明:获取所有hash表中字段
|
||||||
|
// * <p>
|
||||||
|
// *
|
||||||
|
// * @param
|
||||||
|
// * @name: getMapByKey
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Set<Object> MapGetHashByKey(String key) {
|
||||||
|
// return redisTemplate.opsForHash().keys(key);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * <p>说明:根据key和fieId获取对应的值
|
||||||
|
// * <p>
|
||||||
|
// *
|
||||||
|
// * @param fieId hash中的fieId也是Map的Key
|
||||||
|
// * @name: getValueByFieID
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Object MapGetValueByFieID(String key, String fieId) {
|
||||||
|
// return redisTemplate.opsForHash().get(key, fieId);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * <p>说明:根据key获取所有的键值对
|
||||||
|
// * <p>
|
||||||
|
// *
|
||||||
|
// * @param key redis中的key
|
||||||
|
// * @name: getMapByKey
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Map<Object, Object> MapGetMapByKey(String key) {
|
||||||
|
// return redisTemplate.opsForHash().entries(key);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * <p>说明:向key中添加一对新的键值对
|
||||||
|
// * <p>
|
||||||
|
// *
|
||||||
|
// * @param hashKey 键值对的key
|
||||||
|
// * @param value 键值对的value
|
||||||
|
// * @name: setNewMapValue
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public void MapSetNewMapValue(String key, String hashKey, Object value) {
|
||||||
|
// redisTemplate.opsForHash().put(key, hashKey, value);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * <p>说明:根据key和field删除数据
|
||||||
|
// * <p>
|
||||||
|
// *
|
||||||
|
// * @param fields 要删除的fields
|
||||||
|
// * @return Long 影响的条数
|
||||||
|
// * @name: hashDelete
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Long MapHashDelete(String key, Object... fields) {
|
||||||
|
// return redisTemplate.opsForHash().delete(key, fields);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * <p>说明:查看key下存了多少条键值对
|
||||||
|
// * <p>
|
||||||
|
// *
|
||||||
|
// * @param key redis的key
|
||||||
|
// * @name: getMapValueSize
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Long MapGetMapValueSize(String key) {
|
||||||
|
// return redisTemplate.opsForHash().size(key);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 设置值到List中的头部
|
||||||
|
// *
|
||||||
|
// * @param key
|
||||||
|
// * @param value
|
||||||
|
// * @return
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Boolean listAddInHead(String key, Object value) {
|
||||||
|
// try {
|
||||||
|
// redisTemplate.opsForList().leftPush(key, value);
|
||||||
|
// return true;
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// log.error(e.getMessage());
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 批量设置值到List中的头部
|
||||||
|
// *
|
||||||
|
// * @param key List名字
|
||||||
|
// * @param values
|
||||||
|
// * @return
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Boolean listAddAllInHead(String key, Collection<?> values) {
|
||||||
|
// try {
|
||||||
|
// redisTemplate.opsForList().leftPushAll(key, values);
|
||||||
|
// return true;
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// log.error(e.getMessage());
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 如果存在List->key, 则设置值到List中的头部
|
||||||
|
// *
|
||||||
|
// * @param key List名字
|
||||||
|
// * @param value
|
||||||
|
// * @return
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Boolean listAddIfPresent(String key, Object value) {
|
||||||
|
// try {
|
||||||
|
// redisTemplate.opsForList().leftPushIfPresent(key, value);
|
||||||
|
// return true;
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// log.error(e.getMessage());
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 设置值到List中的尾部
|
||||||
|
// *
|
||||||
|
// * @param key List名字
|
||||||
|
// * @param value 值
|
||||||
|
// * @return
|
||||||
|
// */
|
||||||
|
// public Boolean listAddInEnd(String key, Object value) {
|
||||||
|
// try {
|
||||||
|
// redisTemplate.opsForList().rightPush(key, value);
|
||||||
|
// return true;
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// log.error(e.getMessage());
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 批量设置值到List中的尾部
|
||||||
|
// *
|
||||||
|
// * @param key List名字
|
||||||
|
// * @param values 要设置的集合
|
||||||
|
// * @return
|
||||||
|
// */
|
||||||
|
// public Boolean listAddAllInEnd(String key, Collection<?> values) {
|
||||||
|
// try {
|
||||||
|
// redisTemplate.opsForList().rightPushAll(key, values);
|
||||||
|
// return true;
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// log.error(e.getMessage());
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 通过索引去设置List->key中的值
|
||||||
|
// *
|
||||||
|
// * @param key redis的key
|
||||||
|
// * @param index 索引
|
||||||
|
// * @param value 值
|
||||||
|
// * @return
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Boolean listAddByIndex(String key, long index, Object value) {
|
||||||
|
// try {
|
||||||
|
// redisTemplate.opsForList().set(key, index, value);
|
||||||
|
// return true;
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// log.error(e.getMessage());
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 根据索引获取list中的值
|
||||||
|
// *
|
||||||
|
// * @param key list名字
|
||||||
|
// * @param index
|
||||||
|
// * @return
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Object listGetByIndex(String key, long index) {
|
||||||
|
// return redisTemplate.opsForList().index(key, index);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 根据索引范围获取list中的值
|
||||||
|
// *
|
||||||
|
// * @param key list名字
|
||||||
|
// * @param start
|
||||||
|
// * @param end
|
||||||
|
// * @return
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public List<Object> listGetByRange(String key, long start, long end) {
|
||||||
|
// return redisTemplate.opsForList().range(key, start, end);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 移除并获取列表中第一个元素(如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止)
|
||||||
|
// *
|
||||||
|
// * @param key list名字
|
||||||
|
// * @return
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Object listLeftPop(String key) {
|
||||||
|
// return redisTemplate.opsForList().leftPop(key);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 移除并获取列表中最后一个元素(如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止)
|
||||||
|
// *
|
||||||
|
// * @param key list名字
|
||||||
|
// * @return
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Object listRightPop(String key) {
|
||||||
|
// return redisTemplate.opsForList().rightPop(key);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * <p>说明:获取列表元素的大小
|
||||||
|
// * <p>
|
||||||
|
// *
|
||||||
|
// * @param
|
||||||
|
// * @name: listGetSize
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Long listGetSize(String key) {
|
||||||
|
// return redisTemplate.opsForList().size(key);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 删除集合中值等于value的元素(
|
||||||
|
// * index=0, 删除所有值等于value的元素;
|
||||||
|
// * index>0, 从头部开始删除第一个值等于value的元素;
|
||||||
|
// * index<0, 从尾部开始删除第一个值等于value的元素)
|
||||||
|
// *
|
||||||
|
// * @param key
|
||||||
|
// * @param index
|
||||||
|
// * @param value
|
||||||
|
// * @return
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public Long listRemove(String key, long index, Object value) {
|
||||||
|
// return redisTemplate.opsForList().remove(key, index, value);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * <p>说明:清除所有缓存
|
||||||
|
// * <p><b>该方法会清理掉redis中所有的缓存,谨慎使用</b>
|
||||||
|
// * <p>
|
||||||
|
// *
|
||||||
|
// * @name: empty
|
||||||
|
// * @author :Wind
|
||||||
|
// */
|
||||||
|
// public void empty() {
|
||||||
|
// redisTemplate.getConnectionFactory().getConnection().flushAll();
|
||||||
|
// }
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
#???????
|
||||||
|
solon.plugin=org.dromara.sms4j.solon.XPluginImpl
|
||||||
|
#?????????????????0
|
||||||
|
solon.plugin.priority=1
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
package org.dromara.sms4j.demo;
|
||||||
|
|
||||||
|
import org.noear.solon.Solon;
|
||||||
|
import org.noear.solon.annotation.SolonMain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author noear 2023/5/16 created
|
||||||
|
*/
|
||||||
|
@SolonMain
|
||||||
|
public class App {
|
||||||
|
public static void main(String[] args){
|
||||||
|
Solon.start(App.class, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
package org.dromara.sms4j.demo;
|
||||||
|
|
||||||
|
import org.noear.solon.Utils;
|
||||||
|
import org.noear.solon.annotation.Bean;
|
||||||
|
import org.noear.solon.annotation.Configuration;
|
||||||
|
import org.noear.solon.annotation.Inject;
|
||||||
|
import org.redisson.Redisson;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
|
import org.redisson.config.ClusterServersConfig;
|
||||||
|
import org.redisson.config.SingleServerConfig;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author noear 2023/5/16 created
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class Config {
|
||||||
|
@Bean
|
||||||
|
public RedissonClient redisInit(@Inject("${sms4j.redis}") Properties props) {
|
||||||
|
return build(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RedissonClient build(Properties prop) {
|
||||||
|
String server_str = prop.getProperty("server");
|
||||||
|
String db_str = prop.getProperty("db");
|
||||||
|
String user_str = prop.getProperty("user");
|
||||||
|
String password_str = prop.getProperty("password");
|
||||||
|
|
||||||
|
|
||||||
|
int db = 0;
|
||||||
|
|
||||||
|
if (Utils.isNotEmpty(db_str)) {
|
||||||
|
db = Integer.parseInt(db_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 开始实例化 redissonClient
|
||||||
|
//
|
||||||
|
org.redisson.config.Config config = new org.redisson.config.Config();
|
||||||
|
|
||||||
|
if (server_str.contains(",")) {
|
||||||
|
//集群
|
||||||
|
ClusterServersConfig serverConfig = config.useClusterServers();
|
||||||
|
|
||||||
|
//注入一般配置
|
||||||
|
Utils.injectProperties(serverConfig, prop);
|
||||||
|
|
||||||
|
//设置关键配置
|
||||||
|
String[] address = resolveServers(server_str.split(","));
|
||||||
|
serverConfig.addNodeAddress(address)
|
||||||
|
.setUsername(user_str)
|
||||||
|
.setPassword(password_str);
|
||||||
|
} else {
|
||||||
|
//单例
|
||||||
|
SingleServerConfig serverConfig = config.useSingleServer();
|
||||||
|
|
||||||
|
//注入一般配置
|
||||||
|
Utils.injectProperties(serverConfig, prop);
|
||||||
|
|
||||||
|
//设置关键配置
|
||||||
|
String[] address = resolveServers(server_str);
|
||||||
|
serverConfig.setAddress(address[0])
|
||||||
|
.setUsername(user_str)
|
||||||
|
.setPassword(password_str)
|
||||||
|
.setDatabase(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Redisson.create(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] resolveServers(String... servers) {
|
||||||
|
String[] uris = new String[servers.length];
|
||||||
|
|
||||||
|
for (int i = 0; i < servers.length; i++) {
|
||||||
|
String sev = servers[i];
|
||||||
|
|
||||||
|
if (sev.contains("://")) {
|
||||||
|
uris[i] = sev;
|
||||||
|
} else {
|
||||||
|
uris[i] = "redis://" + sev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return uris;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,33 +1,30 @@
|
|||||||
package org.dromara.sms4j.test;
|
package org.dromara.sms4j.test;
|
||||||
|
|
||||||
import org.dromara.sms4j.api.entity.SmsResponse;
|
import org.dromara.sms4j.api.entity.SmsResponse;
|
||||||
import org.dromara.sms4j.comm.enumerate.SupplierType;
|
|
||||||
import org.dromara.sms4j.core.config.SupplierFactory;
|
import org.dromara.sms4j.core.config.SupplierFactory;
|
||||||
import org.dromara.sms4j.core.factory.SmsFactory;
|
import org.dromara.sms4j.core.factory.SmsFactory;
|
||||||
|
import org.dromara.sms4j.provider.enumerate.SupplierType;
|
||||||
import org.dromara.sms4j.unisms.config.UniConfig;
|
import org.dromara.sms4j.unisms.config.UniConfig;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.noear.solon.test.SolonJUnit4ClassRunner;
|
||||||
|
import org.noear.solon.test.SolonTest;
|
||||||
|
|
||||||
@SpringBootTest
|
@RunWith(SolonJUnit4ClassRunner.class)
|
||||||
|
@SolonTest
|
||||||
public class Sms4jTest {
|
public class Sms4jTest {
|
||||||
public static final String USER_AGENT = "uni-java-sdk" + "/0.0.4" ;
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void uniSmsTest() {
|
public void uniSmsTest() {
|
||||||
UniConfig build = UniConfig.builder()
|
UniConfig build = UniConfig.builder()
|
||||||
.signature("洙旭阁")
|
.signature("***")
|
||||||
.accessKeyId("7Cr1ZaQVJQ11Ap4HBQMo7xmFg")
|
.accessKeyId("7Cr1***VJQ11Ap4***Mo7xmFg")
|
||||||
.templateId("2001")
|
.templateId("2001")
|
||||||
.templateName("message")
|
.templateName("message")
|
||||||
.isSimple(true)
|
.isSimple(true)
|
||||||
.build();
|
.build();
|
||||||
SupplierFactory.setUniConfig(build);
|
SupplierFactory.setUniConfig(build);
|
||||||
|
SmsResponse smsResponse = SmsFactory.createSmsBlend(SupplierType.UNI_SMS).sendMessage("175***65952", "123123");
|
||||||
SmsResponse smsResponse = SmsFactory.createSmsBlend(SupplierType.UNI_SMS).sendMessage("17531165952", "123123");
|
|
||||||
System.out.println(smsResponse);
|
System.out.println(smsResponse);
|
||||||
// UniResponse sms = UniSMS.buildMessage().setTo("17531165952").setSignature("洙旭阁").setTemplateId("2001").setTemplateData(map).send();
|
|
||||||
// System.out.println(sms);
|
|
||||||
// Uni.getClient().request("sms.message.send",mes)
|
|
||||||
// UniClient.request()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0
sms4j-solon-plugin/src/test/resources/app.yml
Normal file
0
sms4j-solon-plugin/src/test/resources/app.yml
Normal file
39
sms4j-spring-boot-example/pom.xml
Normal file
39
sms4j-spring-boot-example/pom.xml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?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-spring-boot-example</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.install.skip>true</maven.install.skip>
|
||||||
|
<maven.deploy.skip>true</maven.deploy.skip>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--单元测试-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara.sms4j</groupId>
|
||||||
|
<artifactId>sms4j-spring-boot-starter</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package org.dromara.sms4j.example;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主类
|
||||||
|
*
|
||||||
|
* @author handy
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
public class Sms4jApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(Sms4jApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
29
sms4j-spring-boot-example/src/main/resources/application.yml
Normal file
29
sms4j-spring-boot-example/src/main/resources/application.yml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
sms:
|
||||||
|
alibaba:
|
||||||
|
#阿里云的accessKey
|
||||||
|
accessKeyId: 您的accessKey
|
||||||
|
#阿里云的accessKeySecret
|
||||||
|
accessKeySecret: 您的accessKeySecret
|
||||||
|
#短信签名
|
||||||
|
signature: 测试签名
|
||||||
|
#模板ID 用于发送固定模板短信使用
|
||||||
|
templateId: SMS_215125134
|
||||||
|
#模板变量 上述模板的变量
|
||||||
|
templateName: code
|
||||||
|
#请求地址 默认为dysmsapi.aliyuncs.com 如无特殊改变可以不用设置
|
||||||
|
requestUrl: dysmsapi.aliyuncs.com
|
||||||
|
huawei:
|
||||||
|
#华为短信appKey
|
||||||
|
appKey: 5N6fvXXXX920HaWhVXXXXXX7fYa
|
||||||
|
#华为短信appSecret
|
||||||
|
app-secret: Wujt7EYzZTBXXXXXXEhSP6XXXX
|
||||||
|
#短信签名
|
||||||
|
signature: 华为短信测试
|
||||||
|
#通道号
|
||||||
|
sender: 8823040504797
|
||||||
|
#模板ID 如果使用自定义模板发送方法可不设定
|
||||||
|
template-id: acXXXXXXXXc274b2a8263479b954c1ab5
|
||||||
|
#华为回调地址,如不需要可不设置或为空
|
||||||
|
statusCallBack:
|
||||||
|
#华为分配的app请求地址
|
||||||
|
url: https://XXXXX.cn-north-4.XXXXXXXX.com:443
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package org.dromara.sms4j.example;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.sms4j.api.entity.SmsResponse;
|
||||||
|
import org.dromara.sms4j.comm.utils.SmsUtil;
|
||||||
|
import org.dromara.sms4j.core.factory.SmsFactory;
|
||||||
|
import org.dromara.sms4j.provider.enumerate.SupplierType;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@SpringBootTest
|
||||||
|
class Sms4jTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 填测试手机号
|
||||||
|
*/
|
||||||
|
private static final String PHONE = "";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void alibabaSmsTest() {
|
||||||
|
if (StrUtil.isBlank(PHONE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SmsResponse smsResponse = SmsFactory.createSmsBlend(SupplierType.ALIBABA).sendMessage(PHONE, SmsUtil.getRandomInt(6));
|
||||||
|
log.info(JSONUtil.toJsonStr(smsResponse));
|
||||||
|
Assert.isTrue("OK".equals(smsResponse.getCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void huaweiSmsTest() {
|
||||||
|
if (StrUtil.isBlank(PHONE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SmsResponse smsResponse = SmsFactory.createSmsBlend(SupplierType.HUAWEI).sendMessage(PHONE, SmsUtil.getRandomInt(6));
|
||||||
|
log.info(JSONUtil.toJsonStr(smsResponse));
|
||||||
|
Assert.isTrue("000000".equals(smsResponse.getCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -16,14 +16,6 @@
|
|||||||
<description>sms4j-spring-boot-starter</description>
|
<description>sms4j-spring-boot-starter</description>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-dependencies</artifactId>
|
|
||||||
<version>${spring.boot.version}</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara.sms4j</groupId>
|
<groupId>org.dromara.sms4j</groupId>
|
||||||
<artifactId>sms4j-autoimmit</artifactId>
|
<artifactId>sms4j-autoimmit</artifactId>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user