diff --git a/README.md b/README.md index 4661e9a8..8d397f34 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -

sms4j v2.0.2

+

sms4j v2.1.0

sms4j -- 让发送短信变的更简单

- +

@@ -28,6 +28,7 @@ - **京东云国内短信** - **容联云国内短信** - **亿美软通国内短信** +- **天翼云短信** - **合一短信** - **云片短信** diff --git a/pom.xml b/pom.xml index fbd0f6f5..4a1e3bfa 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,8 @@ sms4j-core sms4j-autoimmit sms4j-spring-boot-starter + sms4j-solon-plugin + sms4j-spring-boot-example @@ -47,17 +49,16 @@ - 2.7.11 - 2.0.2 - 2.0.23 - 3.1.622 - 0.0.4 + 2.1.0-SNAPSHOT + + UTF-8 + UTF-8 + 2.7.12 + 2.2.0 + 3.17.0 1.3.3 - 2.0.15 - 3.14.9 1.5.30 - 5.8.16 - 3.14.9 + 5.8.18 2.3.0 1.1.1 @@ -119,13 +120,6 @@ ${revision} - - - com.alibaba - fastjson - ${json.version} - - com.dtflys.forest diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/AbstractSmsBlend.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/AbstractSmsBlend.java new file mode 100644 index 00000000..9a32765c --- /dev/null +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/AbstractSmsBlend.java @@ -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(); + } + + /** + *

说明:发送固定消息模板短信 + *

此方法将使用配置文件中预设的短信模板进行短信发送 + *

该方法指定的模板变量只能存在一个(配置文件中) + *

如使用的是腾讯的短信,参数字符串中可以同时存在多个参数,使用 & 分隔例如:您的验证码为{1}在{2}分钟内有效,可以传为 message="xxxx"+"&"+"5" + * sendMessage + * + * @param phone 接收短信的手机号 + * message 消息内容 + * @author :Wind + */ + + public abstract SmsResponse sendMessage(String phone, String message); + + /** + *

说明:使用自定义模板发送短信 + * sendMessage + * + * @param templateId 模板id + * @param messages key为模板变量名称 value为模板变量值 + * @author :Wind + */ + + public abstract SmsResponse sendMessage(String phone, String templateId, LinkedHashMap messages); + + /** + *

说明:群发固定模板短信 + * massTexting + * + * @author :Wind + */ + + public abstract SmsResponse massTexting(List phones, String message); + + /** + *

说明:使用自定义模板群发短信 + * massTexting + * + * @author :Wind + */ + + public abstract SmsResponse massTexting(List phones, String templateId, LinkedHashMap messages); + + /** + *

说明:异步短信发送,固定消息模板短信 + * sendMessageAsync + * + * @param phone 要发送的号码 + * @param message 发送内容 + * @param callBack 回调 + * @author :Wind + */ + @Restricted + public final void sendMessageAsync(String phone, String message, CallBack callBack){ + CompletableFuture smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, message), pool); + smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack); + } + + /** + *

说明:异步发送短信,不关注发送结果 + * sendMessageAsync + * + * @param phone 要发送的号码 + * @param message 发送内容 + * @author :Wind + */ + @Restricted + public final void sendMessageAsync(String phone, String message){ + pool.execute(() -> { + sendMessage(phone, message); + }); + } + + /** + *

说明:异步短信发送,使用自定义模板发送短信 + * sendMessage + * + * @param templateId 模板id + * @param messages key为模板变量名称 value为模板变量值 + * @param callBack 回调 + * @author :Wind + */ + + @Restricted + public final void sendMessageAsync(String phone, String templateId, LinkedHashMap messages, CallBack callBack){ + CompletableFuture smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone,templateId, messages), pool); + smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack); + } + + /** + *

说明:异步短信发送,使用自定义模板发送短信,不关注发送结果 + * sendMessageAsync + * + * @param templateId 模板id + * @param messages key为模板变量名称 value为模板变量值 + * @author :Wind + */ + @Restricted + public final void sendMessageAsync(String phone, String templateId, LinkedHashMap messages){ + pool.execute(() -> { + sendMessage(phone, templateId, messages); + }); + } + + /** + *

说明:使用固定模板发送延时短信 + * 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); + } + + /** + *

说明:使用自定义模板发送定时短信 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 messages, Long delayedTime){ + this.delayed.schedule(new TimerTask() { + @Override + public void run() { + sendMessage(phone, templateId, messages); + } + }, delayedTime); + } + + /** + *

说明:群发延迟短信 + * delayMassTexting + * + * @param phones 要群体发送的手机号码 + * @author :Wind + */ + @Restricted + public final void delayMassTexting(List phones, String message, Long delayedTime){ + this.delayed.schedule(new TimerTask() { + @Override + public void run() { + massTexting(phones, message); + } + }, delayedTime); + } + + /** + *

说明:使用自定义模板发送群体延迟短信 + * delayMassTexting + * + * @param phones 要群体发送的手机号码 + * @param templateId 模板id + * @param messages key为模板变量名称 value为模板变量值 + * @param delayedTime 延迟的时间 + * @author :Wind + */ + @Restricted + public final void delayMassTexting(List phones, String templateId, LinkedHashMap messages, Long delayedTime){ + this.delayed.schedule(new TimerTask() { + @Override + public void run() { + massTexting(phones, templateId, messages); + } + }, delayedTime); + } +} diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/SmsBlend.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/SmsBlend.java index 31042825..8ee351cf 100644 --- a/sms4j-api/src/main/java/org/dromara/sms4j/api/SmsBlend.java +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/SmsBlend.java @@ -6,136 +6,35 @@ import org.dromara.sms4j.api.entity.SmsResponse; import java.util.LinkedHashMap; import java.util.List; +/** + * SmsBlend + *

通用接口,定义国内短信方法 + * @author :Wind + * 2023/5/16 16:03 + **/ public interface SmsBlend { - /** - *

说明:发送固定消息模板短信 - *

此方法将使用配置文件中预设的短信模板进行短信发送 - *

该方法指定的模板变量只能存在一个(配置文件中) - *

如使用的是腾讯的短信,参数字符串中可以同时存在多个参数,使用 & 分隔例如:您的验证码为{1}在{2}分钟内有效,可以传为 message="xxxx"+"&"+"5" - * sendMessage - * - * @param phone 接收短信的手机号 - * message 消息内容 - * @author :Wind - */ - SmsResponse sendMessage(String phone, String message); - /** - *

说明:使用自定义模板发送短信 - * sendMessage - * - * @param templateId 模板id - * @param messages key为模板变量名称 value为模板变量值 - * @author :Wind - */ - SmsResponse sendMessage(String phone, String templateId, LinkedHashMap messages); - /** - *

说明:群发固定模板短信 - * massTexting - * - * @author :Wind - */ - SmsResponse massTexting(List phones, String message); - /** - *

说明:使用自定义模板群发短信 - * massTexting - * - * @author :Wind - */ - SmsResponse massTexting(List phones, String templateId, LinkedHashMap messages); - /** - *

说明:异步短信发送,固定消息模板短信 - * sendMessageAsync - * - * @param phone 要发送的号码 - * @param message 发送内容 - * @param callBack 回调 - * @author :Wind - */ - void sendMessageAsync(String phone, String message, CallBack callBack); - /** - *

说明:异步发送短信,不关注发送结果 - * sendMessageAsync - * - * @param phone 要发送的号码 - * @param message 发送内容 - * @author :Wind - */ void sendMessageAsync(String phone, String message); - /** - *

说明:异步短信发送,使用自定义模板发送短信 - * sendMessage - * - * @param templateId 模板id - * @param messages key为模板变量名称 value为模板变量值 - * @param callBack 回调 - * @author :Wind - */ - void sendMessageAsync(String phone, String templateId, LinkedHashMap messages, CallBack callBack); - /** - *

说明:异步短信发送,使用自定义模板发送短信,不关注发送结果 - * sendMessageAsync - * - * @param templateId 模板id - * @param messages key为模板变量名称 value为模板变量值 - * @author :Wind - */ void sendMessageAsync(String phone, String templateId, LinkedHashMap messages); - /** - *

说明:使用固定模板发送延时短信 - * delayedMessage - * - * @param phone 接收短信的手机号 - * @param message 要发送的短信 - * @param delayedTime 延迟时间 - * @author :Wind - */ void delayedMessage(String phone, String message, Long delayedTime); - /** - *

说明:使用自定义模板发送定时短信 sendMessage - * delayedMessage - * - * @param templateId 模板id - * @param messages key为模板变量名称 value为模板变量值 - * @param phone 要发送的手机号 - * @param delayedTime 延迟的时间 - * @author :Wind - */ void delayedMessage(String phone, String templateId, LinkedHashMap messages, Long delayedTime); - /** - *

说明:群发延迟短信 - * delayMassTexting - * - * @param phones 要群体发送的手机号码 - * @author :Wind - */ void delayMassTexting(List phones, String message, Long delayedTime); - /** - *

说明:使用自定义模板发送群体延迟短信 - * delayMassTexting - * - * @param phones 要群体发送的手机号码 - * @param templateId 模板id - * @param messages key为模板变量名称 value为模板变量值 - * @param delayedTime 延迟的时间 - * @author :Wind - */ void delayMassTexting(List phones, String templateId, LinkedHashMap messages, Long delayedTime); } diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/smsProxy/RestrictedProcess.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/smsProxy/RestrictedProcess.java new file mode 100644 index 00000000..748cb90d --- /dev/null +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/smsProxy/RestrictedProcess.java @@ -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; + } +} diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/smsProxy/SmsInvocationHandler.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/smsProxy/SmsInvocationHandler.java new file mode 100644 index 00000000..88c3be47 --- /dev/null +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/smsProxy/SmsInvocationHandler.java @@ -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; + } +} diff --git a/sms4j-api/src/main/java/org/dromara/sms4j/api/universal/SupplierConfig.java b/sms4j-api/src/main/java/org/dromara/sms4j/api/universal/SupplierConfig.java new file mode 100644 index 00000000..ad17efff --- /dev/null +++ b/sms4j-api/src/main/java/org/dromara/sms4j/api/universal/SupplierConfig.java @@ -0,0 +1,10 @@ +package org.dromara.sms4j.api.universal; + +/** + * SupplierConfig + *

空接口,无含义,只为标定配置类的额外类型 + * @author :Wind + * 2023/5/16 15:14 + **/ +public interface SupplierConfig { +} diff --git a/sms4j-api/src/main/resources/application.properties b/sms4j-api/src/main/resources/application.properties deleted file mode 100644 index 8b137891..00000000 --- a/sms4j-api/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/aop/AopAdvice.java b/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/aop/AopAdvice.java deleted file mode 100644 index 19ebdd54..00000000 --- a/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/aop/AopAdvice.java +++ /dev/null @@ -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 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; - } - -} diff --git a/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/aop/RestrictedProcessImpl.java b/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/aop/RestrictedProcessImpl.java new file mode 100644 index 00000000..5710de66 --- /dev/null +++ b/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/aop/RestrictedProcessImpl.java @@ -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; + } +} diff --git a/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/config/SmsAutowiredConfig.java b/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/config/SmsAutowiredConfig.java index 970b1701..7625abff 100644 --- a/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/config/SmsAutowiredConfig.java +++ b/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/config/SmsAutowiredConfig.java @@ -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); } } } diff --git a/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/config/SupplierConfig.java b/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/config/SupplierConfig.java index ad90c132..0ae91749 100644 --- a/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/config/SupplierConfig.java +++ b/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/config/SupplierConfig.java @@ -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(); + } } diff --git a/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/utils/RedisUtils.java b/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/utils/RedisUtils.java index 0331e52f..aa8e1a26 100644 --- a/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/utils/RedisUtils.java +++ b/sms4j-autoimmit/src/main/java/org/dromara/sms4j/autoimmit/utils/RedisUtils.java @@ -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; diff --git a/sms4j-autoimmit/src/main/resources/application.properties b/sms4j-autoimmit/src/main/resources/application.properties deleted file mode 100644 index 8b137891..00000000 --- a/sms4j-autoimmit/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/sms4j-comm/pom.xml b/sms4j-comm/pom.xml index 56074827..eff30c00 100644 --- a/sms4j-comm/pom.xml +++ b/sms4j-comm/pom.xml @@ -15,11 +15,6 @@ sms4j-comm - - com.alibaba - fastjson - - com.dtflys.forest forest-core diff --git a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/config/SmsConfig.java b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/config/SmsConfig.java index 5db5bc13..a7a7c276 100644 --- a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/config/SmsConfig.java +++ b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/config/SmsConfig.java @@ -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 { diff --git a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/Constant.java b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/Constant.java index 273853d9..96aed3e1 100644 --- a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/Constant.java +++ b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/Constant.java @@ -1,9 +1,6 @@ package org.dromara.sms4j.comm.constant; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - /** * Constant *

短信应用常量 @@ -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"参数赋值 diff --git a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/delayedTime/DelayedTime.java b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/delayedTime/DelayedTime.java index 621b3cfd..bf53f152 100644 --- a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/delayedTime/DelayedTime.java +++ b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/delayedTime/DelayedTime.java @@ -1,6 +1,7 @@ package org.dromara.sms4j.comm.delayedTime; -import java.util.*; +import java.util.Timer; +import java.util.TimerTask; /** *

类名: DelayedTime diff --git a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/enumerate/SupplierType.java b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/enumerate/SupplierType.java deleted file mode 100644 index d096515d..00000000 --- a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/enumerate/SupplierType.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.dromara.sms4j.comm.enumerate; - -/** - * SupplierType - *

短信供应商枚举 - * @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; - } -} diff --git a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/JDBCTool.java b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/JDBCTool.java index c2cf9980..5c8c1683 100644 --- a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/JDBCTool.java +++ b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/JDBCTool.java @@ -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; diff --git a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/SmsUtil.java b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/SmsUtil.java index 3a43859e..d91b6da9 100644 --- a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/SmsUtil.java +++ b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/SmsUtil.java @@ -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() { } //私有构造防止实例化 - /** *

说明:生成一个指定长度的随机字符串,包含大小写英文字母和数字但不包含符号 * * @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); } /** *

说明:获取一个长度为6的随机字符串 - *getRandomString + * getRandomString + * * @author :Wind */ public static String getRandomString() { @@ -48,37 +40,29 @@ public class SmsUtil { /** *

说明:生成一个指定长度的只有数字组成的随机字符串 + * * @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 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 *

将json字符串转化为指定的对象 + * * @author :Wind - */ + */ public static T jsonForObject(String json, Class 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 *

拷贝bean,只有源对象不为null才会拷贝 + * * @param t 源对象 * @param m 目标对象 * @author :Wind - */ - public static void copyBean(T t,M m){ - if (t != null){ - BeanUtil.copyProperties(t, m); - } + */ + public static void copyBean(T t, M m) { + BeanUtil.copyProperties(t, m); } -} + /** + * getNewMap + *

获取一个新的空LinkedHashMap + * + * @return 空的 LinkedHashMap 实例 + * @author :Wind + */ + public static LinkedHashMap getNewMap() { + return new LinkedHashMap<>(); + } + + /** + * listToString + *

将list转化为string,元素之间使用逗号分隔,此方法只支持list内部元素为String类型的 + * + * @param list 要转换的list + * @author :Wind + */ + public static String listToString(List list) { + return CollUtil.join(list, ","); + } + + /** + * 以 conjunction 为分隔符将集合转换为字符串 + * + * @param list 集合 + * @return 结果字符串 + */ + public static String arrayToString(List list) { + return CollUtil.join(list, ",", "+86", ""); + } + + /** + * List +86后转 数组 + * + * @param list 集合 + * @return 结果字符串 + */ + public static String[] listToArray(List list) { + List toStr = new ArrayList<>(); + for (String s : list) { + toStr.add("+86" + s); + } + return toStr.toArray(new String[list.size()]); + } + +} \ No newline at end of file diff --git a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/TimeExpiredPoolCache.java b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/TimeExpiredPoolCache.java index 0eccf02c..1ffaf16d 100644 --- a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/TimeExpiredPoolCache.java +++ b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/TimeExpiredPoolCache.java @@ -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); } /** diff --git a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/http/HttpJsonTool.java b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/http/HttpJsonTool.java deleted file mode 100644 index c3137437..00000000 --- a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/utils/http/HttpJsonTool.java +++ /dev/null @@ -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 getJSONBody(Object response,Classt){ - return JSONObject.parseObject(response.toString(), t); - } - - public static T getJSONBody(String response,Classt){ - return JSONObject.parseObject(response, t); - } - - public static JSONObject getJSONObject(Object obj){ - return JSONObject.parseObject(obj.toString()); - } -} diff --git a/sms4j-comm/src/main/resources/application.properties b/sms4j-comm/src/main/resources/application.properties deleted file mode 100644 index 8b137891..00000000 --- a/sms4j-comm/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/SupplierSqlConfig.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/SupplierSqlConfig.java index ab37636b..48c9bf92 100644 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/SupplierSqlConfig.java +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/SupplierSqlConfig.java @@ -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 + *

数据库读取并设置天翼云短信 + * @author :Wind + */ + public static void ctyun(){ + CtyunConfig ctyunConfig = SmsUtil.jsonForObject(select.get(SupplierType.CTYUN.getName()), CtyunConfig.class); + SupplierFactory.setCtyunConfig(ctyunConfig); + } } diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/config/SupplierFactory.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/config/SupplierFactory.java index d494d9a7..d9765bf2 100644 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/config/SupplierFactory.java +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/config/SupplierFactory.java @@ -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 + *

