update 短信失败重试

This commit is contained in:
bleachtred 2023-08-12 21:01:40 +08:00
parent 7011849d57
commit 79108f7d1d
21 changed files with 424 additions and 166 deletions

View File

@ -19,10 +19,5 @@
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-comm</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -25,5 +25,11 @@
<groupId>cn.hutool</groupId>
<artifactId>hutool-json</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -28,6 +28,8 @@ public abstract class Constant {
*/
public static final String FROM_URLENCODED = "application/x-www-form-urlencoded";
public static final String ACCEPT = "application/json";
public static final String APPLICATION_JSON_UTF8 = "application/json; charset=utf-8";
/**

View File

@ -0,0 +1,79 @@
package org.dromara.sms4j.comm.utils;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.dromara.sms4j.comm.exception.SmsBlendException;
import java.util.Map;
public class SmsHttpUtil {
private SmsHttpUtil() {
}
private static class SmsHttpHolder {
private static final SmsHttpUtil INSTANCE = new SmsHttpUtil();
}
public static SmsHttpUtil instance() {
return SmsHttpHolder.INSTANCE;
}
/**
* 发送post json请求
* @param url 请求地址
* @param headers 请求头
* @param body 请求体(json格式字符串)
* @return 返回体
*/
public JSONObject postJson(String url, Map<String, String> headers, String body){
try(HttpResponse response = HttpRequest.post(url)
.addHeaders(headers)
.body(body)
.execute()){
return JSONUtil.parseObj(response.body());
}catch (Exception e){
throw new SmsBlendException(e.getMessage());
}
}
/**
* 发送post json请求
* @param url 请求地址
* @param headers 请求头
* @param body 请求体(map格式请求体)
* @return 返回体
*/
public JSONObject postJson(String url, Map<String, String> headers, Map<String, Object> body){
return postJson(url, headers, JSONUtil.toJsonStr(body));
}
/**
* 发送post form 请求
* @param url 请求地址
* @param headers 请求头
* @param body 请求体(map格式请求体)
* @return 返回体
*/
public JSONObject postFrom(String url, Map<String, String> headers, Map<String, Object> body){
try(HttpResponse response = HttpRequest.post(url)
.addHeaders(headers)
.form(body)
.execute()){
return JSONUtil.parseObj(response.body());
}catch (Exception e){
throw new SmsBlendException(e.getMessage());
}
}
/**
* 线程睡眠
* @param retryInterval
*/
public void safeSleep(int retryInterval){
ThreadUtil.safeSleep(retryInterval * 1000L);
}
}

View File

