mirror of
https://gitee.com/dromara/sms4j.git
synced 2025-12-06 17:08:40 +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>
|
||||
<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/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>
|
||||
<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-autoimmit</module>
|
||||
<module>sms4j-spring-boot-starter</module>
|
||||
<module>sms4j-solon-plugin</module>
|
||||
<module>sms4j-spring-boot-example</module>
|
||||
</modules>
|
||||
|
||||
<!-- 开源协议 Apache 2.0 -->
|
||||
@ -47,17 +49,16 @@
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<spring.boot.version>2.7.11</spring.boot.version>
|
||||
<revision>2.0.2</revision>
|
||||
<aliyun.version>2.0.23</aliyun.version>
|
||||
<tencent.version>3.1.622</tencent.version>
|
||||
<unisms.version>0.0.4</unisms.version>
|
||||
<revision>2.1.0-SNAPSHOT</revision>
|
||||
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<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>
|
||||
<json.version>2.0.15</json.version>
|
||||
<okhttp.version>3.14.9</okhttp.version>
|
||||
<forest.version>1.5.30</forest.version>
|
||||
<hutool.version>5.8.16</hutool.version>
|
||||
<okhttp.version>3.14.9</okhttp.version>
|
||||
<hutool.version>5.8.18</hutool.version>
|
||||
<xmlblend.version>2.3.0</xmlblend.version>
|
||||
<activation.version>1.1.1</activation.version>
|
||||
</properties>
|
||||
@ -119,13 +120,6 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里JSON解析器 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${json.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--Forest依赖 声明式HTTP客户端框架-->
|
||||
<dependency>
|
||||
<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.List;
|
||||
|
||||
/**
|
||||
* SmsBlend
|
||||
* <p> 通用接口,定义国内短信方法
|
||||
* @author :Wind
|
||||
* 2023/5/16 16:03
|
||||
**/
|
||||
public interface SmsBlend {
|
||||
|
||||
/**
|
||||
* <p>说明:发送固定消息模板短信
|
||||
* <p>此方法将使用配置文件中预设的短信模板进行短信发送
|
||||
* <p>该方法指定的模板变量只能存在一个(配置文件中)
|
||||
* <p>如使用的是腾讯的短信,参数字符串中可以同时存在多个参数,使用 & 分隔例如:您的验证码为{1}在{2}分钟内有效,可以传为 message="xxxx"+"&"+"5"
|
||||
* sendMessage
|
||||
*
|
||||
* @param phone 接收短信的手机号
|
||||
* message 消息内容
|
||||
* @author :Wind
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* <p>说明:群发固定模板短信
|
||||
* massTexting
|
||||
*
|
||||
* @author :Wind
|
||||
*/
|
||||
|
||||
SmsResponse massTexting(List<String> phones, String message);
|
||||
|
||||
/**
|
||||
* <p>说明:使用自定义模板群发短信
|
||||
* massTexting
|
||||
*
|
||||
* @author :Wind
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* <p>说明:异步发送短信,不关注发送结果
|
||||
* sendMessageAsync
|
||||
*
|
||||
* @param phone 要发送的号码
|
||||
* @param message 发送内容
|
||||
* @author :Wind
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* <p>说明:异步短信发送,使用自定义模板发送短信,不关注发送结果
|
||||
* sendMessageAsync
|
||||
*
|
||||
* @param templateId 模板id
|
||||
* @param messages key为模板变量名称 value为模板变量值
|
||||
* @author :Wind
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* <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);
|
||||
|
||||
/**
|
||||
* <p>说明:群发延迟短信
|
||||
* delayMassTexting
|
||||
*
|
||||
* @param phones 要群体发送的手机号码
|
||||
* @author :Wind
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
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.RedisUtils;
|
||||
import org.dromara.sms4j.autoimmit.utils.SpringUtil;
|
||||
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.enumerate.ConfigType;
|
||||
import org.dromara.sms4j.comm.enumerate.SupplierType;
|
||||
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sms4j.core.SupplierSqlConfig;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
@ -71,21 +71,21 @@ public class SmsAutowiredConfig {
|
||||
return new SupplierSqlConfig();
|
||||
}
|
||||
|
||||
|
||||
void init(){
|
||||
/* 如果配置中启用了redis,则注入redis工具*/
|
||||
if (BeanFactory.getSmsConfig().getRedisCache()){
|
||||
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组件*/
|
||||
if (BeanFactory.getSmsConfig().getRestricted()){
|
||||
springUtil.createBean(AopAdvice.class);
|
||||
log.debug("SMS restriction is enabled");
|
||||
}
|
||||
// if (BeanFactory.getSmsConfig().getRestricted()){
|
||||
// springUtil.createBean(AopAdvice.class);
|
||||
// log.debug("SMS restriction is enabled");
|
||||
// }
|
||||
//打印banner
|
||||
if (BeanFactory.getSmsConfig().getIsPrint()){
|
||||
SmsBanner.PrintBanner("V 2.0.1");
|
||||
SmsBanner.PrintBanner(Constant.VERSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
package org.dromara.sms4j.autoimmit.config;
|
||||
|
||||
import org.dromara.sms4j.emay.config.EmayConfig;
|
||||
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;
|
||||
@ -72,4 +73,13 @@ public class SupplierConfig {
|
||||
protected EmayConfig emayConfig(){
|
||||
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.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;
|
||||
|
||||
|
||||
|
||||
@ -15,11 +15,6 @@
|
||||
<description>sms4j-comm</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.dtflys.forest</groupId>
|
||||
<artifactId>forest-core</artifactId>
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package org.dromara.sms4j.comm.config;
|
||||
|
||||
|
||||
import org.dromara.sms4j.comm.enumerate.ConfigType;
|
||||
import lombok.Data;
|
||||
import org.dromara.sms4j.comm.enumerate.ConfigType;
|
||||
|
||||
@Data
|
||||
public class SmsConfig {
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
package org.dromara.sms4j.comm.constant;
|
||||
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Constant
|
||||
* <p> 短信应用常量
|
||||
@ -12,6 +9,8 @@ import java.nio.charset.StandardCharsets;
|
||||
* 2023/3/31 19:33
|
||||
**/
|
||||
public abstract class Constant {
|
||||
/** 项目版本号*/
|
||||
public static final String VERSION = "V 2.1.0";
|
||||
|
||||
/**
|
||||
* 用于格式化鉴权头域,给"Authorization"参数赋值
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package org.dromara.sms4j.comm.delayedTime;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* <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.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.Map;
|
||||
|
||||
|
||||
@ -1,45 +1,37 @@
|
||||
package org.dromara.sms4j.comm.utils;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.alibaba.fastjson.JSONException;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.dromara.sms4j.comm.exception.SmsSqlException;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @author wind
|
||||
*/
|
||||
public class SmsUtil {
|
||||
private SmsUtil() {
|
||||
} //私有构造防止实例化
|
||||
|
||||
|
||||
/**
|
||||
* <p>说明:生成一个指定长度的随机字符串,包含大小写英文字母和数字但不包含符号
|
||||
*
|
||||
* @param len 要生成的字符串的长度
|
||||
* getRandomString
|
||||
* getRandomString
|
||||
* @author :Wind
|
||||
*/
|
||||
public static String getRandomString(int len) {
|
||||
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
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();
|
||||
return RandomUtil.randomString(RandomUtil.BASE_CHAR_NUMBER + RandomUtil.BASE_CHAR.toUpperCase(), len);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>说明:获取一个长度为6的随机字符串
|
||||
*getRandomString
|
||||
* getRandomString
|
||||
*
|
||||
* @author :Wind
|
||||
*/
|
||||
public static String getRandomString() {
|
||||
@ -48,37 +40,29 @@ public class SmsUtil {
|
||||
|
||||
/**
|
||||
* <p>说明:生成一个指定长度的只有数字组成的随机字符串
|
||||
*
|
||||
* @param len 要生成的长度
|
||||
* getRandomInt
|
||||
* getRandomInt
|
||||
* @author :Wind
|
||||
*/
|
||||
public static String getRandomInt(int len) {
|
||||
String str = "0123456789";
|
||||
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();
|
||||
return RandomUtil.randomString(RandomUtil.BASE_NUMBER, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定元素是否为null或者空字符串
|
||||
*
|
||||
* @param str 指定元素
|
||||
* @return 是否为null或者空字符串
|
||||
* @author :Wind
|
||||
*/
|
||||
public static boolean isEmpty(Object str) {
|
||||
return str == null || "".equals(str);
|
||||
return ObjectUtil.isEmpty(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定元素是否不为 (null或者空字符串)
|
||||
*
|
||||
* @param str 指定元素
|
||||
* @return 是否为null或者空字符串
|
||||
* @author :Wind
|
||||
@ -87,43 +71,72 @@ public class SmsUtil {
|
||||
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字符串转化为指定的对象
|
||||
*
|
||||
* @author :Wind
|
||||
*/
|
||||
*/
|
||||
public static <T> T jsonForObject(String json, Class<T> t) {
|
||||
try {
|
||||
return json == null||"".equals(json)?null: JSONObject.toJavaObject(JSONObject.parseObject(json), t);
|
||||
} catch (JSONException e) {
|
||||
throw new SmsSqlException("json sequence exception" + e.getMessage());
|
||||
}
|
||||
return JSONUtil.toBean(json, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* copyBean
|
||||
* copyBean
|
||||
* <p>拷贝bean,只有源对象不为null才会拷贝
|
||||
*
|
||||
* @param t 源对象
|
||||
* @param m 目标对象
|
||||
* @author :Wind
|
||||
*/
|
||||
public static <T,M>void copyBean(T t,M m){
|
||||
if (t != null){
|
||||
BeanUtil.copyProperties(t, m);
|
||||
*/
|
||||
public static <T, M> void copyBean(T t, M 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;
|
||||
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -66,8 +66,7 @@ public class TimeExpiredPoolCache {
|
||||
private static boolean persistenceInit() {
|
||||
String path = FileTool.getPath() + FILE_TYPE;
|
||||
try {
|
||||
|
||||
DataWrapper d = JSONObject.parseObject(FileTool.readFile(path), DataWrapper.class);
|
||||
DataWrapper d = JSONUtil.toBean(FileTool.readFile(path), DataWrapper.class);
|
||||
if (dataPool != null) {
|
||||
return true;
|
||||
}
|
||||
@ -95,7 +94,7 @@ public class TimeExpiredPoolCache {
|
||||
private static void persistence() {
|
||||
String path = FileTool.getPath() + FILE_TYPE;
|
||||
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.cloopen.config.CloopenConfig;
|
||||
import org.dromara.sms4j.comm.enumerate.SupplierType;
|
||||
import org.dromara.sms4j.comm.utils.JDBCTool;
|
||||
import org.dromara.sms4j.comm.utils.SmsUtil;
|
||||
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.provider.enumerate.SupplierType;
|
||||
import org.dromara.sms4j.tencent.config.TencentConfig;
|
||||
import org.dromara.sms4j.unisms.config.UniConfig;
|
||||
import org.dromara.sms4j.yunpian.config.YunpianConfig;
|
||||
@ -48,6 +49,7 @@ public class SupplierSqlConfig {
|
||||
yunPian();
|
||||
cloopen();
|
||||
emay();
|
||||
ctyun();
|
||||
}
|
||||
|
||||
public SupplierSqlConfig() {
|
||||
@ -136,4 +138,14 @@ public class SupplierSqlConfig {
|
||||
EmayConfig emayConfig = SmsUtil.jsonForObject(select.get(SupplierType.EMAY.getName()), EmayConfig.class);
|
||||
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;
|
||||
|
||||
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.AlibabaFactory;
|
||||
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||
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.HuaweiFactory;
|
||||
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.TencentFactory;
|
||||
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;
|
||||
|
||||
/**
|
||||
@ -21,103 +33,104 @@ public class SupplierFactory {
|
||||
private SupplierFactory() {
|
||||
}
|
||||
|
||||
/** 阿里云差异化配置*/
|
||||
private static AlibabaConfig alibabaConfig;
|
||||
|
||||
/** 华为云差异化配置*/
|
||||
private static HuaweiConfig huaweiConfig;
|
||||
|
||||
/** 合一短信差异化配置*/
|
||||
private static UniConfig uniConfig;
|
||||
|
||||
/** 腾讯云短信差异化配置*/
|
||||
private static TencentConfig tencentConfig;
|
||||
|
||||
/** 云片短信差异配置*/
|
||||
private static YunpianConfig yunpianConfig;
|
||||
|
||||
/** 京东云短信差异配置 */
|
||||
private static JdCloudConfig jdCloudConfig;
|
||||
|
||||
/** 容联云短信差异配置 */
|
||||
private static CloopenConfig cloopenConfig;
|
||||
/**
|
||||
* 阿里云配置获取
|
||||
*/
|
||||
public static AlibabaConfig getAlibabaConfig() {
|
||||
return AlibabaFactory.instance().getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* 亿美软通短信差异配置
|
||||
* 华为云配置获取
|
||||
*/
|
||||
private static EmayConfig emayConfig;
|
||||
|
||||
/** 阿里云配置获取*/
|
||||
public static AlibabaConfig getAlibabaConfig() {
|
||||
if (alibabaConfig == null){
|
||||
alibabaConfig = AlibabaConfig.builder().build();
|
||||
}
|
||||
return alibabaConfig;
|
||||
}
|
||||
|
||||
/** 华为云配置获取*/
|
||||
public static HuaweiConfig getHuaweiConfig() {
|
||||
if (huaweiConfig == null){
|
||||
huaweiConfig = HuaweiConfig.builder().build();
|
||||
}
|
||||
return huaweiConfig;
|
||||
return HuaweiFactory.instance().getConfig();
|
||||
}
|
||||
|
||||
/** 合一短信配置获取*/
|
||||
/**
|
||||
* 合一短信配置获取
|
||||
*/
|
||||
public static UniConfig getUniConfig() {
|
||||
if (uniConfig == null){
|
||||
uniConfig = UniConfig.builder().build();
|
||||
}
|
||||
return uniConfig;
|
||||
return UniFactory.instance().getConfig();
|
||||
}
|
||||
|
||||
/** 腾讯短信配置获取*/
|
||||
/**
|
||||
* 腾讯短信配置获取
|
||||
*/
|
||||
public static TencentConfig getTencentConfig() {
|
||||
if (tencentConfig == null){
|
||||
tencentConfig = TencentConfig.builder().build();
|
||||
}
|
||||
return tencentConfig;
|
||||
return TencentFactory.instance().getConfig();
|
||||
}
|
||||
|
||||
/** 云片短信配置获取*/
|
||||
/**
|
||||
* 云片短信配置获取
|
||||
*/
|
||||
public static YunpianConfig getYunpianConfig() {
|
||||
if (yunpianConfig == null){
|
||||
yunpianConfig = YunpianConfig.builder().build();
|
||||
}
|
||||
return yunpianConfig;
|
||||
return YunPianFactory.instance().getConfig();
|
||||
}
|
||||
|
||||
/** 京东云短信配置获取 */
|
||||
/**
|
||||
* 京东云短信配置获取
|
||||
*/
|
||||
public static JdCloudConfig getJdCloudConfig() {
|
||||
if (jdCloudConfig == null){
|
||||
jdCloudConfig = JdCloudConfig.builder().build();
|
||||
}
|
||||
return jdCloudConfig;
|
||||
return JdCloudFactory.instance().getConfig();
|
||||
}
|
||||
|
||||
/** 容联云短信配置获取 */
|
||||
/**
|
||||
* 容联云短信配置获取
|
||||
*/
|
||||
public static CloopenConfig getCloopenConfig() {
|
||||
if (cloopenConfig == null){
|
||||
cloopenConfig = CloopenConfig.builder().build();
|
||||
}
|
||||
return cloopenConfig;
|
||||
return CloopenFactory.instance().getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* 亿美软通配置获取
|
||||
*/
|
||||
public static EmayConfig getEmayConfig() {
|
||||
if (emayConfig == null) {
|
||||
emayConfig = EmayConfig.builder().build();
|
||||
return EmayFactory.instance().getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* 天翼云配置获取
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public static void setAlibabaConfig(AlibabaConfig alibabaConfig) {
|
||||
SupplierFactory.alibabaConfig = alibabaConfig;
|
||||
AlibabaFactory.instance().setConfig(alibabaConfig);
|
||||
SmsFactory.refresh(SupplierType.ALIBABA);
|
||||
}
|
||||
|
||||
@ -125,7 +138,7 @@ public class SupplierFactory {
|
||||
* 设置 huaweiConfig
|
||||
*/
|
||||
public static void setHuaweiConfig(HuaweiConfig huaweiConfig) {
|
||||
SupplierFactory.huaweiConfig = huaweiConfig;
|
||||
HuaweiFactory.instance().setConfig(huaweiConfig);
|
||||
SmsFactory.refresh(SupplierType.HUAWEI);
|
||||
}
|
||||
|
||||
@ -133,7 +146,7 @@ public class SupplierFactory {
|
||||
* 设置 uniConfig
|
||||
*/
|
||||
public static void setUniConfig(UniConfig uniConfig) {
|
||||
SupplierFactory.uniConfig = uniConfig;
|
||||
UniFactory.instance().setConfig(uniConfig);
|
||||
SmsFactory.refresh(SupplierType.UNI_SMS);
|
||||
}
|
||||
|
||||
@ -141,7 +154,7 @@ public class SupplierFactory {
|
||||
* 设置 tencentConfig
|
||||
*/
|
||||
public static void setTencentConfig(TencentConfig tencentConfig) {
|
||||
SupplierFactory.tencentConfig = tencentConfig;
|
||||
TencentFactory.instance().setConfig(tencentConfig);
|
||||
SmsFactory.refresh(SupplierType.TENCENT);
|
||||
}
|
||||
|
||||
@ -149,7 +162,7 @@ public class SupplierFactory {
|
||||
* 设置 yunpianConfig
|
||||
*/
|
||||
public static void setYunpianConfig(YunpianConfig yunpianConfig) {
|
||||
SupplierFactory.yunpianConfig = yunpianConfig;
|
||||
YunPianFactory.instance().setConfig(yunpianConfig);
|
||||
SmsFactory.refresh(SupplierType.YUNPIAN);
|
||||
}
|
||||
|
||||
@ -157,7 +170,7 @@ public class SupplierFactory {
|
||||
* 设置 jdCloudConfig
|
||||
*/
|
||||
public static void setJdCloudConfig(JdCloudConfig jdCloudConfig) {
|
||||
SupplierFactory.jdCloudConfig = jdCloudConfig;
|
||||
JdCloudFactory.instance().setConfig(jdCloudConfig);
|
||||
SmsFactory.refresh(SupplierType.JD_CLOUD);
|
||||
}
|
||||
|
||||
@ -165,7 +178,7 @@ public class SupplierFactory {
|
||||
* 设置 cloopenConfig
|
||||
*/
|
||||
public static void setCloopenConfig(CloopenConfig cloopenConfig) {
|
||||
SupplierFactory.cloopenConfig = cloopenConfig;
|
||||
CloopenFactory.instance().setConfig(cloopenConfig);
|
||||
SmsFactory.refresh(SupplierType.CLOOPEN);
|
||||
}
|
||||
|
||||
@ -173,7 +186,15 @@ public class SupplierFactory {
|
||||
* 设置 emayConfig
|
||||
*/
|
||||
public static void setEmayConfig(EmayConfig emayConfig) {
|
||||
SupplierFactory.emayConfig = emayConfig;
|
||||
EmayFactory.instance().setConfig(emayConfig);
|
||||
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;
|
||||
|
||||
import org.dromara.sms4j.aliyun.config.AlibabaSmsConfig;
|
||||
import org.dromara.sms4j.api.SmsBlend;
|
||||
import org.dromara.sms4j.cloopen.config.CloopenSmsConfig;
|
||||
import org.dromara.sms4j.comm.enumerate.SupplierType;
|
||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||
import org.dromara.sms4j.api.smsProxy.SmsInvocationHandler;
|
||||
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||
import org.dromara.sms4j.core.SupplierSqlConfig;
|
||||
import org.dromara.sms4j.core.config.SupplierFactory;
|
||||
import org.dromara.sms4j.emay.config.EmaySmsConfig;
|
||||
import org.dromara.sms4j.huawei.config.HuaweiSmsConfig;
|
||||
import org.dromara.sms4j.jdcloud.config.JdCloudSmsConfig;
|
||||
import org.dromara.sms4j.tencent.config.TencentSmsConfig;
|
||||
import org.dromara.sms4j.unisms.config.UniSmsConfig;
|
||||
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
||||
import org.dromara.sms4j.provider.enumerate.SupplierType;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* SmsFactory
|
||||
@ -23,6 +22,9 @@ import org.dromara.sms4j.unisms.config.UniSmsConfig;
|
||||
* 2023/4/8 15:55
|
||||
**/
|
||||
public abstract class SmsFactory {
|
||||
|
||||
private static Map<SupplierType, SmsBlend> beans = new HashMap<>();
|
||||
|
||||
private SmsFactory() {
|
||||
}
|
||||
|
||||
@ -34,23 +36,8 @@ public abstract class SmsFactory {
|
||||
* @author :Wind
|
||||
*/
|
||||
public static SmsBlend createSmsBlend(SupplierType supplierType) {
|
||||
switch (supplierType) {
|
||||
case ALIBABA:
|
||||
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");
|
||||
BaseProviderFactory providerFactory = supplierType.getProviderFactory();
|
||||
return providerFactory.createSms(providerFactory.getConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,13 +48,9 @@ public abstract class SmsFactory {
|
||||
* @author :Wind
|
||||
*/
|
||||
public static void refresh() {
|
||||
AlibabaSmsConfig.refresh(SupplierFactory.getAlibabaConfig());
|
||||
HuaweiSmsConfig.refresh(SupplierFactory.getHuaweiConfig());
|
||||
UniSmsConfig.refresh(SupplierFactory.getUniConfig());
|
||||
TencentSmsConfig.refresh(SupplierFactory.getTencentConfig());
|
||||
JdCloudSmsConfig.refresh(SupplierFactory.getJdCloudConfig());
|
||||
CloopenSmsConfig.refresh(SupplierFactory.getCloopenConfig());
|
||||
EmaySmsConfig.refresh(SupplierFactory.getEmayConfig());
|
||||
for(SupplierType type : SupplierType.values()) {
|
||||
refresh(type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,31 +61,8 @@ public abstract class SmsFactory {
|
||||
* @author :Wind
|
||||
*/
|
||||
public static void refresh(SupplierType supplierType) {
|
||||
switch (supplierType) {
|
||||
case ALIBABA:
|
||||
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");
|
||||
}
|
||||
BaseProviderFactory providerFactory = supplierType.getProviderFactory();
|
||||
providerFactory.refresh(providerFactory.getConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,4 +75,44 @@ public abstract class SmsFactory {
|
||||
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 java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* SmsLoad
|
||||
|
||||
@ -1 +0,0 @@
|
||||
|
||||
@ -5,13 +5,14 @@ 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
|
||||
@SuperBuilder
|
||||
@ToString(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;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.dtflys.forest.config.ForestConfiguration;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sms4j.aliyun.config.AlibabaConfig;
|
||||
import org.dromara.sms4j.aliyun.utils.AliyunUtils;
|
||||
import org.dromara.sms4j.api.SmsBlend;
|
||||
import org.dromara.sms4j.api.callback.CallBack;
|
||||
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.factory.BeanFactory;
|
||||
import org.dromara.sms4j.comm.utils.SmsUtil;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* <p>类名: AlibabaSmsImpl
|
||||
@ -29,27 +26,19 @@ import java.util.concurrent.Executor;
|
||||
**/
|
||||
|
||||
@Slf4j
|
||||
public class AlibabaSmsImpl implements SmsBlend {
|
||||
public class AlibabaSmsImpl extends AbstractSmsBlend {
|
||||
|
||||
private final AlibabaConfig alibabaSmsConfig;
|
||||
|
||||
private final Executor pool;
|
||||
|
||||
private final DelayedTime delayed;
|
||||
|
||||
private final ForestConfiguration http = BeanFactory.getForestConfiguration();
|
||||
|
||||
/**
|
||||
* AlibabaSmsImpl
|
||||
* <p>构造器,用于构造短信实现模块
|
||||
*
|
||||
* @author :Wind
|
||||
*/
|
||||
|
||||
public AlibabaSmsImpl(AlibabaConfig alibabaSmsConfig, Executor pool, DelayedTime delayedTime) {
|
||||
super(pool, delayedTime);
|
||||
this.alibabaSmsConfig = alibabaSmsConfig;
|
||||
this.pool = pool;
|
||||
this.delayed = delayedTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -63,7 +52,7 @@ public class AlibabaSmsImpl implements SmsBlend {
|
||||
@Override
|
||||
@Restricted
|
||||
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);
|
||||
}
|
||||
|
||||
@ -78,12 +67,12 @@ public class AlibabaSmsImpl implements SmsBlend {
|
||||
@Override
|
||||
@Restricted
|
||||
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
||||
String messageStr = JSON.toJSONString(messages);
|
||||
return getSmsResponse(arrayToString(phones), messageStr, templateId);
|
||||
String messageStr = JSONUtil.toJsonStr(messages);
|
||||
return getSmsResponse(SmsUtil.arrayToString(phones), messageStr, templateId);
|
||||
}
|
||||
|
||||
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
|
||||
SmsResponse smsResponse = new SmsResponse();
|
||||
AtomicReference<SmsResponse> reference = new AtomicReference<>();
|
||||
String requestUrl;
|
||||
String paramStr;
|
||||
try {
|
||||
@ -94,100 +83,32 @@ public class AlibabaSmsImpl implements SmsBlend {
|
||||
throw new SmsBlendException(e.getMessage());
|
||||
}
|
||||
log.debug("requestUrl {}", requestUrl);
|
||||
http.post(requestUrl)
|
||||
super.http.post(requestUrl)
|
||||
.addHeader("Content-Type", "application/x-www-form-urlencoded")
|
||||
.addBody(paramStr)
|
||||
.onSuccess(((data, req, res) -> {
|
||||
JSONObject jsonBody = res.get(JSONObject.class);
|
||||
log.info(jsonBody.toJSONString());
|
||||
reference.set(this.getResponse(res.get(JSONObject.class)));
|
||||
}))
|
||||
.onError((ex, req, res) -> {
|
||||
JSONObject jsonBody = res.get(JSONObject.class);
|
||||
log.info(jsonBody.toJSONString());
|
||||
reference.set(this.getResponse(res.get(JSONObject.class)));
|
||||
})
|
||||
.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;
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
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.comm.constant.Constant;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
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
|
||||
@ -21,18 +27,18 @@ public class AliyunUtils {
|
||||
*/
|
||||
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 {
|
||||
// 这里一定要设置GMT时区
|
||||
sdf.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
||||
SDF.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
||||
Map<String, String> paras = new HashMap<>();
|
||||
// 1. 公共请求参数
|
||||
paras.put("SignatureMethod", ALGORITHM);
|
||||
paras.put("SignatureNonce", UUID.randomUUID().toString());
|
||||
paras.put("AccessKeyId", alibabaConfig.getAccessKeyId());
|
||||
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("Action", alibabaConfig.getAction());
|
||||
paras.put("Version", alibabaConfig.getVersion());
|
||||
@ -80,10 +86,8 @@ public class AliyunUtils {
|
||||
* @param stringToSign 待生成签名的字符串
|
||||
*/
|
||||
private static String sign(String accessSecret, String stringToSign) throws Exception {
|
||||
Mac mac = Mac.getInstance("HmacSHA1");
|
||||
mac.init(new javax.crypto.spec.SecretKeySpec(accessSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA1"));
|
||||
byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
|
||||
return Base64.encode(signData);
|
||||
HMac hMac = new HMac(HmacAlgorithm.HmacSHA1, accessSecret.getBytes());
|
||||
return hMac.digestBase64(stringToSign,StandardCharsets.UTF_8, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -5,6 +5,7 @@ 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;
|
||||
|
||||
/**
|
||||
@ -17,7 +18,7 @@ import org.dromara.sms4j.comm.config.BaseConfig;
|
||||
@SuperBuilder
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class CloopenConfig extends BaseConfig {
|
||||
public class CloopenConfig extends BaseConfig implements SupplierConfig {
|
||||
|
||||
/**
|
||||
* 应用 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 com.dtflys.forest.Forest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sms4j.api.SmsBlend;
|
||||
import org.dromara.sms4j.api.callback.CallBack;
|
||||
import org.dromara.sms4j.api.AbstractSmsBlend;
|
||||
import org.dromara.sms4j.api.entity.SmsResponse;
|
||||
import org.dromara.sms4j.cloopen.api.CloopenRestApi;
|
||||
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.delayedTime.DelayedTime;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
@ -24,20 +25,15 @@ import java.util.concurrent.Executor;
|
||||
* @since 2023/4/10 22:10
|
||||
*/
|
||||
@Slf4j
|
||||
public class CloopenSmsImpl implements SmsBlend {
|
||||
public class CloopenSmsImpl extends AbstractSmsBlend {
|
||||
|
||||
private final CloopenRestApi restApi;
|
||||
|
||||
private final CloopenConfig config;
|
||||
|
||||
private final Executor pool;
|
||||
|
||||
private final DelayedTime delayed;
|
||||
|
||||
public CloopenSmsImpl(CloopenConfig config, Executor pool, DelayedTime delayed) {
|
||||
super(pool,delayed);
|
||||
this.config = config;
|
||||
this.pool = pool;
|
||||
this.delayed = delayed;
|
||||
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));
|
||||
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.Data;
|
||||
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||
|
||||
/**
|
||||
* @author Richard
|
||||
@ -9,7 +10,7 @@ import lombok.Data;
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class EmayConfig {
|
||||
public class EmayConfig implements SupplierConfig {
|
||||
/** appKey*/
|
||||
private String appId ;
|
||||
/** 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;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.dtflys.forest.config.ForestConfiguration;
|
||||
import org.dromara.sms4j.emay.config.EmayConfig;
|
||||
import org.dromara.sms4j.emay.util.EmayBuilder;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sms4j.api.SmsBlend;
|
||||
import org.dromara.sms4j.api.callback.CallBack;
|
||||
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.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.concurrent.CompletableFuture;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.dromara.sms4j.comm.utils.SmsUtil.listToString;
|
||||
|
||||
/**
|
||||
* @author Richard
|
||||
* @date 2023-04-11 12:00
|
||||
*/
|
||||
@Slf4j
|
||||
public class EmaySmsImpl implements SmsBlend {
|
||||
public class EmaySmsImpl extends AbstractSmsBlend {
|
||||
public EmaySmsImpl(EmayConfig config, Executor pool, DelayedTime delayed) {
|
||||
super(pool, delayed);
|
||||
this.config = config;
|
||||
this.pool = pool;
|
||||
this.delayed = delayed;
|
||||
}
|
||||
|
||||
private EmayConfig config;
|
||||
|
||||
private Executor pool;
|
||||
|
||||
private DelayedTime delayed;
|
||||
|
||||
private final ForestConfiguration http = BeanFactory.getForestConfiguration();
|
||||
|
||||
@Override
|
||||
@Restricted
|
||||
public SmsResponse sendMessage(String phone, String message) {
|
||||
@ -71,7 +64,7 @@ public class EmaySmsImpl implements SmsBlend {
|
||||
if (phones.size() > 500) {
|
||||
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于500");
|
||||
}
|
||||
return sendMessage(listToString(phones), message);
|
||||
return sendMessage(SmsUtil.listToString(phones), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -84,77 +77,7 @@ public class EmaySmsImpl implements SmsBlend {
|
||||
for (Map.Entry<String, String> entry : messages.entrySet()) {
|
||||
list.add(entry.getValue());
|
||||
}
|
||||
return sendMessage(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);
|
||||
return sendMessage(SmsUtil.listToString(phones), EmayBuilder.listToString(list));
|
||||
}
|
||||
|
||||
private SmsResponse getSendResponse(Map<String, Object> body, String requestUrl) {
|
||||
@ -177,14 +100,25 @@ public class EmaySmsImpl implements SmsBlend {
|
||||
|
||||
private static SmsResponse getSmsResponse(JSONObject execute) {
|
||||
SmsResponse smsResponse = new SmsResponse();
|
||||
String code = execute.getString("code");
|
||||
smsResponse.setCode(code);
|
||||
if ("success".equalsIgnoreCase(code)) {
|
||||
JSONObject data = execute.getJSONObject("data");
|
||||
String smsId = data.getString("smsId");
|
||||
smsResponse.setBizId(smsId);
|
||||
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);
|
||||
if ("success".equalsIgnoreCase(code)) {
|
||||
JSONArray data = execute.getJSONArray("data");
|
||||
JSONObject result = (JSONObject) data.get(0);
|
||||
String smsId = result.getStr("smsId");
|
||||
smsResponse.setBizId(smsId);
|
||||
}
|
||||
smsResponse.setData(execute);
|
||||
}
|
||||
smsResponse.setData(execute);
|
||||
return smsResponse;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,10 +2,11 @@ package org.dromara.sms4j.huawei.config;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class HuaweiConfig {
|
||||
public class HuaweiConfig implements SupplierConfig {
|
||||
|
||||
/** 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 java.util.Date;
|
||||
|
||||
/**
|
||||
* SmsId
|
||||
* <p> 短信ID列表
|
||||
|
||||
@ -1,48 +1,40 @@
|
||||
package org.dromara.sms4j.huawei.service;
|
||||
|
||||
import com.dtflys.forest.config.ForestConfiguration;
|
||||
|
||||
import org.dromara.sms4j.api.callback.CallBack;
|
||||
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.constant.Constant;
|
||||
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.entity.HuaweiResponse;
|
||||
import org.dromara.sms4j.huawei.utils.HuaweiBuilder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sms4j.api.SmsBlend;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import static org.dromara.sms4j.huawei.utils.HuaweiBuilder.listToString;
|
||||
|
||||
|
||||
@Slf4j
|
||||
public class HuaweiSmsImpl implements SmsBlend {
|
||||
public class HuaweiSmsImpl extends AbstractSmsBlend {
|
||||
public HuaweiSmsImpl(HuaweiConfig config, Executor pool, DelayedTime delayed) {
|
||||
super(pool,delayed);
|
||||
this.config = config;
|
||||
this.pool = pool;
|
||||
this.delayed = delayed;
|
||||
}
|
||||
|
||||
private HuaweiConfig config;
|
||||
|
||||
private Executor pool;
|
||||
|
||||
private DelayedTime delayed;
|
||||
|
||||
private final ForestConfiguration http = BeanFactory.getForestConfiguration();
|
||||
|
||||
@Override
|
||||
@Restricted
|
||||
public SmsResponse sendMessage(String phone, String message) {
|
||||
LinkedHashMap<String,String> mes = new LinkedHashMap<>();
|
||||
mes.put(UUID.randomUUID().toString().replaceAll("-",""),message);
|
||||
return sendMessage(phone,config.getTemplateId(),mes);
|
||||
LinkedHashMap<String, String> mes = new LinkedHashMap<>();
|
||||
mes.put(UUID.randomUUID().toString().replaceAll("-", ""), message);
|
||||
return sendMessage(phone, config.getTemplateId(), mes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -55,26 +47,30 @@ public class HuaweiSmsImpl implements SmsBlend {
|
||||
}
|
||||
String mess = listToString(list);
|
||||
String requestBody = HuaweiBuilder.buildRequestBody(config.getSender(), phone, templateId, mess, config.getStatusCallBack(), config.getSignature());
|
||||
Map<String,String> headers = new LinkedHashMap<>();
|
||||
headers.put("Authorization",Constant.HUAWEI_AUTH_HEADER_VALUE);
|
||||
headers.put("X-WSSE",HuaweiBuilder.buildWsseHeader(config.getAppKey(), config.getAppSecret()));
|
||||
headers.put("Content-Type",Constant.FROM_URLENCODED);
|
||||
Map<String, String> headers = new LinkedHashMap<>();
|
||||
headers.put("Authorization", Constant.HUAWEI_AUTH_HEADER_VALUE);
|
||||
headers.put("X-WSSE", HuaweiBuilder.buildWsseHeader(config.getAppKey(), config.getAppSecret()));
|
||||
headers.put("Content-Type", Constant.FROM_URLENCODED);
|
||||
SmsResponse smsResponse = new SmsResponse();
|
||||
http.post(url)
|
||||
.addHeader(headers)
|
||||
.addBody(requestBody)
|
||||
.onSuccess(((data,req,res)->{
|
||||
.onSuccess(((data, req, res) -> {
|
||||
HuaweiResponse jsonBody = res.get(HuaweiResponse.class);
|
||||
smsResponse.setCode(jsonBody.getCode());
|
||||
smsResponse.setMessage(jsonBody.getDescription());
|
||||
smsResponse.setBizId(jsonBody.getResult().get(0).getSmsMsgId());
|
||||
smsResponse.setData(jsonBody.getResult());
|
||||
}))
|
||||
.onError((ex,req,res)->{
|
||||
.onError((ex, req, res) -> {
|
||||
HuaweiResponse huaweiResponse = res.get(HuaweiResponse.class);
|
||||
smsResponse.setErrMessage(huaweiResponse.getDescription());
|
||||
smsResponse.setErrorCode(huaweiResponse.getCode());
|
||||
log.debug(huaweiResponse.getDescription());
|
||||
if (huaweiResponse == null) {
|
||||
smsResponse.setErrorCode("500");
|
||||
smsResponse.setErrMessage("huawei send sms response is null.check param");
|
||||
} else {
|
||||
smsResponse.setErrMessage(huaweiResponse.getDescription());
|
||||
smsResponse.setErrorCode(huaweiResponse.getCode());
|
||||
}
|
||||
})
|
||||
.execute();
|
||||
return smsResponse;
|
||||
@ -83,7 +79,7 @@ public class HuaweiSmsImpl implements SmsBlend {
|
||||
@Override
|
||||
@Restricted
|
||||
public SmsResponse massTexting(List<String> phones, String message) {
|
||||
return sendMessage(listToString(phones),message);
|
||||
return sendMessage(listToString(phones), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -91,76 +87,4 @@ public class HuaweiSmsImpl implements SmsBlend {
|
||||
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> 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.text.ParseException;
|
||||
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 {
|
||||
private HuaweiBuilder(){}
|
||||
@ -122,8 +127,9 @@ public class HuaweiBuilder {
|
||||
stringBuffer.append(s);
|
||||
stringBuffer.append("\"");
|
||||
stringBuffer.append(",");
|
||||
stringBuffer.append("\"");
|
||||
}
|
||||
stringBuffer.deleteCharAt(stringBuffer.length()-1);
|
||||
stringBuffer.delete(stringBuffer.length()-3,stringBuffer.length()-1);
|
||||
stringBuffer.append("]");
|
||||
return stringBuffer.toString();
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ 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;
|
||||
|
||||
/**
|
||||
@ -17,7 +18,7 @@ import org.dromara.sms4j.comm.config.BaseConfig;
|
||||
@SuperBuilder
|
||||
@ToString(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 org.dromara.sms4j.comm.factory.BeanFactory;
|
||||
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
|
||||
* @since 2023/4/10 20:01
|
||||
*/
|
||||
public class JdCloudSmsConfig {
|
||||
public class JdCloudFactory implements BaseProviderFactory<JdCloudSmsImpl, JdCloudConfig> {
|
||||
|
||||
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) {
|
||||
if (jdCloudSmsConfig == null) {
|
||||
jdCloudSmsConfig = new JdCloudSmsConfig();
|
||||
}
|
||||
@Override
|
||||
public JdCloudSmsImpl createSms(JdCloudConfig jdCloudConfig) {
|
||||
if (jdCloudSms == null) {
|
||||
jdCloudSms = new JdCloudSmsImpl(
|
||||
jdCloudSmsConfig.client(jdCloudConfig),
|
||||
this.client(jdCloudConfig),
|
||||
jdCloudConfig,
|
||||
BeanFactory.getExecutor(),
|
||||
BeanFactory.getDelayedTime()
|
||||
@ -54,16 +68,33 @@ public class JdCloudSmsConfig {
|
||||
/**
|
||||
* 刷新对象
|
||||
*/
|
||||
public static JdCloudSmsImpl refresh(JdCloudConfig jdCloudConfig) {
|
||||
if (jdCloudSmsConfig == null) {
|
||||
jdCloudSmsConfig = new JdCloudSmsConfig();
|
||||
}
|
||||
@Override
|
||||
public JdCloudSmsImpl refresh(JdCloudConfig jdCloudConfig) {
|
||||
jdCloudSms = new JdCloudSmsImpl(
|
||||
jdCloudSmsConfig.client(jdCloudConfig),
|
||||
this.client(jdCloudConfig),
|
||||
jdCloudConfig,
|
||||
BeanFactory.getExecutor(),
|
||||
BeanFactory.getDelayedTime()
|
||||
);
|
||||
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.BatchSendResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sms4j.api.SmsBlend;
|
||||
import org.dromara.sms4j.api.callback.CallBack;
|
||||
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;
|
||||
@ -16,8 +15,6 @@ import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -28,21 +25,16 @@ import java.util.stream.Collectors;
|
||||
* @since 2023/4/10 20:01
|
||||
*/
|
||||
@Slf4j
|
||||
public class JdCloudSmsImpl implements SmsBlend {
|
||||
public class JdCloudSmsImpl extends AbstractSmsBlend {
|
||||
|
||||
private final SmsClient client;
|
||||
|
||||
private final JdCloudConfig config;
|
||||
|
||||
private final Executor pool;
|
||||
|
||||
private final DelayedTime delayed;
|
||||
|
||||
public JdCloudSmsImpl(SmsClient client, JdCloudConfig config, Executor pool, DelayedTime delayed) {
|
||||
super(pool,delayed);
|
||||
this.client = client;
|
||||
this.config = config;
|
||||
this.pool = pool;
|
||||
this.delayed = delayed;
|
||||
}
|
||||
|
||||
@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.ToString;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||
import org.dromara.sms4j.comm.config.BaseConfig;
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class TencentConfig extends BaseConfig {
|
||||
public class TencentConfig extends BaseConfig implements SupplierConfig {
|
||||
|
||||
/**
|
||||
* 短信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;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.dtflys.forest.config.ForestConfiguration;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.jdcloud.sdk.utils.StringUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sms4j.api.SmsBlend;
|
||||
import org.dromara.sms4j.api.callback.CallBack;
|
||||
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.constant.Constant;
|
||||
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
|
||||
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.utils.TencentUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* @author wind
|
||||
*/
|
||||
@Slf4j
|
||||
public class TencentSmsImpl implements SmsBlend {
|
||||
public class TencentSmsImpl extends AbstractSmsBlend {
|
||||
|
||||
private TencentConfig tencentSmsConfig;
|
||||
|
||||
private Executor pool;
|
||||
|
||||
private DelayedTime delayed;
|
||||
|
||||
private final ForestConfiguration http = BeanFactory.getForestConfiguration();
|
||||
|
||||
public TencentSmsImpl(TencentConfig tencentSmsConfig, Executor pool, DelayedTime delayed) {
|
||||
super(pool, delayed);
|
||||
this.tencentSmsConfig = tencentSmsConfig;
|
||||
this.pool = pool;
|
||||
this.delayed = delayed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -77,7 +74,7 @@ public class TencentSmsImpl implements SmsBlend {
|
||||
list.add(entry.getValue());
|
||||
}
|
||||
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) {
|
||||
@ -101,102 +98,31 @@ public class TencentSmsImpl implements SmsBlend {
|
||||
.onSuccess(((data, req, res) -> {
|
||||
JSONObject jsonBody = res.get(JSONObject.class);
|
||||
JSONObject response = jsonBody.getJSONObject("Response");
|
||||
JSONArray sendStatusSet = response.getJSONArray("SendStatusSet");
|
||||
smsResponse.setBizId(sendStatusSet.getJSONObject(0).getString("SerialNo"));
|
||||
smsResponse.setMessage(sendStatusSet.getJSONObject(0).getString("Message"));
|
||||
smsResponse.setCode(sendStatusSet.getJSONObject(0).getString("Code"));
|
||||
String error = response.getStr("Error");
|
||||
if (StringUtils.isNotBlank(error)){
|
||||
smsResponse.setErrorCode("500");
|
||||
smsResponse.setErrMessage(error);
|
||||
}else {
|
||||
JSONArray sendStatusSet = response.getJSONArray("SendStatusSet");
|
||||
smsResponse.setBizId(sendStatusSet.getJSONObject(0).getStr("SerialNo"));
|
||||
smsResponse.setMessage(sendStatusSet.getJSONObject(0).getStr("Message"));
|
||||
smsResponse.setCode(sendStatusSet.getJSONObject(0).getStr("Code"));
|
||||
}
|
||||
}))
|
||||
.onError((ex, req, res) -> {
|
||||
JSONObject jsonBody = res.get(JSONObject.class);
|
||||
JSONObject response = jsonBody.getJSONObject("Response");
|
||||
JSONArray sendStatusSet = response.getJSONArray("SendStatusSet");
|
||||
smsResponse.setErrMessage(sendStatusSet.getJSONObject(0).getString("Message"));
|
||||
smsResponse.setErrorCode(sendStatusSet.getJSONObject(0).getString("Code"));
|
||||
if (jsonBody == null) {
|
||||
smsResponse.setErrorCode("500");
|
||||
smsResponse.setErrMessage("tencent send sms response is null.check param");
|
||||
} else {
|
||||
JSONObject response = jsonBody.getJSONObject("Response");
|
||||
JSONArray sendStatusSet = response.getJSONArray("SendStatusSet");
|
||||
smsResponse.setErrMessage(sendStatusSet.getJSONObject(0).getStr("Message"));
|
||||
smsResponse.setErrorCode(sendStatusSet.getJSONObject(0).getStr("Code"));
|
||||
}
|
||||
})
|
||||
.execute();
|
||||
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,
|
||||
String timestamp) throws Exception {
|
||||
// ************* 步骤 1:拼接规范请求串 *************
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
String date = sdf.format(new Date(Long.parseLong(timestamp + "000")));
|
||||
String canonicalUri = "/";
|
||||
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";
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
// 实际调用需要更新参数,这里仅作为演示签名验证通过的例子
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("PhoneNumberSet", phones);
|
||||
params.put("SmsSdkAppId", tencentConfig.getSdkAppId());
|
||||
params.put("SignName", tencentConfig.getSignature());
|
||||
@ -75,20 +73,15 @@ public class TencentUtils {
|
||||
params.put("TemplateParamSet", messages);
|
||||
String payload = JSON.toJSONString(params);
|
||||
String hashedRequestPayload = sha256Hex(payload);
|
||||
String canonicalRequest = HTTP_REQUEST_METHOD + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
|
||||
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
|
||||
// ************* 步骤 2:拼接待签名字符串 *************
|
||||
String credentialScope = date + "/" + tencentConfig.getService() + "/" + "tc3_request";
|
||||
String canonicalRequest = HTTP_REQUEST_METHOD + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
|
||||
String credentialScope = date + "/" + tencentConfig.getService() + "/tc3_request";
|
||||
String hashedCanonicalRequest = sha256Hex(canonicalRequest);
|
||||
String stringToSign = ALGORITHM + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
|
||||
// ************* 步骤 3:计算签名 *************
|
||||
byte[] secretDate = hmac256(("TC3" + tencentConfig.getAccessKeySecret()).getBytes(StandardCharsets.UTF_8), date);
|
||||
byte[] secretService = hmac256(secretDate, tencentConfig.getService());
|
||||
byte[] secretSigning = hmac256(secretService, "tc3_request");
|
||||
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.ToString;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||
import org.dromara.sms4j.comm.config.BaseConfig;
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@ToString(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;
|
||||
|
||||
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.service.UniSmsImpl;
|
||||
|
||||
@ -10,14 +11,27 @@ import org.dromara.sms4j.unisms.service.UniSmsImpl;
|
||||
* @author :Wind
|
||||
* 2023/4/8 15:46
|
||||
**/
|
||||
public class UniSmsConfig {
|
||||
|
||||
private UniSmsConfig(){}
|
||||
|
||||
private static UniSmsConfig uniSmsConfig;
|
||||
public class UniFactory implements BaseProviderFactory<UniSmsImpl, UniConfig> {
|
||||
|
||||
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){
|
||||
@ -33,12 +47,10 @@ public class UniSmsConfig {
|
||||
* <p>建造一个短信实现对像
|
||||
* @author :Wind
|
||||
*/
|
||||
public static UniSmsImpl createUniSms(UniConfig uniConfig){
|
||||
if (uniSmsConfig == null){
|
||||
uniSmsConfig = new UniSmsConfig();
|
||||
}
|
||||
@Override
|
||||
public UniSmsImpl createSms(UniConfig uniConfig){
|
||||
if (uniSmsImpl == null){
|
||||
uniSmsConfig.buildSms(uniConfig);
|
||||
this.buildSms(uniConfig);
|
||||
uniSmsImpl = new UniSmsImpl(
|
||||
uniConfig,
|
||||
BeanFactory.getExecutor(),
|
||||
@ -53,11 +65,9 @@ public class UniSmsConfig {
|
||||
* <p>刷新对象
|
||||
* @author :Wind
|
||||
*/
|
||||
public static UniSmsImpl refresh(UniConfig uniConfig){
|
||||
if (uniSmsConfig == null){
|
||||
uniSmsConfig = new UniSmsConfig();
|
||||
}
|
||||
uniSmsConfig.buildSms(uniConfig);
|
||||
@Override
|
||||
public UniSmsImpl refresh(UniConfig uniConfig){
|
||||
this.buildSms(uniConfig);
|
||||
uniSmsImpl = new UniSmsImpl(
|
||||
uniConfig,
|
||||
BeanFactory.getExecutor(),
|
||||
@ -65,4 +75,23 @@ public class UniSmsConfig {
|
||||
);
|
||||
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;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.dtflys.forest.config.ForestConfiguration;
|
||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||
import org.dromara.sms4j.comm.factory.BeanFactory;
|
||||
@ -79,6 +79,7 @@ public class UniClient {
|
||||
/**
|
||||
* request
|
||||
* <p>向 uni-sms发送请求
|
||||
*
|
||||
* @param action 接口名称
|
||||
* @author :Wind
|
||||
*/
|
||||
@ -91,21 +92,19 @@ public class UniClient {
|
||||
headers.put("User-Agent", USER_AGENT);
|
||||
headers.put("Content-Type", "application/json;charset=utf-8");
|
||||
headers.put("Accept", "application/json");
|
||||
return new UniResponse(
|
||||
JSONObject.parseObject(
|
||||
http.post(this.endpoint)
|
||||
.addHeader(headers)
|
||||
.addQuery(this.sign(query))
|
||||
.addBody(JSONObject.toJSONString(data))
|
||||
.successWhen(((req, res) -> {
|
||||
return res.noException() && // 请求过程没有异常
|
||||
res.statusIsNot(500); // 不能是 500
|
||||
}))
|
||||
.onError((ex, req, res) -> {
|
||||
throw new SmsBlendException(ex.getMessage());
|
||||
})
|
||||
.executeAsString()
|
||||
));
|
||||
String str = http.post(this.endpoint)
|
||||
.addHeader(headers)
|
||||
.addQuery(this.sign(query))
|
||||
.addBody(JSONUtil.toJsonStr(data))
|
||||
.successWhen(((req, res) -> {
|
||||
return res.noException() && // 请求过程没有异常
|
||||
res.statusIsNot(500); // 不能是 500
|
||||
}))
|
||||
.onError((ex, req, res) -> {
|
||||
throw new SmsBlendException(ex.getMessage());
|
||||
})
|
||||
.executeAsString();
|
||||
return new UniResponse(JSONUtil.parseObj(str));
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
package org.dromara.sms4j.unisms.core;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
public class UniResponse {
|
||||
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 {
|
||||
JSONObject body = response.getJSONObject("data");
|
||||
this.status = body.getJSONArray("messages").getJSONObject(0).getString("status");
|
||||
this.requestId = body.getJSONArray("messages").getJSONObject(0).getString("id");
|
||||
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;
|
||||
if (!Objects.isNull(body)) {
|
||||
this.status = body.getJSONArray("messages").getJSONObject(0).getStr("status");
|
||||
this.requestId = body.getJSONArray("messages").getJSONObject(0).getStr("id");
|
||||
this.raw = body;
|
||||
this.data = body;
|
||||
}
|
||||
else {
|
||||
throw new SmsBlendException(response.getString("message"), "-1");
|
||||
if (this.status != "400") {
|
||||
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;
|
||||
|
||||
import org.dromara.sms4j.api.SmsBlend;
|
||||
import org.dromara.sms4j.api.callback.CallBack;
|
||||
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.unisms.config.UniConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sms4j.unisms.core.Uni;
|
||||
import org.dromara.sms4j.unisms.core.UniResponse;
|
||||
|
||||
@ -16,11 +15,7 @@ import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
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.function.Supplier;
|
||||
|
||||
|
||||
/**
|
||||
@ -31,16 +26,13 @@ import java.util.function.Supplier;
|
||||
**/
|
||||
|
||||
@Slf4j
|
||||
public class UniSmsImpl implements SmsBlend {
|
||||
public class UniSmsImpl extends AbstractSmsBlend {
|
||||
|
||||
private UniConfig config;
|
||||
private Executor pool;
|
||||
private DelayedTime delayed;
|
||||
|
||||
public UniSmsImpl(UniConfig config, Executor pool, DelayedTime delayed) {
|
||||
super(pool,delayed);
|
||||
this.config = config;
|
||||
this.pool = pool;
|
||||
this.delayed = delayed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -90,76 +82,6 @@ public class UniSmsImpl implements SmsBlend {
|
||||
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) {
|
||||
SmsResponse smsResponse = new SmsResponse();
|
||||
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;
|
||||
|
||||
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;
|
||||
@Data
|
||||
@Builder
|
||||
public class YunpianConfig {
|
||||
/**
|
||||
* 账号唯一标识
|
||||
*/
|
||||
private String apikey;
|
||||
@SuperBuilder
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class YunpianConfig extends BaseConfig implements SupplierConfig {
|
||||
|
||||
/**
|
||||
* 短信发送后将向这个地址推送(运营商返回的)发送报告
|
||||
*/
|
||||
private String callbackUrl;
|
||||
|
||||
/**
|
||||
* 模板Id
|
||||
*/
|
||||
private String templateId;
|
||||
|
||||
/**
|
||||
* 模板变量名称
|
||||
*/
|
||||
|
||||
@ -1,40 +1,46 @@
|
||||
package org.dromara.sms4j.yunpian.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.dtflys.forest.config.ForestConfiguration;
|
||||
import org.dromara.sms4j.api.SmsBlend;
|
||||
import org.dromara.sms4j.api.callback.CallBack;
|
||||
import cn.hutool.json.JSONObject;
|
||||
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.constant.Constant;
|
||||
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.yunpian.config.YunpianConfig;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
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 {
|
||||
|
||||
private Executor pool;
|
||||
|
||||
private DelayedTime delayed;
|
||||
public YunPianSmsImpl(Executor pool, DelayedTime delayed, YunpianConfig config) {
|
||||
super(pool, delayed);
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
private YunpianConfig config;
|
||||
|
||||
private ForestConfiguration http;
|
||||
|
||||
private static SmsResponse getSmsResponse(JSONObject execute) {
|
||||
SmsResponse smsResponse = new SmsResponse();
|
||||
smsResponse.setCode(execute.getString("code"));
|
||||
smsResponse.setMessage(execute.getString("msg"));
|
||||
smsResponse.setBizId(execute.getString("sid"));
|
||||
if (execute.getInteger("code") != 0) {
|
||||
smsResponse.setErrMessage(execute.getString("msg"));
|
||||
if (execute == null) {
|
||||
smsResponse.setErrorCode("500");
|
||||
smsResponse.setErrMessage("yunpian send sms response is null.check param");
|
||||
return smsResponse;
|
||||
}
|
||||
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);
|
||||
return smsResponse;
|
||||
@ -50,7 +56,7 @@ public class YunPianSmsImpl implements SmsBlend {
|
||||
@Override
|
||||
@Restricted
|
||||
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);
|
||||
}
|
||||
|
||||
@ -60,7 +66,7 @@ public class YunPianSmsImpl implements SmsBlend {
|
||||
if (phones.size() > 1000) {
|
||||
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于1000");
|
||||
}
|
||||
return sendMessage(listToString(phones), message);
|
||||
return sendMessage(SmsUtil.listToString(phones), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -69,79 +75,7 @@ public class YunPianSmsImpl implements SmsBlend {
|
||||
if (phones.size() > 1000) {
|
||||
throw new SmsBlendException("单次发送超过最大发送上限,建议每次群发短信人数低于1000");
|
||||
}
|
||||
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);
|
||||
return sendMessage(SmsUtil.listToString(phones), templateId, messages);
|
||||
}
|
||||
|
||||
private String formattingMap(Map<String, String> messages) {
|
||||
@ -165,11 +99,12 @@ public class YunPianSmsImpl implements SmsBlend {
|
||||
message.put(config.getTemplateName(), mes);
|
||||
}
|
||||
Map<String, String> body = new HashMap<>();
|
||||
body.put("apikey", config.getApikey());
|
||||
body.put("apikey", config.getAccessKeyId());
|
||||
body.put("mobile", phone);
|
||||
body.put("tpl_id", tplId);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -182,7 +117,7 @@ public class YunPianSmsImpl implements SmsBlend {
|
||||
|
||||
private SmsResponse getSendResponse(Map<String, String> body) {
|
||||
Map<String, String> headers = getHeaders();
|
||||
AtomicReference<SmsResponse> smsResponse = null;
|
||||
AtomicReference<SmsResponse> smsResponse = new AtomicReference<>();
|
||||
http.post(Constant.YUNPIAN_URL + "/sms/tpl_single_send.json")
|
||||
.addHeader(headers)
|
||||
.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;
|
||||
|
||||
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.factory.SmsFactory;
|
||||
import org.dromara.sms4j.provider.enumerate.SupplierType;
|
||||
import org.dromara.sms4j.unisms.config.UniConfig;
|
||||
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 static final String USER_AGENT = "uni-java-sdk" + "/0.0.4" ;
|
||||
|
||||
@Test
|
||||
public void uniSmsTest() {
|
||||
UniConfig build = UniConfig.builder()
|
||||
.signature("洙旭阁")
|
||||
.accessKeyId("7Cr1ZaQVJQ11Ap4HBQMo7xmFg")
|
||||
.signature("***")
|
||||
.accessKeyId("7Cr1***VJQ11Ap4***Mo7xmFg")
|
||||
.templateId("2001")
|
||||
.templateName("message")
|
||||
.isSimple(true)
|
||||
.build();
|
||||
SupplierFactory.setUniConfig(build);
|
||||
|
||||
SmsResponse smsResponse = SmsFactory.createSmsBlend(SupplierType.UNI_SMS).sendMessage("17531165952", "123123");
|
||||
SmsResponse smsResponse = SmsFactory.createSmsBlend(SupplierType.UNI_SMS).sendMessage("175***65952", "123123");
|
||||
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>
|
||||
|
||||
<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>
|
||||
<groupId>org.dromara.sms4j</groupId>
|
||||
<artifactId>sms4j-autoimmit</artifactId>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user