通用化set,用于设置 + * @param t 配置对象 + * @author :Wind + */ + public static 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); + } } diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/factory/SmsFactory.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/factory/SmsFactory.java index 5297c2be..c8ab2825 100644 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/factory/SmsFactory.java +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/factory/SmsFactory.java @@ -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 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 + *

获取某个厂商的带有短信拦截的实现 + * + * @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 + *

刷新带有短信拦截的对象实现 + * @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 + ); + } } diff --git a/sms4j-core/src/main/java/org/dromara/sms4j/core/load/SmsLoad.java b/sms4j-core/src/main/java/org/dromara/sms4j/core/load/SmsLoad.java index e04b0cc0..362c2148 100644 --- a/sms4j-core/src/main/java/org/dromara/sms4j/core/load/SmsLoad.java +++ b/sms4j-core/src/main/java/org/dromara/sms4j/core/load/SmsLoad.java @@ -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 diff --git a/sms4j-core/src/main/resources/application.properties b/sms4j-core/src/main/resources/application.properties deleted file mode 100644 index 8b137891..00000000 --- a/sms4j-core/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/config/AlibabaConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/config/AlibabaConfig.java index b10262d7..2147f3b1 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/config/AlibabaConfig.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/config/AlibabaConfig.java @@ -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 { /** * 模板变量名称 diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/config/AlibabaFactory.java b/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/config/AlibabaFactory.java new file mode 100644 index 00000000..dbe83418 --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/config/AlibabaFactory.java @@ -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 + *

阿里巴巴对象建造者 + * + * @author :Wind + * 2023/4/8 14:54 + **/ +@Slf4j +public class AlibabaFactory implements BaseProviderFactory { + + 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; + } + +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/config/AlibabaSmsConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/config/AlibabaSmsConfig.java deleted file mode 100644 index ce2b6b4d..00000000 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/config/AlibabaSmsConfig.java +++ /dev/null @@ -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 - *

阿里巴巴对象建造者 - * - * @author :Wind - * 2023/4/8 14:54 - **/ -@Slf4j -public class AlibabaSmsConfig { - - private static AlibabaSmsImpl alibabaSms; - - private static AlibabaSmsConfig alibabaSmsConfig; - - /** - * getAlibabaSms - *

建造一个短信实现对像 - * - * @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 - *

刷新对象 - * - * @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() { - } -} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/service/AlibabaSmsImpl.java b/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/service/AlibabaSmsImpl.java index 23f3578c..14b3205f 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/service/AlibabaSmsImpl.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/service/AlibabaSmsImpl.java @@ -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; /** *

类名: 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 *

构造器,用于构造短信实现模块 * * @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 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 phones, String templateId, LinkedHashMap 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 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 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 messages, CallBack callBack) { - CompletableFuture smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone,templateId, messages), pool); - smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack); - } - - @Override - @Restricted - public void sendMessageAsync(String phone, String templateId, LinkedHashMap 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 messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - sendMessage(phone, templateId, messages); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String message, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones, message); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String templateId, LinkedHashMap messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones, templateId, messages); - } - }, delayedTime); - } - - private String arrayToString(List list) { - StringBuilder sb = new StringBuilder(); - for (String s : list) { - sb.append(",").append("+86").append(s); - } - return sb.substring(1); - } -} +} \ No newline at end of file diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/utils/AliyunUtils.java b/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/utils/AliyunUtils.java index 55af6c42..474bfc86 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/utils/AliyunUtils.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/aliyun/utils/AliyunUtils.java @@ -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 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); } /** diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/config/CloopenConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/config/CloopenConfig.java index efeefb15..124ff18e 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/config/CloopenConfig.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/config/CloopenConfig.java @@ -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 diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/config/CloopenFactory.java b/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/config/CloopenFactory.java new file mode 100644 index 00000000..04c5f58c --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/config/CloopenFactory.java @@ -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 { + + 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; + } + +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/config/CloopenSmsConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/config/CloopenSmsConfig.java deleted file mode 100644 index 31f058fa..00000000 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/config/CloopenSmsConfig.java +++ /dev/null @@ -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; - } -} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/service/CloopenSmsImpl.java b/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/service/CloopenSmsImpl.java index 29c45ee7..32ca6af6 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/service/CloopenSmsImpl.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/cloopen/service/CloopenSmsImpl.java @@ -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 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 messages, CallBack callBack) { - CompletableFuture smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone,templateId, messages), pool); - smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack); - } - - @Override - @Restricted - public void sendMessageAsync(String phone, String templateId, LinkedHashMap 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 messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - sendMessage(phone, templateId, messages); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String message, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones, message); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String templateId, LinkedHashMap messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones, templateId, messages); - } - }, delayedTime); - } } diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/ctyun/config/CtyunConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/ctyun/config/CtyunConfig.java new file mode 100644 index 00000000..5c818247 --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/ctyun/config/CtyunConfig.java @@ -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; + +/** + *

类名: CtyunConfig + *

说明: 天翼云短信差异配置 + * + * @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"; +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/ctyun/config/CtyunFactory.java b/sms4j-provider/src/main/java/org/dromara/sms4j/ctyun/config/CtyunFactory.java new file mode 100644 index 00000000..bfb77d44 --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/ctyun/config/CtyunFactory.java @@ -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; + +/** + *

类名: CtyunSmsConfig + *

说明: 天翼云 云通信短信配置器 + * + * @author :bleachhtred + * 2023/5/12 15:06 + **/ +@Slf4j +public class CtyunFactory implements BaseProviderFactory { + + 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 + *

建造一个短信实现对像 + * + * @author :bleachhtred + */ + @Override + public CtyunSmsImpl createSms(CtyunConfig ctyunConfig) { + if (ctyunSms == null) { + ctyunSms = new CtyunSmsImpl( + ctyunConfig, + BeanFactory.getExecutor(), + BeanFactory.getDelayedTime()); + } + return ctyunSms; + } + + /** + * refresh + *

刷新对象 + * + * @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; + } +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/ctyun/service/CtyunSmsImpl.java b/sms4j-provider/src/main/java/org/dromara/sms4j/ctyun/service/CtyunSmsImpl.java new file mode 100644 index 00000000..f8bc710c --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/ctyun/service/CtyunSmsImpl.java @@ -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; + +/** + *

类名: CtyunSmsImpl + *

说明: 天翼云短信实现 + * + * @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 map = new LinkedHashMap<>(); + map.put(ctyunConfig.getTemplateName(), message); + return sendMessage(phone, ctyunConfig.getTemplateId(), map); + } + + @Override + @Restricted + public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap messages) { + String messageStr = JSONUtil.toJsonStr(messages); + return getSmsResponse(phone, messageStr, templateId); + } + + @Override + @Restricted + public SmsResponse massTexting(List phones, String message) { + LinkedHashMap map = new LinkedHashMap<>(); + map.put(ctyunConfig.getTemplateName(), message); + return massTexting(phones, ctyunConfig.getTemplateId(), map); + } + + @Override + @Restricted + public SmsResponse massTexting(List phones, String templateId, LinkedHashMap messages) { + String messageStr = JSONUtil.toJsonStr(messages); + return getSmsResponse(SmsUtil.arrayToString(phones), messageStr, templateId); + } + + private SmsResponse getSmsResponse(String phone, String message, String templateId) { + AtomicReference 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; + } + +} \ No newline at end of file diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/ctyun/utils/CtyunUtils.java b/sms4j-provider/src/main/java/org/dromara/sms4j/ctyun/utils/CtyunUtils.java new file mode 100644 index 00000000..c7880640 --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/ctyun/utils/CtyunUtils.java @@ -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 signHeader(String body, String key, String secret){ + Map 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 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()); + } + } +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/emay/config/EmayConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/emay/config/EmayConfig.java index e9d273af..f91868ab 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/emay/config/EmayConfig.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/emay/config/EmayConfig.java @@ -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 */ diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/emay/config/EmayFactory.java b/sms4j-provider/src/main/java/org/dromara/sms4j/emay/config/EmayFactory.java new file mode 100644 index 00000000..3ccd9720 --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/emay/config/EmayFactory.java @@ -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 + *

Emay短信对象建造 + * + * @author Richard + * @date 2023/04/11 12:00 + * */ +public class EmayFactory implements BaseProviderFactory { + 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; + } + +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/emay/config/EmaySmsConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/emay/config/EmaySmsConfig.java deleted file mode 100644 index d9c7db2e..00000000 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/emay/config/EmaySmsConfig.java +++ /dev/null @@ -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 - *

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; - } - -} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/emay/service/EmaySmsImpl.java b/sms4j-provider/src/main/java/org/dromara/sms4j/emay/service/EmaySmsImpl.java index 4c96c7e0..9e6cb7e0 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/emay/service/EmaySmsImpl.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/emay/service/EmaySmsImpl.java @@ -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 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 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 messages, CallBack callBack) { - CompletableFuture smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, templateId, messages), pool); - smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack); - } - - @Override - @Restricted - public void sendMessageAsync(String phone, String templateId, LinkedHashMap 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 messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - sendMessage(phone, templateId, messages); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String message, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones, message); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String templateId, LinkedHashMap 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 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; } } diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/config/HuaweiConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/config/HuaweiConfig.java index ba2e9f5a..a11a8902 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/config/HuaweiConfig.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/config/HuaweiConfig.java @@ -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 ; diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/config/HuaweiFactory.java b/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/config/HuaweiFactory.java new file mode 100644 index 00000000..6b62aef6 --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/config/HuaweiFactory.java @@ -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 + *

