mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-26 17:21:53 +08:00
增加钉钉模拟短信的 smsClient 实现类
This commit is contained in:
parent
1740128dc3
commit
be8b892bf6
@ -3,6 +3,7 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl;
|
|||||||
import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
|
import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
|
||||||
import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
|
import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
|
||||||
import cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun.AliyunSmsClient;
|
import cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun.AliyunSmsClient;
|
||||||
|
import cn.iocoder.dashboard.framework.sms.core.client.impl.debug.DebugDingTalkSmsClient;
|
||||||
import cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian.YunpianSmsClient;
|
import cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian.YunpianSmsClient;
|
||||||
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
|
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
|
||||||
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
|
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
|
||||||
@ -77,35 +78,13 @@ public class SmsClientFactoryImpl implements SmsClientFactory {
|
|||||||
Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum));
|
Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum));
|
||||||
// 创建客户端
|
// 创建客户端
|
||||||
switch (channelEnum) {
|
switch (channelEnum) {
|
||||||
case ALIYUN:
|
case ALIYUN: return new AliyunSmsClient(properties);
|
||||||
return new AliyunSmsClient(properties);
|
case YUN_PIAN: return new YunpianSmsClient(properties);
|
||||||
case YUN_PIAN:
|
case DEBUG_DING_TALK: return new DebugDingTalkSmsClient(properties);
|
||||||
return new YunpianSmsClient(properties);
|
|
||||||
}
|
}
|
||||||
// 创建失败,错误日志 + 抛出异常
|
// 创建失败,错误日志 + 抛出异常
|
||||||
log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties);
|
log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties);
|
||||||
throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", properties));
|
throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", properties));
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * 从短信发送回调函数请求中获取用于唯一确定一条send_lod的apiId
|
|
||||||
// *
|
|
||||||
// * @param callbackRequest 短信发送回调函数请求
|
|
||||||
// * @return 第三方平台短信唯一标识
|
|
||||||
// */
|
|
||||||
// public SmsResultDetail getSmsResultDetailFromCallbackQuery(ServletRequest callbackRequest) {
|
|
||||||
// for (Long channelId : clients.keySet()) {
|
|
||||||
// AbstractSmsClient smsClient = clients.get(channelId);
|
|
||||||
// try {
|
|
||||||
// SmsResultDetail smsSendResult = smsClient.smsSendCallbackHandle(callbackRequest);
|
|
||||||
// if (smsSendResult != null) {
|
|
||||||
// return smsSendResult;
|
|
||||||
// }
|
|
||||||
// } catch (Exception ignored) {
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// throw new IllegalArgumentException("getSmsResultDetailFromCallbackQuery fail! don't match SmsClient by RequestParam: "
|
|
||||||
// + JsonUtils.toJsonString(callbackRequest.getParameterMap()));
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package cn.iocoder.dashboard.framework.sms.core.client.impl.debug;
|
||||||
|
|
||||||
|
import cn.iocoder.dashboard.common.exception.ErrorCode;
|
||||||
|
import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
|
import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 钉钉的 SmsCodeMapping 实现类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class DebugDingTalkCodeMapping implements SmsCodeMapping {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ErrorCode apply(String apiCode) {
|
||||||
|
return Objects.equals(apiCode, "0") ? GlobalErrorCodeConstants.SUCCESS : SMS_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
package cn.iocoder.dashboard.framework.sms.core.client.impl.debug;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64;
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.crypto.digest.DigestUtil;
|
||||||
|
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
|
import cn.iocoder.dashboard.common.core.KeyValue;
|
||||||
|
import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
|
||||||
|
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||||
|
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||||
|
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||||
|
import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
|
||||||
|
import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
||||||
|
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
|
||||||
|
import cn.iocoder.dashboard.util.collection.MapUtils;
|
||||||
|
import cn.iocoder.dashboard.util.json.JsonUtils;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于钉钉 WebHook 实现的调试的短信客户端实现类
|
||||||
|
*
|
||||||
|
* 考虑到省钱,我们使用钉钉 WebHook 模拟发送短信,方便调试。
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class DebugDingTalkSmsClient extends AbstractSmsClient {
|
||||||
|
|
||||||
|
public DebugDingTalkSmsClient(SmsChannelProperties properties) {
|
||||||
|
super(properties, new DebugDingTalkCodeMapping());
|
||||||
|
Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
|
||||||
|
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
|
||||||
|
String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
|
||||||
|
// 构建请求
|
||||||
|
String url = buildUrl("robot/send");
|
||||||
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.put("msgtype", "text");
|
||||||
|
String content = String.format("【模拟短信】\n手机号:%s\n短信日志编号:%d\n模板参数:%s",
|
||||||
|
mobile, sendLogId, MapUtils.convertMap(templateParams));
|
||||||
|
params.put("text", MapUtil.builder().put("content", content).build());
|
||||||
|
// 执行请求
|
||||||
|
String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params));
|
||||||
|
// 解析结果
|
||||||
|
Map<?, ?> responseObj = JsonUtils.parseObject(responseText, Map.class);
|
||||||
|
return SmsCommonResult.build(MapUtil.getStr(responseObj, "errcode"), MapUtil.getStr(responseObj, "errorMsg"),
|
||||||
|
null, new SmsSendRespDTO().setSerialNo(StrUtil.uuid()), codeMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建请求地址
|
||||||
|
*
|
||||||
|
* 参见 https://developers.dingtalk.com/document/app/custom-robot-access/title-nfv-794-g71 文档
|
||||||
|
*
|
||||||
|
* @param path 请求路径
|
||||||
|
* @return 请求地址
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
|
private String buildUrl(String path) {
|
||||||
|
// 生成 timestamp
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
// 生成 sign
|
||||||
|
String secret = properties.getApiSecret();
|
||||||
|
String stringToSign = timestamp + "\n" + secret;
|
||||||
|
byte[] signData = DigestUtil.hmac(HmacAlgorithm.HmacSHA256, StrUtil.bytes(secret)).digest(stringToSign);
|
||||||
|
String sign = Base64.encode(signData);
|
||||||
|
// 构建最终 URL
|
||||||
|
return String.format("https://oapi.dingtalk.com/%s?access_token=%s×tamp=%d&sign=%s",
|
||||||
|
path, properties.getApiKey(), timestamp, sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
|
||||||
|
throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) {
|
||||||
|
SmsTemplateRespDTO data = new SmsTemplateRespDTO().setId(apiTemplateId).setContent("")
|
||||||
|
.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason("");
|
||||||
|
return SmsCommonResult.build("0", "success", null, data, codeMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -14,6 +14,7 @@ import lombok.Getter;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum SmsChannelEnum {
|
public enum SmsChannelEnum {
|
||||||
|
|
||||||
|
DEBUG_DING_TALK("DEBUG_DING_TALK", "调试(钉钉)"),
|
||||||
YUN_PIAN("YUN_PIAN", "云片"),
|
YUN_PIAN("YUN_PIAN", "云片"),
|
||||||
ALIYUN("ALIYUN", "阿里云"),
|
ALIYUN("ALIYUN", "阿里云"),
|
||||||
// TENCENT("TENCENT", "腾讯云"),
|
// TENCENT("TENCENT", "腾讯云"),
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package cn.iocoder.dashboard.framework.sms.core.client.impl.debug;
|
||||||
|
|
||||||
|
import cn.iocoder.dashboard.common.core.KeyValue;
|
||||||
|
import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
|
||||||
|
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||||
|
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
|
||||||
|
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link DebugDingTalkSmsClient} 的集成测试
|
||||||
|
*/
|
||||||
|
public class DebugDingTalkSmsClientIntegrationTest {
|
||||||
|
|
||||||
|
private static DebugDingTalkSmsClient smsClient;
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public static void init() {
|
||||||
|
// 创建配置类
|
||||||
|
SmsChannelProperties properties = new SmsChannelProperties();
|
||||||
|
properties.setId(1L);
|
||||||
|
properties.setSignature("芋道");
|
||||||
|
properties.setCode(SmsChannelEnum.DEBUG_DING_TALK.getCode());
|
||||||
|
properties.setApiKey("696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859");
|
||||||
|
properties.setApiSecret("SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67");
|
||||||
|
// 创建客户端
|
||||||
|
smsClient = new DebugDingTalkSmsClient(properties);
|
||||||
|
smsClient.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSendSms() {
|
||||||
|
List<KeyValue<String, Object>> templateParams = new ArrayList<>();
|
||||||
|
templateParams.add(new KeyValue<>("code", "1024"));
|
||||||
|
templateParams.add(new KeyValue<>("operation", "嘿嘿"));
|
||||||
|
// SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams);
|
||||||
|
SmsCommonResult<SmsSendRespDTO> result = smsClient.sendSms(1L, "15601691399", "4383920", templateParams);
|
||||||
|
System.out.println(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user