diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java index 1754b897d..46c59033c 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java @@ -60,8 +60,12 @@ public class SmsResult implements Serializable { public static SmsResult success(SmsSendFailureTypeEnum sendFailureType, String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) { - return new SmsResult().setSuccess(true).setSendFailureType(sendFailureType.getType()).setSendFailureMsg(sendFailureType.getMsg()) - .setApiSendCode(apiSendCode).setApiSendMsg(apiSendMsg).setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo); + SmsResult result = new SmsResult().setSuccess(true).setApiSendCode(apiSendCode).setApiSendMsg(apiSendMsg) + .setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo); + if (sendFailureType != null) { + result.setSendFailureType(sendFailureType.getType()).setSendFailureMsg(sendFailureType.getMsg()); + } + return result; } public static SmsResult error(Throwable ex) { diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java index a2af47ffb..f9f19a22e 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java @@ -2,14 +2,20 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.util.json.JsonUtils; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.http.MethodType; import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.IClientProfile; import com.fasterxml.jackson.core.type.TypeReference; @@ -36,8 +42,6 @@ public class AliyunSmsClient extends AbstractSmsClient { private static final String DOMAIN = "dysmsapi.aliyuncs.com"; private static final String ENDPOINT = "cn-hangzhou"; - private static final String OK = "OK"; - /** * 阿里云客户端 */ @@ -56,29 +60,44 @@ public class AliyunSmsClient extends AbstractSmsClient { @Override protected SmsResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) throws Exception { - return null; + // 构建参数 + SendSmsRequest request = new SendSmsRequest(); + request.setSysMethod(MethodType.POST); + request.setPhoneNumbers(mobile); + request.setSignName(properties.getSignature()); + request.setTemplateCode(apiTemplateId); + request.setTemplateParam(JsonUtils.toJsonString(templateParams)); + request.setOutId(String.valueOf(sendLogId)); + + try { + // 执行发送 + SendSmsResponse sendResult = acsClient.getAcsResponse(request); + // 解析结果 + return SmsResult.success(parseSendFailureType(sendResult.getCode()), // 将 API 短信平台,解析成统一的错误码 + sendResult.getCode(), sendResult.getMessage(), sendResult.getRequestId(), sendResult.getBizId()); + } catch (ClientException ex) { + return SmsResult.success(parseSendFailureType(ex.getErrCode()), // 将 API 短信平台,解析成统一的错误码 + ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null); + } } -// @Override -// public SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception { -// SendSmsRequest request = new SendSmsRequest(); -// request.setSysMethod(MethodType.POST); -// request.setPhoneNumbers(targetPhone); -// request.setSignName(properties.getSignature()); -// request.setTemplateCode(templateApiId); -// request.setTemplateParam(smsBody.getParamsStr()); -// SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); -// -// boolean success = OK.equals(sendSmsResponse.getCode()); -// if (!success) { -// log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage()); -// } -// return new SmsResult() -// .setSuccess(success) -// .setMessage(sendSmsResponse.getMessage()) -// .setCode(sendSmsResponse.getCode()) -// .setApiId(sendSmsResponse.getBizId()); -// } + private static SmsSendFailureTypeEnum parseSendFailureType(String code) { + switch (code) { + case "OK": return null; + case "MissingAccessKeyId": return SmsSendFailureTypeEnum.SMS_CHANNEL_API_KEY_MISSING; + case "isp.RAM_PERMISSION_DENY": return SmsSendFailureTypeEnum.SMS_CHANNEL_PERMISSION_DENY; + case "isv.INVALID_PARAMETERS": return SmsSendFailureTypeEnum.SMS_API_PARAM_ERROR; + case "isv.BUSINESS_LIMIT_CONTROL": return SmsSendFailureTypeEnum.SMS_SEND_LIMIT_CONTROL; + } + return SmsSendFailureTypeEnum.SMS_UNKNOWN; + } + + private static String formatResultMsg(ClientException ex) { + if (StrUtil.isEmpty(ex.getErrorDescription())) { + return ex.getMessage(); + } + return ex.getErrMsg() + " => " + ex.getErrorDescription(); + } /** * [{ diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java index 00b64ad4c..9e840f6ae 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java @@ -106,10 +106,11 @@ public class YunpianSmsClient extends AbstractSmsClient { private static SmsSendFailureTypeEnum parseSendFailureType(Result sendResult) { Integer code = sendResult.getCode(); switch (code) { + case OK: return null; case ARGUMENT_MISSING: return SmsSendFailureTypeEnum.SMS_API_PARAM_ERROR; case BAD_ARGUMENT_FORMAT: return SmsSendFailureTypeEnum.SMS_TEMPLATE_PARAM_ERROR; case TPL_NOT_FOUND: return SmsSendFailureTypeEnum.SMS_TEMPLATE_NOT_EXISTS; - case TPL_NOT_VALID: return SmsSendFailureTypeEnum.SMS_TMPLATE_INVALID; + case TPL_NOT_VALID: return SmsSendFailureTypeEnum.SMS_TEMPLATE_INVALID; } return SmsSendFailureTypeEnum.SMS_UNKNOWN; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java index d014f5966..af29977fa 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java @@ -14,16 +14,19 @@ public enum SmsSendFailureTypeEnum { // ========== 渠道相关(100 开头) ========== SMS_CHANNEL_CLIENT_NOT_EXISTS(100, "短信渠道的客户端不存在"), + SMS_CHANNEL_API_KEY_MISSING(101, "API Key 不存在"), + SMS_CHANNEL_PERMISSION_DENY(102, "没有发送短信的权限"), // ========== 模板相关(200 开头) ========== SMS_TEMPLATE_NOT_EXISTS(200, "短信模板不存在"), SMS_TEMPLATE_DISABLE(201, "短信模板被禁用"), // 例如说,我们在管理后台禁用了 - SMS_TMPLATE_INVALID(202, "短信模板不可用"), // 例如说,短信模板正在审核中 + SMS_TEMPLATE_INVALID(202, "短信模板不可用"), // 例如说,短信模板正在审核中 SMS_TEMPLATE_PARAM_ERROR(203, "模板参数不正确"), // ========== 其它相关(900 开头) ========== SMS_API_PARAM_ERROR(900, "请求参数缺失"), + SMS_SEND_LIMIT_CONTROL(997, "业务限流"), // 将短信发送频率限制在正常的业务限流范围内。默认短信验证码:使用同一签名,对同一个手机号验证码,支持 1 条 / 分钟,5 条 / 小时,累计 10 条 / 天。 SMS_SEND_EXCEPTION(998, "发送异常"), SMS_UNKNOWN(999, "未知错误,需要解析") ; diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java new file mode 100644 index 000000000..b042365e4 --- /dev/null +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java @@ -0,0 +1,37 @@ +package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; + +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * {@link AliyunSmsClient} 的集成测试 + */ +public class AliyunSmsClientTest { + + @Test + public void testSend() { + // 创建配置类 + SmsChannelProperties properties = new SmsChannelProperties(); + properties.setId(1L); + properties.setSignature("Ballcat"); + properties.setCode(SmsChannelEnum.ALIYUN.getCode()); + properties.setApiKey(System.getenv("ALIYUN_ACCESS_KEY")); + properties.setApiSecret(System.getenv("ALIYUN_SECRET_KEY")); + // 创建客户端 + AliyunSmsClient smsClient = new AliyunSmsClient(properties); + smsClient.init(); + // 发送短信 + Map templateParams = new HashMap<>(); + templateParams.put("code", "1024"); +// templateParams.put("operation", "嘿嘿"); +// SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); + SmsResult result = smsClient.send(1L, "15601691399", "SMS_207945135", templateParams); + System.out.println(result); + } + +}