华为短信对象建造 + * + * @author :Wind + * 2023/4/8 15:27 + **/ +public class HuaweiFactory implements BaseProviderFactory { + 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; + } + +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/config/HuaweiSmsConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/config/HuaweiSmsConfig.java deleted file mode 100644 index 3aed8b40..00000000 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/config/HuaweiSmsConfig.java +++ /dev/null @@ -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 - *

华为短信对象建造 - * - * @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; - } - -} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/entity/SmsId.java b/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/entity/SmsId.java index 185611d3..197e6bf4 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/entity/SmsId.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/entity/SmsId.java @@ -2,8 +2,6 @@ package org.dromara.sms4j.huawei.entity; import lombok.Data; -import java.util.Date; - /** * SmsId *

短信ID列表 diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/service/HuaweiSmsImpl.java b/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/service/HuaweiSmsImpl.java index 971f98c9..6321a19b 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/service/HuaweiSmsImpl.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/service/HuaweiSmsImpl.java @@ -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 mes = new LinkedHashMap<>(); - mes.put(UUID.randomUUID().toString().replaceAll("-",""),message); - return sendMessage(phone,config.getTemplateId(),mes); + LinkedHashMap 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 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 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 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 phones, String templateId, LinkedHashMap messages) { return sendMessage(listToString(phones), templateId, messages); } - - @Override - @Restricted - public void sendMessageAsync(String phone, String message, CallBack callBack) { - CompletableFuture 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 messages, CallBack callBack) { - CompletableFuture smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, templateId, messages), pool); - smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack); - } - - @Override - @Restricted - public void sendMessageAsync(String phone, String templateId, LinkedHashMap 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 messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - sendMessage(phone, templateId, messages); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String message, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones, message); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String templateId, LinkedHashMap messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones, templateId, messages); - } - }, delayedTime); - } } diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/utils/HuaweiBuilder.java b/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/utils/HuaweiBuilder.java index 27a05b14..462100ff 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/utils/HuaweiBuilder.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/huawei/utils/HuaweiBuilder.java @@ -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(); } diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/config/JdCloudConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/config/JdCloudConfig.java index 5fbc6f70..af179568 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/config/JdCloudConfig.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/config/JdCloudConfig.java @@ -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 { /** * 地域信息 diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/config/JdCloudSmsConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/config/JdCloudFactory.java similarity index 58% rename from sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/config/JdCloudSmsConfig.java rename to sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/config/JdCloudFactory.java index cf29b5ca..5c3cde20 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/config/JdCloudSmsConfig.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/config/JdCloudFactory.java @@ -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 { 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; + } + } diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/service/JdCloudSmsImpl.java b/sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/service/JdCloudSmsImpl.java index 5a7c94e0..54f0d846 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/service/JdCloudSmsImpl.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/jdcloud/service/JdCloudSmsImpl.java @@ -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 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 messages, CallBack callBack) { - CompletableFuture smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, templateId, messages), pool); - smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack); - } - - @Override - @Restricted - public void sendMessageAsync(String phone, String templateId, LinkedHashMap 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 messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - sendMessage(phone, templateId, messages); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String message, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones, message); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String templateId, LinkedHashMap messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones, templateId, messages); - } - }, delayedTime); - } - /** * 获取短信返回信息 * diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/provider/base/BaseProviderFactory.java b/sms4j-provider/src/main/java/org/dromara/sms4j/provider/base/BaseProviderFactory.java new file mode 100644 index 00000000..42dd2508 --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/provider/base/BaseProviderFactory.java @@ -0,0 +1,40 @@ +package org.dromara.sms4j.provider.base; + +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.universal.SupplierConfig; + +/** + * AlibabaSmsConfig + *

短信对象建造者

+ * @param 短信对象 + * @param 短信配置对象 + */ +public interface BaseProviderFactory { + + /** + * 创建短信实现对象 + * @param c 短信配置对象 + * @return 短信实现对象 + */ + S createSms(C c); + + /** + * 刷新短信实现对象 + * @param c 短信配置对象 + * @return 刷新后的短信实现对象 + */ + S refresh(C c); + + /** + * 获取配置 + * @return 配置对象 + */ + C getConfig(); + + /** + * 设置配置 + * @param config 配置对象 + */ + void setConfig(C config); + +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/provider/enumerate/SupplierType.java b/sms4j-provider/src/main/java/org/dromara/sms4j/provider/enumerate/SupplierType.java new file mode 100644 index 00000000..9725047c --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/provider/enumerate/SupplierType.java @@ -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 + *

短信供应商枚举 + * @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 providerFactory; + + + SupplierType(String name, BaseProviderFactory providerFactory) { + this.name = name; + this.providerFactory = providerFactory; + } + + public String getName() { + return name; + } + + public BaseProviderFactory getProviderFactory() { + return providerFactory; + } +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/config/TencentConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/config/TencentConfig.java index 7143ab75..0f1ccef5 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/config/TencentConfig.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/config/TencentConfig.java @@ -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 diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/config/TencentFactory.java b/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/config/TencentFactory.java new file mode 100644 index 00000000..0b9571fe --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/config/TencentFactory.java @@ -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 + *

建造腾讯云短信 + * + * @author :Wind + * 2023/4/8 16:05 + **/ +public class TencentFactory implements BaseProviderFactory { + + 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; + } + +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/config/TencentSmsConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/config/TencentSmsConfig.java deleted file mode 100644 index dee0cc4f..00000000 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/config/TencentSmsConfig.java +++ /dev/null @@ -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 - *

建造腾讯云短信 - * - * @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; - } -} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/service/TencentSmsImpl.java b/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/service/TencentSmsImpl.java index 3caeeafd..d986b1be 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/service/TencentSmsImpl.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/service/TencentSmsImpl.java @@ -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 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 messages, CallBack callBack) { - CompletableFuture smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, templateId, messages), pool); - smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack); - } - - @Override - @Restricted - public void sendMessageAsync(String phone, String templateId, LinkedHashMap 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 messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - sendMessage(phone, templateId, messages); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String message, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones, message); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String templateId, LinkedHashMap messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones, templateId, messages); - } - }, delayedTime); - } - - private String[] arrayToString(List list) { - String[] strs = new String[list.size()]; - List toStr = new ArrayList<>(); - for (String s : list) { - toStr.add("+86" + s); - } - return toStr.toArray(strs); - } -} +} \ No newline at end of file diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/utils/TencentUtils.java b/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/utils/TencentUtils.java index 9742a5e4..8abbdb04 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/utils/TencentUtils.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/tencent/utils/TencentUtils.java @@ -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 params = new HashMap<>(); - // 实际调用需要更新参数,这里仅作为演示签名验证通过的例子 + Map 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; } /** diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/config/UniConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/config/UniConfig.java index 67ca0395..791296ce 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/config/UniConfig.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/config/UniConfig.java @@ -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 { /** * 是否为简易模式 diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/config/UniSmsConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/config/UniFactory.java similarity index 53% rename from sms4j-provider/src/main/java/org/dromara/sms4j/unisms/config/UniSmsConfig.java rename to sms4j-provider/src/main/java/org/dromara/sms4j/unisms/config/UniFactory.java index 977605e3..17f3f5f3 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/config/UniSmsConfig.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/config/UniFactory.java @@ -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 { 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 { *

