add 联通一信通平台短信通道

This commit is contained in:
moat 2024-07-31 11:45:13 +08:00
parent 8ec8cf8bd6
commit f0e018b855
10 changed files with 316 additions and 0 deletions

View File

@ -93,4 +93,8 @@ public abstract class SupplierConstant {
* danmi sms * danmi sms
*/ */
public static final String DAN_MI = "danmi"; public static final String DAN_MI = "danmi";
/**
* 联通一信通 sms
*/
public static final String YIXINTONG = "yixintong";
} }

View File

@ -51,6 +51,7 @@ import org.dromara.sms4j.qiniu.config.QiNiuFactory;
import org.dromara.sms4j.submail.config.SubMailFactory; import org.dromara.sms4j.submail.config.SubMailFactory;
import org.dromara.sms4j.tencent.config.TencentFactory; import org.dromara.sms4j.tencent.config.TencentFactory;
import org.dromara.sms4j.unisms.config.UniFactory; import org.dromara.sms4j.unisms.config.UniFactory;
import org.dromara.sms4j.yixintong.config.YiXintongFactory;
import org.dromara.sms4j.yunpian.config.YunPianFactory; import org.dromara.sms4j.yunpian.config.YunPianFactory;
import org.dromara.sms4j.zhutong.config.ZhutongFactory; import org.dromara.sms4j.zhutong.config.ZhutongFactory;
@ -269,6 +270,7 @@ public class SEInitializer {
ProviderFactoryHolder.registerFactory(LuoSiMaoFactory.instance()); ProviderFactoryHolder.registerFactory(LuoSiMaoFactory.instance());
ProviderFactoryHolder.registerFactory(SubMailFactory.instance()); ProviderFactoryHolder.registerFactory(SubMailFactory.instance());
ProviderFactoryHolder.registerFactory(DanMiFactory.instance()); ProviderFactoryHolder.registerFactory(DanMiFactory.instance());
ProviderFactoryHolder.registerFactory(YiXintongFactory.instance());
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) { if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance()); ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());
} }

View File

@ -0,0 +1,43 @@
package org.dromara.sms4j.yixintong.config;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.sms4j.comm.constant.SupplierConstant;
import org.dromara.sms4j.provider.config.BaseConfig;
/**
* <p>类名: YiXintongConfig
* <p>说明联通一信通平台配置类
* <p>所用到配置项spCodefaccessKeyId(用户名)accessKeySecret接口密钥templateIdretryIntervalmaxRetries
*
* @author moat
* @create 2024-07-30 16:50
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class YiXintongConfig extends BaseConfig {
/**
* 短信发送请求地址
*/
private String requestUrl = "https://api.ums86.com:9600/sms/Api/Send.do";
/**
* 企业编号
*/
private String spCode;
/**
* 提交时检测方式
* 1 --- 提交号码中有效的号码仍正常发出短信无效的号码在返回参数faillist中列出
*
* 不为1 或该参数不存在 --- 提交号码中只要有无效的号码那么所有的号码都不发出短信无效号码在返回参数faillist中列出
*/
private String f = "1";
@Override
public String getSupplier() {
return SupplierConstant.YIXINTONG;
}
}

View File

@ -0,0 +1,46 @@
package org.dromara.sms4j.yixintong.config;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.dromara.sms4j.comm.constant.SupplierConstant;
import org.dromara.sms4j.provider.factory.AbstractProviderFactory;
import org.dromara.sms4j.yixintong.service.YiXintongSmsImpl;
/**
* <p>类名: YiXintongFactory
* <p>说明联通一信通平台短信对象建造
*
* @author moat
* @create 2024-07-30 17:10
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class YiXintongFactory extends AbstractProviderFactory<YiXintongSmsImpl, YiXintongConfig> {
private static final YiXintongFactory INSTANCE = new YiXintongFactory();
/**
* 获取建造者实例
* @return 建造者实例
*/
public static YiXintongFactory instance() {
return INSTANCE;
}
/**
* createSms
* <p> 建造一个短信实现对像
*/
@Override
public YiXintongSmsImpl createSms(YiXintongConfig yiXintongConfig) {
return new YiXintongSmsImpl(yiXintongConfig);
}
/**
* 获取供应商
* @return 供应商
*/
@Override
public String getSupplier() {
return SupplierConstant.YIXINTONG;
}
}

View File

