diff --git a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/SupplierConstant.java b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/SupplierConstant.java
index 59de4921..31057f38 100644
--- a/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/SupplierConstant.java
+++ b/sms4j-comm/src/main/java/org/dromara/sms4j/comm/constant/SupplierConstant.java
@@ -93,4 +93,8 @@ public abstract class SupplierConstant {
* danmi sms
*/
public static final String DAN_MI = "danmi";
+ /**
+ * 联通一信通 sms
+ */
+ public static final String YIXINTONG = "yixintong";
}
diff --git a/sms4j-javase-plugin/src/main/java/org/dromara/sms4j/javase/config/SEInitializer.java b/sms4j-javase-plugin/src/main/java/org/dromara/sms4j/javase/config/SEInitializer.java
index fce1f3bc..18b718ef 100644
--- a/sms4j-javase-plugin/src/main/java/org/dromara/sms4j/javase/config/SEInitializer.java
+++ b/sms4j-javase-plugin/src/main/java/org/dromara/sms4j/javase/config/SEInitializer.java
@@ -50,6 +50,7 @@ import org.dromara.sms4j.qiniu.config.QiNiuFactory;
import org.dromara.sms4j.submail.config.SubMailFactory;
import org.dromara.sms4j.tencent.config.TencentFactory;
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.zhutong.config.ZhutongFactory;
@@ -266,6 +267,7 @@ public class SEInitializer {
ProviderFactoryHolder.registerFactory(LuoSiMaoFactory.instance());
ProviderFactoryHolder.registerFactory(SubMailFactory.instance());
ProviderFactoryHolder.registerFactory(DanMiFactory.instance());
+ ProviderFactoryHolder.registerFactory(YiXintongFactory.instance());
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());
}
diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/yixintong/config/YiXintongConfig.java b/sms4j-provider/src/main/java/org/dromara/sms4j/yixintong/config/YiXintongConfig.java
new file mode 100644
index 00000000..36fabb2e
--- /dev/null
+++ b/sms4j-provider/src/main/java/org/dromara/sms4j/yixintong/config/YiXintongConfig.java
@@ -0,0 +1,48 @@
+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;
+
+/**
+ *
类名: YiXintongConfig
+ *
说明:联通一信通平台配置类
+ *
所用到配置项:spCode、f、accessKeyId(用户名)、accessKeySecret(接口密钥)、signCode、templateId、retryInterval、maxRetries
+ *
+ * @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;
+
+ /**
+ * 签名编号
+ */
+ private String signCode;
+
+ /**
+ * 提交时检测方式
+ * 1 --- 提交号码中有效的号码仍正常发出短信,无效的号码在返回参数faillist中列出
+ *
+ * 不为1 或该参数不存在 --- 提交号码中只要有无效的号码,那么所有的号码都不发出短信,无效号码在返回参数faillist中列出
+ */
+ private String f = "1";
+
+
+ @Override
+ public String getSupplier() {
+ return SupplierConstant.YIXINTONG;
+ }
+}
diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/yixintong/config/YiXintongFactory.java b/sms4j-provider/src/main/java/org/dromara/sms4j/yixintong/config/YiXintongFactory.java
new file mode 100644
index 00000000..4c9573ea
--- /dev/null
+++ b/sms4j-provider/src/main/java/org/dromara/sms4j/yixintong/config/YiXintongFactory.java
@@ -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;
+
+/**
+ *
类名: YiXintongFactory
+ *
说明:联通一信通平台短信对象建造
+ *
+ * @author moat
+ * @create 2024-07-30 17:10
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class YiXintongFactory extends AbstractProviderFactory {
+
+ private static final YiXintongFactory INSTANCE = new YiXintongFactory();
+
+ /**
+ * 获取建造者实例
+ * @return 建造者实例
+ */
+ public static YiXintongFactory instance() {
+ return INSTANCE;
+ }
+
+ /**
+ * createSms
+ * 建造一个短信实现对像
+ */
+ @Override
+ public YiXintongSmsImpl createSms(YiXintongConfig yiXintongConfig) {
+ return new YiXintongSmsImpl(yiXintongConfig);
+ }
+
+ /**
+ * 获取供应商
+ * @return 供应商
+ */
+ @Override
+ public String getSupplier() {
+ return SupplierConstant.YIXINTONG;
+ }
+}
diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/yixintong/service/YiXintongSmsImpl.java b/sms4j-provider/src/main/java/org/dromara/sms4j/yixintong/service/YiXintongSmsImpl.java
new file mode 100644
index 00000000..c6b2996b
--- /dev/null
+++ b/sms4j-provider/src/main/java/org/dromara/sms4j/yixintong/service/YiXintongSmsImpl.java
@@ -0,0 +1,129 @@
+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;
+
+/**
+ *
类名: YiXintongSmsImpl
+ *
说明:联通一信通 sms
+ *
+ * @author moat
+ * @create 2024-07-30 16:59
+ */
+@Slf4j
+public class YiXintongSmsImpl extends AbstractSmsBlend {
+
+ 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 phones, String message) {
+ return getSmsResponse(SmsUtils.joinComma(phones), message, getConfig().getTemplateId());
+ }
+
+ @Override
+ public SmsResponse sendMessage(String phone, LinkedHashMap messages) {
+ throw new SmsBlendException("不支持此方法");
+ }
+
+ @Override
+ public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap messages) {
+ throw new SmsBlendException("不支持此方法");
+ }
+
+ @Override
+ public SmsResponse massTexting(List phones, String templateId, LinkedHashMap 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 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());
+ forms.put("signCode", config.getSignCode());
+
+ 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());
+ }
+
+}
diff --git a/sms4j-provider/src/main/java/org/dromara/sms4j/yixintong/utils/YiXintongUtils.java b/sms4j-provider/src/main/java/org/dromara/sms4j/yixintong/utils/YiXintongUtils.java
new file mode 100644
index 00000000..83cb665c
--- /dev/null
+++ b/sms4j-provider/src/main/java/org/dromara/sms4j/yixintong/utils/YiXintongUtils.java
@@ -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;
+
+/**
+ * 类名: YiXintongUtils
+ *
说明:联通一信通工具类
+ *
+ * @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 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 headers, Map 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());
+ }
+ }
+
+
+}
diff --git a/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SmsBlendsInitializer.java b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SmsBlendsInitializer.java
index b31578e5..6b658299 100644
--- a/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SmsBlendsInitializer.java
+++ b/sms4j-solon-plugin/src/main/java/org/dromara/sms4j/solon/config/SmsBlendsInitializer.java
@@ -40,6 +40,7 @@ import org.dromara.sms4j.solon.holder.SolonSmsDaoHolder;
import org.dromara.sms4j.submail.config.SubMailFactory;
import org.dromara.sms4j.tencent.config.TencentFactory;
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.zhutong.config.ZhutongFactory;
import org.noear.solon.core.AppContext;
@@ -135,6 +136,7 @@ public class SmsBlendsInitializer {
ProviderFactoryHolder.registerFactory(LuoSiMaoFactory.instance());
ProviderFactoryHolder.registerFactory(SubMailFactory.instance());
ProviderFactoryHolder.registerFactory(DanMiFactory.instance());
+ ProviderFactoryHolder.registerFactory(YiXintongFactory.instance());
if(SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());
}
diff --git a/sms4j-spring-boot-example/src/main/resources/application.yml b/sms4j-spring-boot-example/src/main/resources/application.yml
index 1780baae..4b906f27 100644
--- a/sms4j-spring-boot-example/src/main/resources/application.yml
+++ b/sms4j-spring-boot-example/src/main/resources/application.yml
@@ -155,6 +155,14 @@ sms:
accessKeyId: ACCOUNT SID
accessKeySecret: AUTH TOKEN
action: 默认请求方法 distributor/sendSMS
+ # 一信通
+ yixintong:
+ sp-code: xxxxxx #(必填)企业编号
+ access-key-id: xxxxxx #(必填)用户名
+ access-key-secret: 324gaxxxxxxxxxxxxxxxxx9sdf89 #(必填)接口密钥(正式帐户需要登陆平台,接口业务-接口申请右侧钥匙状图标查看或获取,接口密钥获取后十分钟生效)
+ template-id: #(可选)模板编号(若配置此参数,则会默认使用该模板,以便提高服务方性能)
+ sign-code: #(可选)短信前置签名编号(登陆平台-接口业务-我的签名查看)
+ f: 1 #(可选)默认为1,提交时检测方式
sms-oa:
config-type: yaml
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
index a45a69c8..cca4a1f3 100644
--- 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
@@ -1,5 +1,6 @@
package org.dromara.sms4j.example;
+import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.UUID;
@@ -526,4 +527,31 @@ public class Sms4jTest {
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 phones = CollectionUtil.toList(PHONE);
+ 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());
+ }
+
}
diff --git a/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/config/SmsBlendsInitializer.java b/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/config/SmsBlendsInitializer.java
index 53fe8f30..cb373ddf 100644
--- a/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/config/SmsBlendsInitializer.java
+++ b/sms4j-spring-boot-starter/src/main/java/org/dromara/sms4j/starter/config/SmsBlendsInitializer.java
@@ -42,6 +42,7 @@ import org.dromara.sms4j.starter.adepter.ConfigCombineMapAdaptor;
import org.dromara.sms4j.submail.config.SubMailFactory;
import org.dromara.sms4j.tencent.config.TencentFactory;
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.zhutong.config.ZhutongFactory;
import org.springframework.beans.factory.ObjectProvider;
@@ -150,6 +151,7 @@ public class SmsBlendsInitializer {
ProviderFactoryHolder.registerFactory(LuoSiMaoFactory.instance());
ProviderFactoryHolder.registerFactory(SubMailFactory.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());