建造一个短信实现对像 * @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 { *

刷新对象 * @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; + } + } diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/core/UniClient.java b/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/core/UniClient.java index 7306ea7a..b4c1522f 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/core/UniClient.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/core/UniClient.java @@ -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 *

向 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 { diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/core/UniResponse.java b/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/core/UniResponse.java index 6ea1bba8..fd80e3b5 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/core/UniResponse.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/core/UniResponse.java @@ -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"); } } diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/service/UniSmsImpl.java b/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/service/UniSmsImpl.java index b17f4b2e..bf562b93 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/service/UniSmsImpl.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/unisms/service/UniSmsImpl.java @@ -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 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 messages, CallBack callBack) { - CompletableFuture smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, templateId, messages), pool); - smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack); - } - - @Override - public void sendMessageAsync(String phone, String templateId, LinkedHashMap 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 messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - sendMessage(phone,templateId,messages); - } - },delayedTime); - } - - @Override - public void delayMassTexting(List phones, String message, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones,message); - } - },delayedTime); - } - - @Override - public void delayMassTexting(List phones, String templateId, LinkedHashMap messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones,templateId,messages); - } - },delayedTime); - } - private SmsResponse getSmsResponse( Map data) { SmsResponse smsResponse = new SmsResponse(); try { diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/config/YunPianFactory.java b/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/config/YunPianFactory.java new file mode 100644 index 00000000..975994f0 --- /dev/null +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/config/YunPianFactory.java @@ -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 { + + 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; + } + +} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/config/YunPianSmsConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/config/YunPianSmsConfig.java deleted file mode 100644 index 0d9973ee..00000000 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/config/YunPianSmsConfig.java +++ /dev/null @@ -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(); - } -} diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/config/YunpianConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/config/YunpianConfig.java index d08dd964..a09ae1dc 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/config/YunpianConfig.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/config/YunpianConfig.java @@ -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; - /** * 模板变量名称 */ diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/service/YunPianSmsImpl.java b/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/service/YunPianSmsImpl.java index 77aba422..1b6536a6 100644 --- a/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/service/YunPianSmsImpl.java +++ b/sms4j-provider/src/main/java/org/dromara/sms4j/yunpian/service/YunPianSmsImpl.java @@ -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 messages) { - Map body = setBody(phone, "", messages,templateId); + Map 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 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 messages, CallBack callBack) { - CompletableFuture smsResponseCompletableFuture = CompletableFuture.supplyAsync(() -> sendMessage(phone, templateId, messages), pool); - smsResponseCompletableFuture.thenAcceptAsync(callBack::callBack); - } - - @Override - @Restricted - public void sendMessageAsync(String phone, String templateId, LinkedHashMap 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 messages, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - sendMessage(phone, templateId, messages); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String message, Long delayedTime) { - this.delayed.schedule(new TimerTask() { - @Override - public void run() { - massTexting(phones, message); - } - }, delayedTime); - } - - @Override - @Restricted - public void delayMassTexting(List phones, String templateId, LinkedHashMap 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 messages) { @@ -165,11 +99,12 @@ public class YunPianSmsImpl implements SmsBlend { message.put(config.getTemplateName(), mes); } Map 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 body) { Map headers = getHeaders(); - AtomicReference smsResponse = null; + AtomicReference smsResponse = new AtomicReference<>(); http.post(Constant.YUNPIAN_URL + "/sms/tpl_single_send.json") .addHeader(headers) .addBody(body) diff --git a/sms4j-solon-plugin/pom.xml b/sms4j-solon-plugin/pom.xml new file mode 100644 index 00000000..75dc6f32 --- /dev/null +++ b/sms4j-solon-plugin/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + org.dromara.sms4j + sms4j + ${revision} + ../pom.xml + + + sms4j-solon-plugin + + sms4j-solon-plugin + sms4j-solon-plugin + + + + + org.noear + solon + ${solon.version} + + + + org.dromara.sms4j + sms4j-core + + + + org.redisson + redisson + ${redisson.version} + + + + org.noear + solon-test + ${solon.version} + test + + + diff --git a/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/XPluginImpl.java b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/XPluginImpl.java new file mode 100644 index 00000000..d30071fc --- /dev/null +++ b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/XPluginImpl.java @@ -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; + } +} diff --git a/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/aop/SolonRestrictedProcess.java b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/aop/SolonRestrictedProcess.java new file mode 100644 index 00000000..360051a3 --- /dev/null +++ b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/aop/SolonRestrictedProcess.java @@ -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; + } +} diff --git a/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SmsAutowiredConfig.java b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SmsAutowiredConfig.java new file mode 100644 index 00000000..bbb282a8 --- /dev/null +++ b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SmsAutowiredConfig.java @@ -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 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); + } + } +} diff --git a/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SupplierConfig.java b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SupplierConfig.java new file mode 100644 index 00000000..39ea927e --- /dev/null +++ b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SupplierConfig.java @@ -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 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()); + } +} diff --git a/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/utils/RedisUtils.java b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/utils/RedisUtils.java new file mode 100644 index 00000000..fd9e42c5 --- /dev/null +++ b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/utils/RedisUtils.java @@ -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; + } + } + + /** + *

说明:将Map中的数据批量放置到redis中 + *

+ * + * @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(); + } + + /** + *

说明:获取字符串型值 + * + * @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 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); +// } +// +// /** +// *

说明:将map对象存入redis +// *

+// * +// * @param map 要存入redis中的map +// * @name: setMap +// * @author :Wind +// */ +// public void MapSetMap(String key, Map map) { +// redisClient.getHash(key).putAll(map); +// } +// +// /** +// *