@ -0,0 +1,128 @@
package org.dromara.sms4j.yixintong.service;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.api.utils.SmsRespUtils;
import org.dromara.sms4j.comm.constant.SupplierConstant;
import org.dromara.sms4j.comm.delayedTime.DelayedTime;
import org.dromara.sms4j.comm.exception.SmsBlendException;
import org.dromara.sms4j.comm.utils.SmsUtils;
import org.dromara.sms4j.provider.service.AbstractSmsBlend;
import org.dromara.sms4j.yixintong.config.YiXintongConfig;
import org.dromara.sms4j.yixintong.utils.YiXintongUtils;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
/**
* <p>类名: YiXintongSmsImpl
* <p>说明联通一信通 sms
*
* @author moat
* @create 2024-07-30 16:59
*/
@Slf4j
public class YiXintongSmsImpl extends AbstractSmsBlend<YiXintongConfig> {
private int retry = 0;
public YiXintongSmsImpl(YiXintongConfig config, Executor pool, DelayedTime delayedTime) {
super(config, pool, delayedTime);
}
public YiXintongSmsImpl(YiXintongConfig config) {
super(config);
}
@Override
public String getSupplier() {
return SupplierConstant.YIXINTONG;
}
@Override
public SmsResponse sendMessage(String phone, String message) {
return getSmsResponse(phone, message, getConfig().getTemplateId());
}
@Override
public SmsResponse massTexting(List<String> phones, String message) {
return getSmsResponse(SmsUtils.joinComma(phones), message, getConfig().getTemplateId());
}
@Override
public SmsResponse sendMessage(String phone, LinkedHashMap<String, String> messages) {
throw new SmsBlendException("不支持此方法");
}
@Override
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
throw new SmsBlendException("不支持此方法");
}
@Override
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
throw new SmsBlendException("不支持此方法");
}
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
final YiXintongConfig config = getConfig();
if (StrUtil.isBlank(phone)){
log.error("phone is required.");
throw new SmsBlendException("phone is required.");
}
if (StrUtil.isBlank(message)){
log.error("message is required.");
throw new SmsBlendException("message is required.");
}
// 生成20位流水号
String serialNumber = SmsUtils.getRandomInt(20);
Map<String, Object> forms = new HashMap<>();
forms.put("SpCode", config.getSpCode());
forms.put("LoginName", config.getAccessKeyId());
forms.put("Password", config.getAccessKeySecret());
forms.put("MessageContent", message);
forms.put("UserNumber", phone);
forms.put("templateId", templateId);
forms.put("SerialNumber", serialNumber);
forms.put("ScheduleTime", ""); // 立即发送
forms.put("f", config.getF());
SmsResponse smsResponse;
try {
smsResponse = getResponse(YiXintongUtils.postForm(config.getRequestUrl(), forms));
} catch (SmsBlendException e) {
smsResponse = errorResp(e.message);
}
if (smsResponse.isSuccess() || retry == config.getMaxRetries()) {
retry = 0;
return smsResponse;
}
return requestRetry(phone, message, templateId);
}
private SmsResponse requestRetry(String phone, String message, String templateId) {
http.safeSleep(getConfig().getRetryInterval());
retry ++;
log.warn("The SMS has been resent for the {}th time.", retry);
return getSmsResponse(phone, message, templateId);
}
/**
* 构造统一短信返回信息
* @param body 原始响应信息
* @return 短信返回信息
*/
private SmsResponse getResponse(String body) {
return SmsRespUtils.resp(body, StrUtil.contains(body, "result=0&"), getConfigId());
}
}

View File

@ -0,0 +1,54 @@
package org.dromara.sms4j.yixintong.utils;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import org.dromara.sms4j.comm.exception.SmsBlendException;
import java.util.Map;
/**
* <p>类名: YiXintongUtils
* <p>说明联通一信通工具类
*
* @author moat
* @create 2024-07-31 9:55
*/
public class YiXintongUtils {
/**
* 发送post form请求
*
* @param url 请求地址
* @param forms 表单参数
* @return 返回体
*/
public static String postForm(String url, Map<String, Object> forms) {
return postForm(url, null, forms, "gbk");
}
/**
* 发送post form请求
*
* @param url 请求地址
* @param headers 请求头
* @param forms 表单参数
* @param charset 字符集编码
* @return 返回体
*/
public static String postForm(String url, Map<String, String> headers, Map<String, Object> forms, String charset) {
try (HttpResponse response = HttpRequest.post(url)
.addHeaders(headers)
.form(forms)
.charset(charset)
.execute()) {
return response.body();
} catch (Exception e) {
throw new SmsBlendException(e.getMessage());
}
}
}

View File

@ -41,6 +41,7 @@ import org.dromara.sms4j.solon.holder.SolonSmsDaoHolder;
import org.dromara.sms4j.submail.config.SubMailFactory; import org.dromara.sms4j.submail.config.SubMailFactory;
import org.dromara.sms4j.tencent.config.TencentFactory; import org.dromara.sms4j.tencent.config.TencentFactory;
import org.dromara.sms4j.unisms.config.UniFactory; import org.dromara.sms4j.unisms.config.UniFactory;
import org.dromara.sms4j.yixintong.config.YiXintongFactory;
import org.dromara.sms4j.yunpian.config.YunPianFactory; import org.dromara.sms4j.yunpian.config.YunPianFactory;
import org.dromara.sms4j.zhutong.config.ZhutongFactory; import org.dromara.sms4j.zhutong.config.ZhutongFactory;
import org.noear.solon.core.AppContext; import org.noear.solon.core.AppContext;
@ -137,6 +138,7 @@ public class SmsBlendsInitializer {
ProviderFactoryHolder.registerFactory(LuoSiMaoFactory.instance()); ProviderFactoryHolder.registerFactory(LuoSiMaoFactory.instance());
ProviderFactoryHolder.registerFactory(SubMailFactory.instance()); ProviderFactoryHolder.registerFactory(SubMailFactory.instance());
ProviderFactoryHolder.registerFactory(DanMiFactory.instance()); ProviderFactoryHolder.registerFactory(DanMiFactory.instance());
ProviderFactoryHolder.registerFactory(YiXintongFactory.instance());
if(SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) { if(SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance()); ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());
} }