@ -1,13 +1,12 @@
package org.dromara.sms4j.aliyun.service;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
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.entity.SmsResponse;
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;
@ -15,6 +14,7 @@ import org.dromara.sms4j.provider.service.AbstractSmsBlend;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
/**
@ -28,6 +28,7 @@ import java.util.concurrent.Executor;
public class AlibabaSmsImpl extends AbstractSmsBlend<AlibabaConfig> {
public static final String SUPPLIER = "alibaba";
private int retry = 0;
/**
* AlibabaSmsImpl
@ -89,15 +90,27 @@ public class AlibabaSmsImpl extends AbstractSmsBlend<AlibabaConfig> {
throw new SmsBlendException(e.getMessage());
}
log.debug("requestUrl {}", requestUrl);
try(HttpResponse response = HttpRequest.post(requestUrl)
.header("Content-Type", "application/x-www-form-urlencoded")
.body(paramStr)
.execute()){
JSONObject body = JSONUtil.parseObj(response.body());
return this.getResponse(body);
try {
Map<String, String> headers = new LinkedHashMap<>(1);
headers.put("Content-Type", Constant.FROM_URLENCODED);
SmsResponse smsResponse = getResponse(http.postJson(requestUrl, headers, paramStr));
if(smsResponse.isSuccess() || retry == getConfig().getMaxRetries()){
retry = 0;
return smsResponse;
}
return requestRetry(phone, message, templateId);
}catch (SmsBlendException e){
return requestRetry(phone, message, templateId);
}
}
private SmsResponse requestRetry(String phone, String message, String templateId) {
http.safeSleep(getConfig().getRetryInterval());
retry++;
log.warn("短信第 {" + retry + "} 次重新发送");
return getSmsResponse(phone, message, templateId);
}
private SmsResponse getResponse(JSONObject resJson) {
SmsResponse smsResponse = new SmsResponse();
smsResponse.setSuccess("OK".equals(resJson.getStr("Code")));

View File

@ -1,6 +1,5 @@
package org.dromara.sms4j.cloopen.service;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.entity.SmsResponse;
@ -51,15 +50,15 @@ public class CloopenSmsImpl extends AbstractSmsBlend<CloopenConfig> {
@Override
public SmsResponse massTexting(List<String> phones, String message) {
LinkedHashMap<String, String> map = new LinkedHashMap<>();
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put(IdUtil.fastSimpleUUID(), message);
return massTexting(phones, getConfig().getTemplateId(), map);
}
@Override
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
CloopenHelper helper = new CloopenHelper(getConfig());
Map<String, Object> paramMap = MapUtil.newHashMap(4);
CloopenHelper helper = new CloopenHelper(getConfig(), http);
Map<String, Object> paramMap = new LinkedHashMap<>(4);
paramMap.put("to", String.join(",", phones));
paramMap.put("appId", getConfig().getAppId());
paramMap.put("templateId", templateId);

View File

@ -4,14 +4,16 @@ import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.cloopen.config.CloopenConfig;
import org.dromara.sms4j.comm.constant.Constant;
import org.dromara.sms4j.comm.exception.SmsBlendException;
import org.dromara.sms4j.comm.utils.SmsHttpUtil;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
/**
@ -20,33 +22,48 @@ import java.util.Map;
* @author Charles7c
* @since 2023/4/17 20:57
*/
@Slf4j
public class CloopenHelper {
private final CloopenConfig config;
private final SmsHttpUtil http;
private int retry = 0;
public CloopenHelper(CloopenConfig config) {
public CloopenHelper(CloopenConfig config, SmsHttpUtil http) {
this.config = config;
this.http = http;
}
public SmsResponse smsResponse(Map<String, Object> paramMap){
String timestamp = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
try {
String timestamp = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
String url = String.format("%s/Accounts/%s/SMS/TemplateSMS?sig=%s",
config.getBaseUrl(),
config.getAccessKeyId(),
this.generateSign(config.getAccessKeyId(), config.getAccessKeySecret(), timestamp));
try(HttpResponse response = HttpRequest.post(url)
.header("Accept", "application/json")
.header("Content-Type", "application/json;charset=utf-8")
.header("Authorization", this.generateAuthorization(config.getAccessKeyId(), timestamp))
.body(JSONUtil.toJsonStr(paramMap))
.execute()){
JSONObject body = JSONUtil.parseObj(response.body());
return this.getResponse(body);
String url = String.format("%s/Accounts/%s/SMS/TemplateSMS?sig=%s",
config.getBaseUrl(),
config.getAccessKeyId(),
this.generateSign(config.getAccessKeyId(), config.getAccessKeySecret(), timestamp));
Map<String, String> headers = new LinkedHashMap<>(3);
headers.put("Accept", Constant.ACCEPT);
headers.put("Content-Type", Constant.APPLICATION_JSON_UTF8);
headers.put("Authorization", this.generateAuthorization(config.getAccessKeyId(), timestamp));
SmsResponse smsResponse = getResponse(http.postJson(url, headers, paramMap));
if(smsResponse.isSuccess() || retry == config.getMaxRetries()){
retry = 0;
return smsResponse;
}
return requestRetry(paramMap);
}catch (SmsBlendException e){
return requestRetry(paramMap);
}
}
private SmsResponse requestRetry(Map<String, Object> paramMap) {
http.safeSleep(config.getRetryInterval());
retry++;
log.warn("短信第 {" + retry + "} 次重新发送");
return smsResponse(paramMap);
}
private SmsResponse getResponse(JSONObject resJson) {
SmsResponse smsResponse = new SmsResponse();
smsResponse.setSuccess("000000".equals(resJson.getStr("statusCode")));

View File

@ -1,7 +1,5 @@
package org.dromara.sms4j.ctyun.service;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
@ -29,6 +27,8 @@ public class CtyunSmsImpl extends AbstractSmsBlend<CtyunConfig> {
public static final String SUPPLIER = "ctyun";
private int retry = 0;
public CtyunSmsImpl(CtyunConfig config, Executor pool, DelayedTime delayedTime) {
super(config, pool, delayedTime);
}
@ -44,7 +44,7 @@ public class CtyunSmsImpl extends AbstractSmsBlend<CtyunConfig> {
@Override
public SmsResponse sendMessage(String phone, String message) {
LinkedHashMap<String, String> map = new LinkedHashMap<>();
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put(getConfig().getTemplateName(), message);
return sendMessage(phone, getConfig().getTemplateId(), map);
}
@ -57,7 +57,7 @@ public class CtyunSmsImpl extends AbstractSmsBlend<CtyunConfig> {
@Override
public SmsResponse massTexting(List<String> phones, String message) {
LinkedHashMap<String, String> map = new LinkedHashMap<>();
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put(getConfig().getTemplateName(), message);
return massTexting(phones, getConfig().getTemplateId(), map);
}
@ -79,15 +79,27 @@ public class CtyunSmsImpl extends AbstractSmsBlend<CtyunConfig> {
throw new SmsBlendException(e.getMessage());
}
log.debug("requestUrl {}", requestUrl);
try(HttpResponse response = HttpRequest.post(requestUrl)
.addHeaders(CtyunUtils.signHeader(paramStr, getConfig().getAccessKeyId(), getConfig().getAccessKeySecret()))
.body(paramStr)
.execute()){
JSONObject body = JSONUtil.parseObj(response.body());
return this.getResponse(body);
try {
SmsResponse smsResponse = getResponse(http.postJson(requestUrl,
CtyunUtils.signHeader(paramStr, getConfig().getAccessKeyId(), getConfig().getAccessKeySecret()),
paramStr));
if(smsResponse.isSuccess() || retry == getConfig().getMaxRetries()){
retry = 0;
return smsResponse;
}
return requestRetry(phone, message, templateId);
}catch (SmsBlendException e){
return requestRetry(phone, message, templateId);
}
}
private SmsResponse requestRetry(String phone, String message, String templateId) {
http.safeSleep(getConfig().getRetryInterval());
retry ++;
log.warn("短信第 {" + retry + "} 次重新发送");
return getSmsResponse(phone, message, templateId);
}
private SmsResponse getResponse(JSONObject resJson) {
SmsResponse smsResponse = new SmsResponse();
smsResponse.setSuccess("OK".equals(resJson.getStr("code")));

View File

@ -6,6 +6,7 @@ import cn.hutool.crypto.digest.HmacAlgorithm;
import cn.hutool.json.JSONUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.dromara.sms4j.comm.constant.Constant;
import org.dromara.sms4j.comm.exception.SmsBlendException;
import org.dromara.sms4j.ctyun.config.CtyunConfig;
@ -35,7 +36,7 @@ public class CtyunUtils {
* 获取签名请求头
*/
public static Map<String, String> signHeader(String body, String key, String secret){
Map<String, String> map = new ConcurrentHashMap<>();
Map<String, String> map = new ConcurrentHashMap<>(4);
// 构造时间戳
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
@ -58,7 +59,7 @@ public class CtyunUtils {
// 构造签名
String signature = Base64.encode(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("Content-Type", Constant.APPLICATION_JSON_UTF8);
map.put("ctyun-eop-request-id", uuid);
map.put("Eop-date", signatureTime);
map.put("Eop-Authorization", signHeader);
@ -74,7 +75,7 @@ public class CtyunUtils {
* @param templateId 模板id
*/
public static String generateParamJsonStr(CtyunConfig ctyunConfig, String phone, String message, String templateId) {
Map<String, String> paramMap = new HashMap<>();
Map<String, String> paramMap = new HashMap<>(5);
paramMap.put("action", ctyunConfig.getAction());
paramMap.put("phoneNumber", phone);
paramMap.put("signName", ctyunConfig.getSignature());

View File

@ -1,11 +1,9 @@
package org.dromara.sms4j.emay.service;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.entity.SmsResponse;
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;
@ -27,6 +25,7 @@ import java.util.concurrent.Executor;
public class EmaySmsImpl extends AbstractSmsBlend<EmayConfig> {
public static final String SUPPLIER = "emay";
private int retry = 0;
public EmaySmsImpl(EmayConfig config, Executor pool, DelayedTime delayed) {
super(config, pool, delayed);
@ -44,17 +43,29 @@ public class EmaySmsImpl extends AbstractSmsBlend<EmayConfig> {
@Override
public SmsResponse sendMessage(String phone, String message) {
String url = getConfig().getRequestUrl();
Map<String, Object> params;
Map<String, Object> params = EmayBuilder.buildRequestBody(getConfig().getAccessKeyId(), getConfig().getAccessKeySecret(), phone, message);
try {
params = EmayBuilder.buildRequestBody(getConfig().getAccessKeyId(), getConfig().getAccessKeySecret(), phone, message);
} catch (SmsBlendException e) {
SmsResponse smsResponse = new SmsResponse();
smsResponse.setSuccess(false);
return smsResponse;
Map<String, String> headers = new LinkedHashMap<>(1);
headers.put("Content-Type", Constant.FROM_URLENCODED);
SmsResponse smsResponse = getResponse(http.postJson(url, headers, params));
if(smsResponse.isSuccess() || retry == getConfig().getMaxRetries()){
retry = 0;
return smsResponse;
}
return requestRetry(phone, message);
}catch (SmsBlendException e){
return requestRetry(phone, message);
}
return getSendResponse(params, url);
}
private SmsResponse requestRetry(String phone, String message) {
http.safeSleep(getConfig().getRetryInterval());
retry++;
log.warn("短信第 {" + retry + "} 次重新发送");
return sendMessage(phone, message);
}
@Override
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
List<String> list = new ArrayList<>();
@ -84,16 +95,6 @@ public class EmaySmsImpl extends AbstractSmsBlend<EmayConfig> {
return sendMessage(SmsUtil.listToString(phones), EmayBuilder.listToString(list));
}
private SmsResponse getSendResponse(Map<String, Object> body, String requestUrl) {
try(HttpResponse response = HttpRequest.post(requestUrl)
.header("Content-Type", "application/x-www-form-urlencoded")
.body(JSONUtil.toJsonStr(body))
.execute()){
JSONObject res = JSONUtil.parseObj(response.body());
return this.getResponse(res);
}
}
private SmsResponse getResponse(JSONObject resJson) {
SmsResponse smsResponse = new SmsResponse();
smsResponse.setSuccess("success".equalsIgnoreCase(resJson.getStr("code")));

View File

@ -1,13 +1,11 @@
package org.dromara.sms4j.huawei.service;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.entity.SmsResponse;
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.huawei.config.HuaweiConfig;
import org.dromara.sms4j.huawei.utils.HuaweiBuilder;
import org.dromara.sms4j.provider.service.AbstractSmsBlend;
@ -21,6 +19,7 @@ import static org.dromara.sms4j.huawei.utils.HuaweiBuilder.listToString;
public class HuaweiSmsImpl extends AbstractSmsBlend<HuaweiConfig> {
public static final String SUPPLIER = "huawei";
private int retry = 0;
public HuaweiSmsImpl(HuaweiConfig config, Executor pool, DelayedTime delayed) {
super(config, pool, delayed);
@ -51,19 +50,29 @@ public class HuaweiSmsImpl extends AbstractSmsBlend<HuaweiConfig> {
}
String mess = listToString(list);
String requestBody = HuaweiBuilder.buildRequestBody(getConfig().getSender(), phone, templateId, mess, getConfig().getStatusCallBack(), getConfig().getSignature());
Map<String, String> headers = new LinkedHashMap<>();
headers.put("Authorization", Constant.HUAWEI_AUTH_HEADER_VALUE);
headers.put("X-WSSE", HuaweiBuilder.buildWsseHeader(getConfig().getAccessKeyId(), getConfig().getAccessKeySecret()));
headers.put("Content-Type", Constant.FROM_URLENCODED);
try(HttpResponse response = HttpRequest.post(url)
.addHeaders(headers)
.body(requestBody)
.execute()){
JSONObject body = JSONUtil.parseObj(response.body());
return this.getResponse(body);
try {
Map<String, String> headers = new LinkedHashMap<>(3);
headers.put("Authorization", Constant.HUAWEI_AUTH_HEADER_VALUE);
headers.put("X-WSSE", HuaweiBuilder.buildWsseHeader(getConfig().getAccessKeyId(), getConfig().getAccessKeySecret()));
headers.put("Content-Type", Constant.FROM_URLENCODED);
SmsResponse smsResponse = getResponse(http.postJson(url, headers, requestBody));
if(smsResponse.isSuccess() || retry == getConfig().getMaxRetries()){
retry = 0;
return smsResponse;
}
return requestRetry(phone, templateId, messages);
}catch (SmsBlendException e){
return requestRetry(phone, templateId, messages);
}
}
private SmsResponse requestRetry(String phone, String templateId, LinkedHashMap<String, String> messages) {
http.safeSleep(getConfig().getRetryInterval());
retry++;
log.warn("短信第 {" + retry + "} 次重新发送");
return sendMessage(phone, templateId, messages);
}
@Override
public SmsResponse massTexting(List<String> phones, String message) {
return sendMessage(listToString(phones), message);

View File

@ -2,13 +2,11 @@ package org.dromara.sms4j.netease.service;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.entity.SmsResponse;
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.netease.config.NeteaseConfig;
@ -29,6 +27,7 @@ import java.util.concurrent.Executor;
public class NeteaseSmsImpl extends AbstractSmsBlend<NeteaseConfig> {
public static final String SUPPLIER = "netease";
private int retry = 0;
public NeteaseSmsImpl(NeteaseConfig config, Executor pool, DelayedTime delayed) {
super(config, pool, delayed);
@ -98,24 +97,37 @@ public class NeteaseSmsImpl extends AbstractSmsBlend<NeteaseConfig> {
String checkSum = NeteaseUtils.getCheckSum(getConfig().getAccessKeySecret(), nonce, curTime);
Map<String, Object> body = new LinkedHashMap<>(4);
body.put("templateid", templateId);
JSONArray jsonArray = JSONUtil.createArray();
JSONArray jsonArray = new JSONArray();
jsonArray.addAll(phones);
body.put("mobiles", jsonArray.toString());
body.put("params", message);
body.put("needUp", getConfig().getNeedUp());
try(HttpResponse response = HttpRequest.post(requestUrl)
.header("Content-Type", "application/x-www-form-urlencoded")
.header("AppKey", getConfig().getAccessKeyId())
.header("Nonce", nonce)
.header("CurTime", curTime)
.header("CheckSum", checkSum)
.body(JSONUtil.toJsonStr(body))
.execute()){
JSONObject res = JSONUtil.parseObj(response.body());
return this.getResponse(res);
try {
Map<String, String> headers = new LinkedHashMap<>(5);
headers.put("Content-Type", Constant.FROM_URLENCODED);
headers.put("AppKey", getConfig().getAccessKeyId());
headers.put("Nonce", nonce);
headers.put("CurTime", curTime);
headers.put("CheckSum", checkSum);
SmsResponse smsResponse = getResponse(http.postJson(requestUrl, headers, body));
if(smsResponse.isSuccess() || retry == getConfig().getMaxRetries()){
retry = 0;
return smsResponse;
}
return requestRetry(requestUrl, phones, message, templateId);
}catch (SmsBlendException e){
return requestRetry(requestUrl, phones, message, templateId);
}
}
private SmsResponse requestRetry(String requestUrl, List<String> phones, String message, String templateId) {
http.safeSleep(getConfig().getRetryInterval());
retry++;
log.warn("短信第 {" + retry + "} 次重新发送");
return getSmsResponse(requestUrl, phones, message, templateId);
}
private SmsResponse getResponse(JSONObject jsonObject) {
SmsResponse smsResponse = new SmsResponse();
smsResponse.setSuccess(jsonObject.getInt("code") <= 200);

View File

@ -1,10 +1,8 @@
package org.dromara.sms4j.provider.config;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.dromara.sms4j.api.universal.SupplierConfig;
import org.dromara.sms4j.comm.exception.SmsBlendException;
/**
* 短信配置属性基类
@ -48,4 +46,27 @@ public abstract class BaseConfig implements SupplierConfig {
*/
private String configId;
/**
* 重试间隔单位默认为5秒
*/
private int retryInterval = 5;
public void setRetryInterval(int retryInterval) {
if (retryInterval <= 0){
throw new SmsBlendException("重试间隔必须大于0秒");
}
this.retryInterval = retryInterval;
}
/**
* 重试次数默认为0次
*/
private int maxRetries = 0;
public void setMaxRetries(int maxRetries) {
if (maxRetries < 0){
throw new SmsBlendException("重试次数不能小于0次");
}
this.maxRetries = maxRetries;
}
}

View File

@ -8,6 +8,7 @@ import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.api.universal.SupplierConfig;
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
import org.dromara.sms4j.comm.factory.BeanFactory;
import org.dromara.sms4j.comm.utils.SmsHttpUtil;
import java.util.LinkedHashMap;
import java.util.List;
@ -26,6 +27,8 @@ public abstract class AbstractSmsBlend<C extends SupplierConfig> implements SmsB
protected final DelayedTime delayed;
protected final SmsHttpUtil http = SmsHttpUtil.instance();
protected AbstractSmsBlend(C config, Executor pool, DelayedTime delayed) {
this.configId = StrUtil.isEmpty(config.getConfigId()) ? getSupplier() : config.getConfigId();
this.config = config;

View File

@ -1,9 +1,6 @@
package org.dromara.sms4j.tencent.service;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jdcloud.sdk.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.entity.SmsResponse;
@ -28,6 +25,7 @@ import java.util.concurrent.Executor;
public class TencentSmsImpl extends AbstractSmsBlend<TencentConfig> {
public static final String SUPPLIER = "alibaba";
private int retry = 0;
public TencentSmsImpl(TencentConfig tencentSmsConfig, Executor pool, DelayedTime delayed) {
super(tencentSmsConfig, pool, delayed);
@ -96,15 +94,26 @@ public class TencentSmsImpl extends AbstractSmsBlend<TencentConfig> {
Map<String, Object> requestBody = TencentUtils.generateRequestBody(phones, getConfig().getSdkAppId(),
getConfig().getSignature(), templateId, messages);
String url = Constant.HTTPS_PREFIX + getConfig().getRequestUrl();
try(HttpResponse response = HttpRequest.post(url)
.addHeaders(headsMap)
.body(JSONUtil.toJsonStr(requestBody))
.execute()){
JSONObject body = JSONUtil.parseObj(response.body());
return this.getResponse(body);
try {
SmsResponse smsResponse = getResponse(http.postJson(url, headsMap, requestBody));
if(smsResponse.isSuccess() || retry == getConfig().getMaxRetries()){
retry = 0;
return smsResponse;
}
return requestRetry(phones, messages, templateId);
}catch (SmsBlendException e){
return requestRetry(phones, messages, templateId);
}
}
private SmsResponse requestRetry(String[] phones, String[] messages, String templateId) {
http.safeSleep(getConfig().getRetryInterval());
retry++;
log.warn("短信第 {" + retry + "} 次重新发送");
return getSmsResponse(phones, messages, templateId);
}
private SmsResponse getResponse(JSONObject resJson) {
SmsResponse smsResponse = new SmsResponse();
JSONObject response = resJson.getJSONObject("Response");

View File

@ -61,11 +61,11 @@ public class Uni {
* @return the Uni Client
* @author :Wind
*/
public static UniClient getClient() {
public static UniClient getClient(int retryInterval, int maxRetries) {
if (Uni.client == null) {
synchronized (Uni.class) {
if (Uni.client == null) {
Uni.client = buildClient();
Uni.client = buildClient(retryInterval, maxRetries);
}
}
}
@ -78,7 +78,7 @@ public class Uni {
}
}
private static UniClient buildClient() {
private static UniClient buildClient(int retryInterval, int maxRetries) {
UniClient.Builder builder = new UniClient.Builder(Uni.accessKeyId);
if (Uni.accessKeySecret != null) {
@ -87,7 +87,8 @@ public class Uni {
builder.endpoint(Uni.endpoint);
builder.signingAlgorithm(Uni.signingAlgorithm);
builder.setRetryInterval(retryInterval);
builder.setMaxRetries(maxRetries);
return builder.build();
}
}

View File

@ -3,10 +3,10 @@ package org.dromara.sms4j.unisms.core;
import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.digest.HMac;
import cn.hutool.crypto.digest.HmacAlgorithm;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.comm.constant.Constant;
import org.dromara.sms4j.comm.exception.SmsBlendException;
import org.dromara.sms4j.comm.utils.SmsHttpUtil;
import java.util.Comparator;
import java.util.Date;
@ -17,6 +17,7 @@ import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.UUID;
@Slf4j
public class UniClient {
public static final String USER_AGENT = "uni-java-sdk" + "/" + Uni.VERSION;
@ -24,12 +25,18 @@ public class UniClient {
private final String accessKeySecret;
private final String endpoint;
private final String signingAlgorithm;
private final int retryInterval;
private final int maxRetries;
private int retry = 0;
private final SmsHttpUtil http = SmsHttpUtil.instance();
protected UniClient(Builder b) {
this.accessKeyId = b.accessKeyId;
this.accessKeySecret = b.accessKeySecret;
this.endpoint = b.endpoint;
this.signingAlgorithm = b.signingAlgorithm;
this.retryInterval = b.retryInterval;
this.maxRetries = b.maxRetries;
}
private static String getSignature(final String message, final String secretKey) {
@ -81,23 +88,37 @@ public class UniClient {
public UniResponse request(final String action, final Map<String, Object> data) throws SmsBlendException {
Map<String, String> headers = new HashMap<>();
headers.put("User-Agent", USER_AGENT);
headers.put("Content-Type", "application/json;charset=utf-8");
headers.put("Accept", "application/json");
headers.put("Content-Type", Constant.APPLICATION_JSON_UTF8);
headers.put("Accept", Constant.ACCEPT);
String url = this.endpoint + "?action=" + action + "&accessKeyId=" + this.accessKeyId;
try(HttpResponse response = HttpRequest.post(url)
.addHeaders(headers)
.body(JSONUtil.toJsonStr(data))
.execute()){
return new UniResponse(JSONUtil.parseObj(response.body()));
try {
UniResponse smsResponse = new UniResponse(http.postJson(url, headers, data));
if("Success".equals(smsResponse.message) || retry == maxRetries){
retry = 0;
return smsResponse;
}
return requestRetry(action, data);
}catch (SmsBlendException e){
return requestRetry(action, data);
}
}
private UniResponse requestRetry(String action, Map<String, Object> data) {
http.safeSleep(retryInterval);
retry++;
log.warn("短信第 {" + retry + "} 次重新发送");
return request(action, data);
}
public static class Builder {
private String accessKeyId;
private String accessKeySecret;
private String endpoint;
private String signingAlgorithm;
private int retryInterval;
private int maxRetries;
public Builder(final String accessKeyId) {
this.accessKeyId = accessKeyId;
@ -123,6 +144,16 @@ public class UniClient {
return this;
}
public Builder setRetryInterval(int retryInterval) {
this.retryInterval = retryInterval;
return this;
}
public Builder setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
return this;
}
public UniClient build() {
return new UniClient(this);
}

View File

@ -27,7 +27,7 @@ public class UniResponse {
this.raw = body;
this.data = body;
}
if (this.status != "400") {
if (!"400".equals(this.status)) {
String code = response.getStr("code");
if (!"0".equals(code)) {
this.message = response.getStr("message");

View File

@ -42,14 +42,14 @@ public class UniSmsImpl extends AbstractSmsBlend<UniConfig> {
if ("".equals(getConfig().getTemplateId()) && "".equals(getConfig().getTemplateName())) {
throw new SmsBlendException("配置文件模板id和模板变量不能为空");
}
LinkedHashMap<String, String> map = new LinkedHashMap<>();
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put(getConfig().getTemplateName(), message);
return sendMessage(phone, getConfig().getTemplateId(), map);
}
@Override
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
Map<String, Object> data = new HashMap<>();
Map<String, Object> data = new LinkedHashMap<>(4);
data.put("to", Collections.singletonList(phone));
data.put("signature", getConfig().getSignature());
data.put("templateId", templateId);
@ -62,7 +62,7 @@ public class UniSmsImpl extends AbstractSmsBlend<UniConfig> {
if ("".equals(getConfig().getTemplateId()) && "".equals(getConfig().getTemplateName())) {
throw new SmsBlendException("配置文件模板id和模板变量不能为空");
}
LinkedHashMap<String, String> map = new LinkedHashMap<>();
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put(getConfig().getTemplateName(), message);
return massTexting(phones, getConfig().getTemplateId(), map);
}
@ -72,7 +72,7 @@ public class UniSmsImpl extends AbstractSmsBlend<UniConfig> {
if (phones.size() > 1000) {
throw new SmsBlendException("单次发送超过最大发送上限建议每次群发短信人数低于1000");
}
Map<String, Object> data = new HashMap<>();
Map<String, Object> data = new LinkedHashMap<>(4);
data.put("to", phones);
data.put("signature", getConfig().getSignature());
data.put("templateId", templateId);
@ -83,7 +83,7 @@ public class UniSmsImpl extends AbstractSmsBlend<UniConfig> {
private SmsResponse getSmsResponse(Map<String, Object> data) {
SmsResponse smsResponse = new SmsResponse();
try {
UniResponse send = Uni.getClient().request("sms.message.send", data);
UniResponse send = Uni.getClient(getConfig().getRetryInterval(), getConfig().getMaxRetries()).request("sms.message.send", data);
smsResponse.setSuccess("Success".equals(send.message));
smsResponse.setData(send);
smsResponse.setConfigId(getConfigId());

View File

@ -1,9 +1,7 @@
package org.dromara.sms4j.yunpian.service;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.comm.constant.Constant;
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
@ -21,9 +19,11 @@ import java.util.concurrent.Executor;
/**
* @author wind
*/
@Slf4j
public class YunPianSmsImpl extends AbstractSmsBlend<YunpianConfig> {
public static final String SUPPLIER = "yunpian";
private int retry = 0;
public YunPianSmsImpl(YunpianConfig config, Executor pool, DelayedTime delayed) {
super(config, pool, delayed);
@ -52,14 +52,50 @@ public class YunPianSmsImpl extends AbstractSmsBlend<YunpianConfig> {
@Override
public SmsResponse sendMessage(String phone, String message) {
Map<String, String> body = setBody(phone, message, null, getConfig().getTemplateId());
return getSendResponse(body);
Map<String, Object> body = setBody(phone, message, null, getConfig().getTemplateId());
Map<String, String> headers = getHeaders();
try {
SmsResponse smsResponse = getResponse(http.postJson(Constant.YUNPIAN_URL + "/sms/tpl_single_send.json", headers, body));
if(smsResponse.isSuccess() || retry == getConfig().getMaxRetries()){
retry = 0;
return smsResponse;
}
return requestRetry(phone, message);
}catch (SmsBlendException e){
return requestRetry(phone, message);
}
}
private SmsResponse requestRetry(String phone, String message) {
http.safeSleep(getConfig().getRetryInterval());
retry++;
log.warn("短信第 {" + retry + "} 次重新发送");
return sendMessage(phone, message);
}
@Override
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
Map<String, String> body = setBody(phone, "", messages, templateId);
return getSendResponse(body);
Map<String, Object> body = setBody(phone, "", messages, templateId);
Map<String, String> headers = getHeaders();
try {
SmsResponse smsResponse = getResponse(http.postJson(Constant.YUNPIAN_URL + "/sms/tpl_single_send.json", headers, body));
if(smsResponse.isSuccess() || retry == getConfig().getMaxRetries()){
retry = 0;
return smsResponse;
}
return requestRetry(phone, templateId, messages);
}catch (SmsBlendException e){
return requestRetry(phone, templateId, messages);
}
}
private SmsResponse requestRetry(String phone, String templateId, LinkedHashMap<String, String> messages) {
http.safeSleep(getConfig().getRetryInterval());
retry++;
log.warn("短信第 {" + retry + "} 次重新发送");
return sendMessage(phone, templateId, messages);
}
@Override
@ -91,14 +127,14 @@ public class YunPianSmsImpl extends AbstractSmsBlend<YunpianConfig> {
return str.toString();
}
private Map<String, String> setBody(String phone, String mes, LinkedHashMap<String, String> messages, String tplId) {
private Map<String, Object> setBody(String phone, String mes, LinkedHashMap<String, String> messages, String tplId) {
LinkedHashMap<String, String> message = new LinkedHashMap<>();
if (mes.isEmpty()) {
message = messages;
} else {
message.put(getConfig().getTemplateName(), mes);
}
Map<String, String> body = new HashMap<>();
Map<String, Object> body = new HashMap<>();
body.put("apikey", getConfig().getAccessKeyId());
body.put("mobile", phone);
body.put("tpl_id", tplId);
@ -110,19 +146,8 @@ public class YunPianSmsImpl extends AbstractSmsBlend<YunpianConfig> {
private Map<String, String> getHeaders() {
Map<String, String> headers = new HashMap<>();
headers.put("Accept", "application/json;charset=utf-8");
headers.put("Accept", Constant.APPLICATION_JSON_UTF8);
headers.put("Content-Type", Constant.FROM_URLENCODED);
return headers;
}
private SmsResponse getSendResponse(Map<String, String> body) {
Map<String, String> headers = getHeaders();
try(HttpResponse response = HttpRequest.post(Constant.YUNPIAN_URL + "/sms/tpl_single_send.json")
.addHeaders(headers)
.body(JSONUtil.toJsonStr(body))
.execute()){
JSONObject res = JSONUtil.parseObj(response.body());
return getResponse(res);
}
}
}

View File

@ -5,11 +5,8 @@ import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.comm.constant.Constant;
@ -33,6 +30,7 @@ import java.util.concurrent.Executor;
public class ZhutongSmsImpl extends AbstractSmsBlend<ZhutongConfig> {
public static final String SUPPLIER = "zhutong";
private int retry = 0;
/**
* ZhutongSmsImpl
@ -63,7 +61,7 @@ public class ZhutongSmsImpl extends AbstractSmsBlend<ZhutongConfig> {
return getSmsResponse(phone, message);
}
LinkedHashMap<String, String> map = new LinkedHashMap<>();
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put(config.getTemplateName(), message);
return sendMessage(phone, config.getTemplateId(), map);
}
@ -81,7 +79,7 @@ public class ZhutongSmsImpl extends AbstractSmsBlend<ZhutongConfig> {
return getSmsResponse(phones, message);
}
LinkedHashMap<String, String> map = new LinkedHashMap<>();
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put(config.getTemplateName(), message);
return massTexting(phones, config.getTemplateId(), map);
}
@ -120,7 +118,7 @@ public class ZhutongSmsImpl extends AbstractSmsBlend<ZhutongConfig> {
String url = requestUrl + "v2/sendSms";
long tKey = System.currentTimeMillis() / 1000;
Map<String, String> json = new HashMap<>(5);
Map<String, Object> json = new HashMap<>(5);
//账号
json.put("username", username);
//密码
@ -132,15 +130,27 @@ public class ZhutongSmsImpl extends AbstractSmsBlend<ZhutongConfig> {
//内容
json.put("content", content);
try(HttpResponse response = HttpRequest.post(url)
.header("Content-Type", Constant.APPLICATION_JSON_UTF8)
.body(JSONUtil.toJsonStr(json))
.execute()){
JSONObject body = JSONUtil.parseObj(response.body());
return this.getResponse(body);
try {
Map<String, String> headers = new LinkedHashMap<>(1);
headers.put("Content-Type", Constant.APPLICATION_JSON_UTF8);
SmsResponse smsResponse = getResponse(http.postJson(requestUrl, headers, json));
if(smsResponse.isSuccess() || retry == getConfig().getMaxRetries()){
retry = 0;
return smsResponse;
}
return requestRetry(phones, content);
}catch (SmsBlendException e){
return requestRetry(phones, content);
}
}
private SmsResponse requestRetry(List<String> phones, String content) {
http.safeSleep(getConfig().getRetryInterval());
retry++;
log.warn("短信第 {" + retry + "} 次重新发送");
return getSmsResponse(phones, content);
}
protected SmsResponse getSmsResponse(String mobile, String content) {
return getSmsResponse(ListUtil.of(mobile), content);
}
@ -205,15 +215,27 @@ public class ZhutongSmsImpl extends AbstractSmsBlend<ZhutongConfig> {
}
requestJson.set("records", records);
try(HttpResponse response = HttpRequest.post(url)
.header("Content-Type", Constant.APPLICATION_JSON_UTF8)
.body(requestJson.toString())
.execute()){
JSONObject body = JSONUtil.parseObj(response.body());
return this.getResponse(body);
try {
Map<String, String> headers = new LinkedHashMap<>(1);
headers.put("Content-Type", Constant.APPLICATION_JSON_UTF8);
SmsResponse smsResponse = getResponse(http.postJson(requestUrl, headers, requestJson.toString()));
if(smsResponse.isSuccess() || retry == getConfig().getMaxRetries()){
retry = 0;
return smsResponse;
}
return requestRetry(templateId, phones, messages);
}catch (SmsBlendException e){
return requestRetry(templateId, phones, messages);
}
}
private SmsResponse requestRetry(String templateId, List<String> phones, LinkedHashMap<String, String> messages) {
http.safeSleep(getConfig().getRetryInterval());
retry++;
log.warn("短信第 {" + retry + "} 次重新发送");
return getSmsResponseTemplate(templateId, phones, messages);
}
protected SmsResponse getSmsResponseTemplate(String templateId, String mobile, LinkedHashMap<String, String> content) {
return getSmsResponseTemplate(templateId, ListUtil.of(mobile), content);
}