说明:获取所有hash表中字段 +// *

+// * +// * @param +// * @name: getMapByKey +// * @author :Wind +// */ +// public Set MapGetHashByKey(String key) { +// return redisTemplate.opsForHash().keys(key); +// } +// +// /** +// *

说明:根据key和fieId获取对应的值 +// *

+// * +// * @param fieId hash中的fieId也是Map的Key +// * @name: getValueByFieID +// * @author :Wind +// */ +// public Object MapGetValueByFieID(String key, String fieId) { +// return redisTemplate.opsForHash().get(key, fieId); +// } +// +// /** +// *

说明:根据key获取所有的键值对 +// *

+// * +// * @param key redis中的key +// * @name: getMapByKey +// * @author :Wind +// */ +// public Map MapGetMapByKey(String key) { +// return redisTemplate.opsForHash().entries(key); +// } +// +// /** +// *

说明:向key中添加一对新的键值对 +// *

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

说明:根据key和field删除数据 +// *

+// * +// * @param fields 要删除的fields +// * @return Long 影响的条数 +// * @name: hashDelete +// * @author :Wind +// */ +// public Long MapHashDelete(String key, Object... fields) { +// return redisTemplate.opsForHash().delete(key, fields); +// } +// +// /** +// *

说明:查看key下存了多少条键值对 +// *

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