View File

@ -155,6 +155,13 @@ sms:
accessKeyId: ACCOUNT SID accessKeyId: ACCOUNT SID
accessKeySecret: AUTH TOKEN accessKeySecret: AUTH TOKEN
action: 默认请求方法 distributor/sendSMS action: 默认请求方法 distributor/sendSMS
# 一信通
yixintong:
sp-code: xxxxxx #(必填)企业编号
access-key-id: xxxxxx #(必填)用户名
access-key-secret: 324gaxxxxxxxxxxxxxxxxx9sdf89 #(必填)接口密钥(正式帐户需要登陆平台,接口业务-接口申请右侧钥匙状图标查看或获取,接口密钥获取后十分钟生效)
template-id: #(可选)模板编号(若配置此参数,则会默认使用该模板,以便提高服务方性能)
f: 1 #(可选)默认为1提交时检测方式
sms-oa: sms-oa:
config-type: yaml config-type: yaml

View File

@ -1,5 +1,6 @@
package org.dromara.sms4j.example; package org.dromara.sms4j.example;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil; import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.UUID; import cn.hutool.core.lang.UUID;
@ -526,4 +527,31 @@ public class Sms4jTest {
Assert.isTrue(smsResponse5.isSuccess()); Assert.isTrue(smsResponse5.isSuccess());
} }
/**
* 联通一信通模板
*/
@Test
public void yixintongSmsTest() {
if (StrUtil.isBlank(PHONE)) {
return;
}
//短信发送模板你有一项编号为{xxxxxxxxx}的事务需要处理{x}
//其中的{xxxxxx}代表短信模板中的变量部分可变化一个x代表一个字或者字符{}为变量标识在发送时不用传实发变量字数小于等于x的个数
// 单发
String message1 = StrUtil.format("你有一项编号为{}的事务需要处理。", SmsUtils.getRandomInt(6));
SmsResponse smsResponse1 = SmsFactory.getBySupplier(SupplierConstant.YIXINTONG).sendMessage(PHONE, message1);
log.info(JSONUtil.toJsonStr(smsResponse1));
Assert.isTrue(smsResponse1.isSuccess());
// 群发
List<String> phones = CollectionUtil.toList("2222222222");
String message2 = StrUtil.format("你有一项编号为{}的事务需要处理。", SmsUtils.getRandomInt(6));
SmsResponse smsResponse2 = SmsFactory.getBySupplier(SupplierConstant.YIXINTONG).massTexting(phones, message2);
log.info(JSONUtil.toJsonStr(smsResponse2));
Assert.isTrue(smsResponse2.isSuccess());
}
} }

View File

@ -43,6 +43,7 @@ import org.dromara.sms4j.starter.adepter.ConfigCombineMapAdaptor;
import org.dromara.sms4j.submail.config.SubMailFactory; import org.dromara.sms4j.submail.config.SubMailFactory;
import org.dromara.sms4j.tencent.config.TencentFactory; import org.dromara.sms4j.tencent.config.TencentFactory;
import org.dromara.sms4j.unisms.config.UniFactory; import org.dromara.sms4j.unisms.config.UniFactory;
import org.dromara.sms4j.yixintong.config.YiXintongFactory;
import org.dromara.sms4j.yunpian.config.YunPianFactory; import org.dromara.sms4j.yunpian.config.YunPianFactory;
import org.dromara.sms4j.zhutong.config.ZhutongFactory; import org.dromara.sms4j.zhutong.config.ZhutongFactory;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
@ -152,6 +153,7 @@ public class SmsBlendsInitializer {
ProviderFactoryHolder.registerFactory(LuoSiMaoFactory.instance()); ProviderFactoryHolder.registerFactory(LuoSiMaoFactory.instance());
ProviderFactoryHolder.registerFactory(SubMailFactory.instance()); ProviderFactoryHolder.registerFactory(SubMailFactory.instance());
ProviderFactoryHolder.registerFactory(DanMiFactory.instance()); ProviderFactoryHolder.registerFactory(DanMiFactory.instance());
ProviderFactoryHolder.registerFactory(YiXintongFactory.instance());
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) { if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) { if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance()); ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());