mirror of
https://gitee.com/dromara/sms4j.git
synced 2025-12-06 17:08:40 +08:00
commit
65cad7d296
12
README_MONTNETS.md
Normal file
12
README_MONTNETS.md
Normal file
@ -0,0 +1,12 @@
|
||||
### 梦网 --- montnets
|
||||
|
||||
配置类:`org.dromara.sms4j.montnets.config.MontnetsConfig`
|
||||
|
||||
| 字段名称 | 作用 | 默认值 |
|
||||
|-------------------|---------|-----------------------------|
|
||||
| `accessKeyId` | 账号 | `null` |
|
||||
| `accessKeySecret` | 密码 | `null` |
|
||||
| `url` | 请求地址 | `http://ip:port` |
|
||||
| `api` | 接口名称 | `/sms/v2/std/send_template` |
|
||||
| `templateId` | 默认模板id | `null` |
|
||||
| `templateParam` | 默认模板参数名 | `null` |
|
||||
@ -97,4 +97,8 @@ public abstract class SupplierConstant {
|
||||
* 联通一信通 sms
|
||||
*/
|
||||
public static final String YIXINTONG = "yixintong";
|
||||
/**
|
||||
* 梦网 sms
|
||||
*/
|
||||
public static final String MONTNETS = "montnets";
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@ import org.dromara.sms4j.jg.config.JgFactory;
|
||||
import org.dromara.sms4j.lianlu.config.LianLuFactory;
|
||||
import org.dromara.sms4j.luosimao.config.LuoSiMaoFactory;
|
||||
import org.dromara.sms4j.mas.config.MasFactory;
|
||||
import org.dromara.sms4j.montnets.config.MontnetsFactory;
|
||||
import org.dromara.sms4j.netease.config.NeteaseFactory;
|
||||
import org.dromara.sms4j.provider.config.SmsConfig;
|
||||
import org.dromara.sms4j.provider.factory.BaseProviderFactory;
|
||||
@ -264,6 +265,7 @@ public class SEInitializer {
|
||||
ProviderFactoryHolder.registerFactory(SubMailFactory.instance());
|
||||
ProviderFactoryHolder.registerFactory(DanMiFactory.instance());
|
||||
ProviderFactoryHolder.registerFactory(YiXintongFactory.instance());
|
||||
ProviderFactoryHolder.registerFactory(MontnetsFactory.instance());
|
||||
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
|
||||
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());
|
||||
}
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
package org.dromara.sms4j.montnets.config;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||
import org.dromara.sms4j.provider.config.BaseConfig;
|
||||
|
||||
/**
|
||||
* @author SU
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class MontnetsConfig extends BaseConfig {
|
||||
|
||||
/**
|
||||
* 请求地址
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* 接口名称
|
||||
*/
|
||||
private String api;
|
||||
/**
|
||||
* 模板code
|
||||
*/
|
||||
private String templateId;
|
||||
/**
|
||||
* 模板变量名称
|
||||
*/
|
||||
private String templateParam;
|
||||
|
||||
/**
|
||||
* 获取供应商
|
||||
*/
|
||||
@Override
|
||||
public String getSupplier() {
|
||||
return SupplierConstant.MONTNETS;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package org.dromara.sms4j.montnets.config;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.dromara.sms4j.comm.constant.SupplierConstant;
|
||||
import org.dromara.sms4j.montnets.service.MontnetsSmsImpl;
|
||||
import org.dromara.sms4j.provider.factory.AbstractProviderFactory;
|
||||
|
||||
|
||||
/**
|
||||
* MontnetsSmsConfig
|
||||
* <p> 梦网对象建造者
|
||||
*
|
||||
* @author :SU
|
||||
* 2025/4/23 10:32
|
||||
**/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class MontnetsFactory extends AbstractProviderFactory<MontnetsSmsImpl, MontnetsConfig> {
|
||||
|
||||
private static final MontnetsFactory INSTANCE = new MontnetsFactory();
|
||||
|
||||
/**
|
||||
* 获取建造者实例
|
||||
* @return 建造者实例
|
||||
*/
|
||||
public static MontnetsFactory instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建短信实现对象
|
||||
* @param montnetsConfig 短信配置对象
|
||||
* @return 短信实现对象
|
||||
*/
|
||||
@Override
|
||||
public MontnetsSmsImpl createSms(MontnetsConfig montnetsConfig) {
|
||||
return new MontnetsSmsImpl(montnetsConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取供应商
|
||||
* @return 供应商
|
||||
*/
|
||||
@Override
|
||||
public String getSupplier() {
|
||||
return SupplierConstant.MONTNETS;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,152 @@
|
||||
package org.dromara.sms4j.montnets.service;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.net.URLDecoder;
|
||||
import cn.hutool.core.net.URLEncodeUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
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.Constant;
|
||||
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.montnets.config.MontnetsConfig;
|
||||
import org.dromara.sms4j.montnets.utils.MontnetsUtils;
|
||||
import org.dromara.sms4j.provider.service.AbstractSmsBlend;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* <p>类名: MontnetsSmsImpl
|
||||
* <p>说明: 梦网短信实现
|
||||
*
|
||||
* @author :SU
|
||||
* 2025/4/23 10:32
|
||||
**/
|
||||
@Slf4j
|
||||
public class MontnetsSmsImpl extends AbstractSmsBlend<MontnetsConfig> {
|
||||
|
||||
private int retry = 0;
|
||||
|
||||
/**
|
||||
* MontnetsSmsImpl
|
||||
* <p>构造器,用于构造短信实现模块
|
||||
*/
|
||||
public MontnetsSmsImpl(MontnetsConfig config, Executor pool, DelayedTime delayedTime) {
|
||||
super(config, pool, delayedTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* MontnetsSmsImpl
|
||||
* <p>构造器,用于构造短信实现模块
|
||||
*/
|
||||
public MontnetsSmsImpl(MontnetsConfig config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSupplier() {
|
||||
return SupplierConstant.MONTNETS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsResponse sendMessage(String phone, String message) {
|
||||
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
|
||||
map.put(getConfig().getTemplateParam(), message);
|
||||
return sendMessage(phone, this.getConfig().getTemplateId(), map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsResponse sendMessage(String phone, LinkedHashMap<String, String> messages) {
|
||||
if (Objects.isNull(messages)) {
|
||||
messages = new LinkedHashMap<>();
|
||||
}
|
||||
return sendMessage(phone, getConfig().getTemplateId(), messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages) {
|
||||
if (Objects.isNull(messages)) {
|
||||
messages = new LinkedHashMap<>();
|
||||
}
|
||||
String messageStr = formatMessage(messages);
|
||||
return getSmsResponse(phone, messageStr, templateId);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SmsResponse massTexting(List<String> phones, String message) {
|
||||
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||
map.put(getConfig().getTemplateParam(), message);
|
||||
return massTexting(phones, getConfig().getTemplateId(), map);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SmsResponse massTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
||||
if (Objects.isNull(messages)) {
|
||||
messages = new LinkedHashMap<>();
|
||||
}
|
||||
String messageStr = formatMessage(messages);
|
||||
return getSmsResponse(SmsUtils.addCodePrefixIfNot(phones), messageStr, templateId);
|
||||
}
|
||||
|
||||
private SmsResponse getSmsResponse(String phone, String message, String templateId) {
|
||||
String requestUrl;
|
||||
String paramStr;
|
||||
try {
|
||||
requestUrl = MontnetsUtils.generateSendSmsRequestUrl(this.getConfig());
|
||||
paramStr = MontnetsUtils.generateParamBody(this.getConfig(), phone, message, templateId);
|
||||
} catch (Exception e) {
|
||||
log.error("montnets send message error", e);
|
||||
throw new SmsBlendException(e.getMessage());
|
||||
}
|
||||
|
||||
log.debug("requestUrl {}", requestUrl);
|
||||
Map<String, String> headers = MapUtil.newHashMap(1, true);
|
||||
headers.put(Constant.CONTENT_TYPE, Constant.APPLICATION_JSON_UTF8);
|
||||
|
||||
SmsResponse smsResponse;
|
||||
try {
|
||||
smsResponse = this.getResponse(this.http.postJson(requestUrl, headers, paramStr));
|
||||
} catch (SmsBlendException e) {
|
||||
smsResponse = this.errorResp(e.message);
|
||||
}
|
||||
|
||||
if (!smsResponse.isSuccess() && this.retry != this.getConfig().getMaxRetries()) {
|
||||
return this.requestRetry(phone, message, templateId);
|
||||
} else {
|
||||
this.retry = 0;
|
||||
return smsResponse;
|
||||
}
|
||||
}
|
||||
|
||||
private SmsResponse requestRetry(String phone, String message, String templateId) {
|
||||
this.http.safeSleep(this.getConfig().getRetryInterval());
|
||||
++this.retry;
|
||||
log.warn("短信第 {} 次重新发送", this.retry);
|
||||
return this.getSmsResponse(phone, message, templateId);
|
||||
}
|
||||
|
||||
private SmsResponse getResponse(JSONObject resJson) {
|
||||
return SmsRespUtils.resp(URLDecoder.decode(resJson.getStr("desc"), StandardCharsets.UTF_8), "0".equals(resJson.getStr("result")), getConfigId());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>说明:格式化消息
|
||||
*
|
||||
* @param messages 模板参数key-value集合
|
||||
* @return 格式化后的消息 key1=urlEncode(value1)&key2=urlEncode(value2)
|
||||
*/
|
||||
private String formatMessage(LinkedHashMap<String, String> messages) {
|
||||
StringJoiner joiner = new StringJoiner("&");
|
||||
for (Map.Entry<String, String> entry : messages.entrySet()) {
|
||||
joiner.add(entry.getKey() + "=" + URLEncodeUtil.encode(entry.getValue(), StandardCharsets.UTF_8));
|
||||
}
|
||||
return URLEncodeUtil.encode(joiner.toString());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package org.dromara.sms4j.montnets.utils;
|
||||
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import org.dromara.sms4j.comm.utils.SmsDateUtils;
|
||||
import org.dromara.sms4j.montnets.config.MontnetsConfig;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author SU
|
||||
* 2025/4/23 10:32
|
||||
*/
|
||||
public class MontnetsUtils {
|
||||
|
||||
public static String generateSendSmsRequestUrl(MontnetsConfig montnetsConfig) {
|
||||
String url = montnetsConfig.getUrl();
|
||||
String api = montnetsConfig.getApi();
|
||||
return url + api;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成请求body参数
|
||||
*
|
||||
* @param montnetsConfig 短信配置
|
||||
* @param phone 手机号
|
||||
* @param message 短信内容
|
||||
* @param templateId 模板ID
|
||||
*/
|
||||
public static Map<String, String> generateParamMap(MontnetsConfig montnetsConfig, String phone, String message, String templateId) {
|
||||
Map<String, String> paramMap = new HashMap<>();
|
||||
|
||||
String accessKeyId = montnetsConfig.getAccessKeyId();
|
||||
String accessKeySecret = montnetsConfig.getAccessKeySecret();
|
||||
String timeStamp = SmsDateUtils.formatDateToStr(new Date(), "MMddHHmmss", SmsDateUtils.gmt8());
|
||||
|
||||
paramMap.put("userid", accessKeyId);
|
||||
paramMap.put("pwd", DigestUtil.md5Hex(accessKeyId.toUpperCase(Locale.ENGLISH) + "00000000" + accessKeySecret + timeStamp));
|
||||
paramMap.put("timestamp", timeStamp);
|
||||
paramMap.put("mobile", phone);
|
||||
paramMap.put("content", message);
|
||||
paramMap.put("tmplid", templateId);
|
||||
|
||||
return paramMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成请求参数body字符串
|
||||
*
|
||||
* @param montnetsConfig 短信配置
|
||||
* @param phone 手机号
|
||||
* @param message 短信内容
|
||||
* @param templateId 模板ID
|
||||
*/
|
||||
public static String generateParamBody(MontnetsConfig montnetsConfig, String phone, String message, String templateId) {
|
||||
Map<String, String> paramMap = generateParamMap(montnetsConfig, phone, message, templateId);
|
||||
return JSONUtil.toJsonStr(paramMap);
|
||||
}
|
||||
}
|
||||
@ -33,6 +33,7 @@ import org.dromara.sms4j.jg.config.JgFactory;
|
||||
import org.dromara.sms4j.lianlu.config.LianLuFactory;
|
||||
import org.dromara.sms4j.luosimao.config.LuoSiMaoFactory;
|
||||
import org.dromara.sms4j.mas.config.MasFactory;
|
||||
import org.dromara.sms4j.montnets.config.MontnetsFactory;
|
||||
import org.dromara.sms4j.netease.config.NeteaseFactory;
|
||||
import org.dromara.sms4j.provider.config.SmsConfig;
|
||||
import org.dromara.sms4j.provider.factory.BaseProviderFactory;
|
||||
@ -150,6 +151,7 @@ public class SmsBlendsInitializer {
|
||||
ProviderFactoryHolder.registerFactory(SubMailFactory.instance());
|
||||
ProviderFactoryHolder.registerFactory(DanMiFactory.instance());
|
||||
ProviderFactoryHolder.registerFactory(YiXintongFactory.instance());
|
||||
ProviderFactoryHolder.registerFactory(MontnetsFactory.instance());
|
||||
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
|
||||
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
|
||||
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());
|
||||
|
||||
@ -169,6 +169,20 @@ sms:
|
||||
template-id: #(可选)模板编号(若配置此参数,则会默认使用该模板,以便提高服务方性能)
|
||||
sign-code: #(可选)短信前置签名编号(登陆平台-接口业务-我的签名查看)
|
||||
f: 1 #(可选)默认为1,提交时检测方式
|
||||
# 梦网
|
||||
montnets:
|
||||
# 您的accessKey
|
||||
access-key-id: 您的accessKey
|
||||
# 您的accessKeySecret
|
||||
access-key-secret: 您的accessKeySecret
|
||||
# 服务地址
|
||||
url: 服务地址 http://ip:port
|
||||
# 接口地址
|
||||
api: 接口地址 /sms/v2/std/send_template
|
||||
# 默认模板id
|
||||
templateId: 默认模板id
|
||||
# 默认模板参数名
|
||||
templateParam: 默认模板参数名
|
||||
|
||||
sms-oa:
|
||||
config-type: yaml
|
||||
|
||||
@ -281,7 +281,7 @@ public class Sms4jTest {
|
||||
log.info(JSONUtil.toJsonStr(smsResponse3));
|
||||
Assert.isTrue(smsResponse3.isSuccess());
|
||||
|
||||
SmsResponse smsResponse4 = dz.massTexting(phones, "" ,messages);
|
||||
SmsResponse smsResponse4 = dz.massTexting(phones, "", messages);
|
||||
log.info(JSONUtil.toJsonStr(smsResponse4));
|
||||
Assert.isTrue(smsResponse4.isSuccess());
|
||||
|
||||
@ -559,4 +559,14 @@ public class Sms4jTest {
|
||||
Assert.isTrue(smsResponse2.isSuccess());
|
||||
}
|
||||
|
||||
/**
|
||||
* 梦网短信
|
||||
*/
|
||||
@Test
|
||||
public void montnetsSmsTest() {
|
||||
// 梦网
|
||||
SmsResponse smsResponse = SmsFactory.getBySupplier(SupplierConstant.MONTNETS).sendMessage(PHONE, SmsUtils.getRandomInt(6));
|
||||
Assert.isTrue(smsResponse.isSuccess());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@ import org.dromara.sms4j.jg.config.JgFactory;
|
||||
import org.dromara.sms4j.lianlu.config.LianLuFactory;
|
||||
import org.dromara.sms4j.luosimao.config.LuoSiMaoFactory;
|
||||
import org.dromara.sms4j.mas.config.MasFactory;
|
||||
import org.dromara.sms4j.montnets.config.MontnetsFactory;
|
||||
import org.dromara.sms4j.netease.config.NeteaseFactory;
|
||||
import org.dromara.sms4j.provider.config.SmsConfig;
|
||||
import org.dromara.sms4j.provider.factory.BaseProviderFactory;
|
||||
@ -84,7 +85,7 @@ public class SmsBlendsInitializer {
|
||||
SmsProxyFactory.addPreProcessor(new CoreMethodParamValidateProcessor(null));
|
||||
}
|
||||
//注册执行器实现
|
||||
if(this.smsConfig.getRestricted()){
|
||||
if (this.smsConfig.getRestricted()) {
|
||||
SmsProxyFactory.addPreProcessor(new RestrictedProcessor());
|
||||
SmsProxyFactory.addPreProcessor(new BlackListProcessor());
|
||||
SmsProxyFactory.addPreProcessor(new BlackListRecordingProcessor());
|
||||
@ -150,6 +151,7 @@ public class SmsBlendsInitializer {
|
||||
ProviderFactoryHolder.registerFactory(SubMailFactory.instance());
|
||||
ProviderFactoryHolder.registerFactory(DanMiFactory.instance());
|
||||
ProviderFactoryHolder.registerFactory(YiXintongFactory.instance());
|
||||
ProviderFactoryHolder.registerFactory(MontnetsFactory.instance());
|
||||
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
|
||||
if (SmsUtils.isClassExists("com.jdcloud.sdk.auth.CredentialsProvider")) {
|
||||
ProviderFactoryHolder.registerFactory(JdCloudFactory.instance());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user