说明:获取列表元素的大小 +// *

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

说明:清除所有缓存 +// *

该方法会清理掉redis中所有的缓存,谨慎使用 +// *

+// * +// * @name: empty +// * @author :Wind +// */ +// public void empty() { +// redisTemplate.getConnectionFactory().getConnection().flushAll(); +// } +} diff --git a/sms4j-solon-plugin/src/main/resources/META-INF/solon/sms4j-solon-plugin.properties b/sms4j-solon-plugin/src/main/resources/META-INF/solon/sms4j-solon-plugin.properties new file mode 100644 index 00000000..07519a28 --- /dev/null +++ b/sms4j-solon-plugin/src/main/resources/META-INF/solon/sms4j-solon-plugin.properties @@ -0,0 +1,4 @@ +#??????? +solon.plugin=org.dromara.sms4j.solon.XPluginImpl +#?????????????????0 +solon.plugin.priority=1 \ No newline at end of file diff --git a/sms4j-solon-plugin/src/test/java/org/dromara/sms4j/demo/App.java b/sms4j-solon-plugin/src/test/java/org/dromara/sms4j/demo/App.java new file mode 100644 index 00000000..3c5948bb --- /dev/null +++ b/sms4j-solon-plugin/src/test/java/org/dromara/sms4j/demo/App.java @@ -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); + } +} diff --git a/sms4j-solon-plugin/src/test/java/org/dromara/sms4j/demo/Config.java b/sms4j-solon-plugin/src/test/java/org/dromara/sms4j/demo/Config.java new file mode 100644 index 00000000..43e97bb4 --- /dev/null +++ b/sms4j-solon-plugin/src/test/java/org/dromara/sms4j/demo/Config.java @@ -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; + } +} diff --git a/sms4j-spring-boot-starter/src/test/java/org/dromara/sms4j/test/Sms4jTest.java b/sms4j-solon-plugin/src/test/java/org/dromara/sms4j/test/Sms4jTest.java similarity index 51% rename from sms4j-spring-boot-starter/src/test/java/org/dromara/sms4j/test/Sms4jTest.java rename to sms4j-solon-plugin/src/test/java/org/dromara/sms4j/test/Sms4jTest.java index 2f94474c..d4e056cc 100644 --- a/sms4j-spring-boot-starter/src/test/java/org/dromara/sms4j/test/Sms4jTest.java +++ b/sms4j-solon-plugin/src/test/java/org/dromara/sms4j/test/Sms4jTest.java @@ -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() } } diff --git a/sms4j-solon-plugin/src/test/resources/app.yml b/sms4j-solon-plugin/src/test/resources/app.yml new file mode 100644 index 00000000..e69de29b diff --git a/sms4j-spring-boot-example/pom.xml b/sms4j-spring-boot-example/pom.xml new file mode 100644 index 00000000..86e92f69 --- /dev/null +++ b/sms4j-spring-boot-example/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + + org.dromara.sms4j + sms4j + ${revision} + ../pom.xml + + + sms4j-spring-boot-example + + + true + true + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.dromara.sms4j + sms4j-spring-boot-starter + ${revision} + + + + \ No newline at end of file diff --git a/sms4j-spring-boot-example/src/main/java/org/dromara/sms4j/example/Sms4jApplication.java b/sms4j-spring-boot-example/src/main/java/org/dromara/sms4j/example/Sms4jApplication.java new file mode 100644 index 00000000..4946f8c5 --- /dev/null +++ b/sms4j-spring-boot-example/src/main/java/org/dromara/sms4j/example/Sms4jApplication.java @@ -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); + } + +} diff --git a/sms4j-spring-boot-example/src/main/resources/application.yml b/sms4j-spring-boot-example/src/main/resources/application.yml new file mode 100644 index 00000000..ccf437d1 --- /dev/null +++ b/sms4j-spring-boot-example/src/main/resources/application.yml @@ -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 diff --git a/sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/Sms4jTest.java b/sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/Sms4jTest.java new file mode 100644 index 00000000..fa0b9333 --- /dev/null +++ b/sms4j-spring-boot-example/src/test/java/org/dromara/sms4j/example/Sms4jTest.java @@ -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())); + } + +} diff --git a/sms4j-spring-boot-starter/pom.xml b/sms4j-spring-boot-starter/pom.xml index 678778fe..3cc53857 100644 --- a/sms4j-spring-boot-starter/pom.xml +++ b/sms4j-spring-boot-starter/pom.xml @@ -16,14 +16,6 @@ sms4j-spring-boot-starter - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - org.dromara.sms4j sms4j-autoimmit