liusheng
2026-10-10 0afac42fb2e9d6e5291304dd0044ce3042b45d2b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package com.ruoyi.message.sms.provider.aliyun;
 
import com.aliyun.dysmsapi20170525.models.SendSmsResponseBody;
import com.ruoyi.message.MessageChannel;
import com.ruoyi.message.SendResult;
import com.ruoyi.message.sms.AbstractSmsSender;
import com.ruoyi.message.sms.SmsSendRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
 
/**
 * 阿里云短信发送方({@code aliyun} 通道)。
 * <p>
 * 对接特征:阿里云 dysmsapi SDK,{@code SignName + TemplateCode + TemplateParam},
 * 成功判定为响应 {@code Code == "OK"}。
 * <p>
 * 说明:该通道目前只在 {@code BaseSmsaccountServiceImpl}(短信账号/模板管理)里使用,
 * 业务发送流程未走它。收口后可由工厂统一调度。
 */
@Slf4j
@Component
public class AliYunSmsSender extends AbstractSmsSender {
 
    /**
     * 渠道 key
     */
    public static final String KEY = "aliyun";
 
    private final AliYunSmsApi aliYunSmsApi;
 
    public AliYunSmsSender(AliYunSmsApi aliYunSmsApi) {
        this.aliYunSmsApi = aliYunSmsApi;
    }
 
    @Override
    public String key() {
        return KEY;
    }
 
    @Override
    public String description() {
        return "阿里云短信(dysmsapi,模板化)";
    }
 
    @Override
    protected SendResult doSend(SmsSendRequest request) {
        //阿里云短信不走内容直发,而是 模板编码 + 模板参数
        SendSmsRequestAdapter adapter = new SendSmsRequestAdapter(request);
        if (adapter.templateParam == null) {
            return SendResult.fail(KEY, MessageChannel.SMS, "短信模板参数为空", null);
        }
 
        SendSmsResponseBody body = aliYunSmsApi.sendSms(
                adapter.phone, adapter.templateCode, adapter.templateParam);
        if (body == null) {
            return SendResult.fail(KEY, MessageChannel.SMS, "短信发送失败", null);
        }
        log.info("【{}】阿里云短信发送结果:code={}, message={}", KEY, body.getCode(), body.getMessage());
        if ("OK".equals(body.getCode())) {
            return SendResult.success(KEY, MessageChannel.SMS, body.getMessage())
                    .withCode(body.getCode())
                    .withMessage(body.getBizId());
        }
        return SendResult.fail(KEY, MessageChannel.SMS, body.getMessage(), body.getMessage())
                .withCode(body.getCode());
    }
 
    /**
     * 绕过基类「内容不能为空」的校验:阿里云用模板参数,不用 content 直发。
     */
    @Override
    public SendResult send(SmsSendRequest request) {
        if (request == null || request.getPhone() == null || request.getPhone().trim().isEmpty()) {
            return SendResult.fail(KEY, MessageChannel.SMS, "手机号为空", null);
        }
        try {
            return doSend(request);
        } catch (Exception e) {
            log.error("【{}】阿里云短信发送异常:{}", KEY, e.getMessage(), e);
            return SendResult.fail(KEY, MessageChannel.SMS, "短信发送异常:" + e.getMessage(), null);
        }
    }
 
    /**
     * 小适配器:把统一入参映射成阿里云需要的三个字段。
     * <p>
     * 兼容旧调用方({@code BaseSmsRequest})传参习惯:手机号走 {@code phone},
     * 模板编码/参数走 {@code templateCode} / {@code templateParam}。
     */
    private static final class SendSmsRequestAdapter {
        private final String phone;
        private final String templateCode;
        private final String templateParam;
 
        private SendSmsRequestAdapter(SmsSendRequest request) {
            this.phone = request.getPhone();
            this.templateCode = request.getTemplateCode();
            this.templateParam = request.getTemplateParam() != null
                    ? request.getTemplateParam()
                    : request.getContent();
        }
    }
}