更新时间:2023-11-17 GMT+08:00
分享

Java

参考API签名SDK与demo,点击下载其中的SDK与Demo。将下列代码样例复制到新建java文件中即可运行。

  • 发送短信为单模板群发短信示例,发送分批短信为多模板群发短信示例。
  • 本文档所述Demo在提供服务的过程中,可能会涉及个人数据的使用,建议您遵从国家的相关法律采取足够的措施,以确保用户的个人数据受到充分的保护。
  • 本文档所述Demo仅用于功能演示,不允许客户直接进行商业使用。
  • 本文档信息仅供参考,不构成任何要约或承诺。

发送短信示例

  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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import com.huawei.apig.sdk.util.Constant;

import com.cloud.apigateway.sdk.utils.Client;
import com.cloud.apigateway.sdk.utils.Request;
import com.huawei.apig.sdk.util.Constant;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;

public class SendSms {

    private static final Logger LOGGER = LoggerFactory.getLogger(SendSms.class);

    public static final String UTF_8 = "UTF-8";

    private static CloseableHttpClient client =  null;

    public static void main(String[] args) throws Exception {
        // 为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题
        client = createIgnoreSSLHttpClient();
        sendSms();
    }

    private static void sendSms() throws IOException {
        //必填,请参考"开发准备"获取如下数据,替换为实际值
        String url = "https://smsapi.ap-southeast-1.myhuaweicloud.com:443/sms/batchSendSms/v1"; //APP接入地址+接口访问URI
        // 认证用的appKey和appSecret硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全;
        String appKey = "c8RWg3gg************3Y7x1Ile"; //Application Key
        String appSecret = "q4Ii87Bh************80SfD7Al"; //Application Secret
        String sender = "csms12345678"; //中国大陆短信签名通道号或全球短信通道号
        String templateId = "8ff55eac1d0b478ab3c06c3c6a492300"; //模板ID

        //条件必填,中国大陆短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称
        //全球短信不用关注该参数
        String signature = "华为云短信测试"; //签名名称

        //必填,全局号码格式(包含国家码),示例:+86151****6789,多个号码之间用英文逗号分隔
        String receiver = "+86151****6789,+86152****7890"; //短信接收人号码

        //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
        String statusCallBack = "";

        /**
         * 选填,使用无变量模板时请赋空值 String templateParas = "";
         * 单变量模板示例:模板内容为"您的验证码是${NUM_6}"时,templateParas可填写为"[\"111111\"]"
         * 双变量模板示例:模板内容为"您有${NUM_2}件快递请到${TXT_20}领取"时,templateParas可填写为"[\"3\",\"人民公园正门\"]"
         * 查看更多模板规范和变量规范:产品介绍>短信模板须知和短信变量须知
         */
        String templateParas = "[\"111111\"]"; //模板变量,此处以单变量验证码短信为例,请客户自行生成6位验证码,并定义为字符串类型,以杜绝首位0丢失的问题(例如:002569变成了2569)。

        //请求Body,不携带签名名称时,signature请填null
        String body = buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, signature);
        if (null == body || body.isEmpty()) {
            LOGGER.warn("body is null.");
            return;
        }

        Request request = new Request();
        request.setKey(appKey);
        request.setSecret(appSecret);
        request.setMethod("POST");
        request.setUrl(url);
        request.addHeader("Content-Type", "application/x-www-form-urlencoded");
        request.setBody(body);
        LOGGER.info("Print the body: {}", body);

        try {
            HttpRequestBase signedRequest = Client.sign(request, Constant.SIGNATURE_ALGORITHM_SDK_HMAC_SHA256);
            LOGGER.info("Print the authorization: {}", Arrays.toString(signedRequest.getHeaders("Authorization")));
            Header[] requestAllHeaders = signedRequest.getAllHeaders();
            for (Header h : requestAllHeaders) {
                LOGGER.info("req Header with name: {} and value: {}", h.getName(), h.getValue());
            }

            HttpResponse response = client.execute(signedRequest);

            LOGGER.info("Print the status line of the response: {}", response.getStatusLine().toString());
            Header[] resHeaders = response.getAllHeaders();
            for (Header h : resHeaders) {
                LOGGER.info("Processing Header with name: {} and value: {}", h.getName(), h.getValue());
            }
            HttpEntity resEntity = response.getEntity();
            if (resEntity != null) {
                LOGGER.info("Processing Body with name: {} and value: {}", System.getProperty("line.separator"),
                    EntityUtils.toString(resEntity, "UTF-8"));
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    public static CloseableHttpClient createIgnoreSSLHttpClient() throws Exception {
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (x509CertChain, authType) -> true).build();
        return HttpClients.custom().setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)).build();
    }

    static String buildRequestBody(String sender, String receiver, String templateId, String templateParas,
                                   String statusCallBack, String signature) throws UnsupportedEncodingException {
        if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty()
            || templateId.isEmpty()) {
            System.out.println("buildRequestBody(): sender, receiver or templateId is null.");
            return null;
        }

        StringBuilder body = new StringBuilder();
        appendToBody(body, "from=", sender);
        appendToBody(body, "&to=", receiver);
        appendToBody(body, "&templateId=", templateId);
        appendToBody(body, "&templateParas=", templateParas);
        appendToBody(body, "&statusCallback=", statusCallBack);
        appendToBody(body, "&signature=", signature);
        return body.toString();
    }

    private static void appendToBody(StringBuilder body, String key, String val) throws UnsupportedEncodingException {
        if (null != val && !val.isEmpty()) {
            LOGGER.info("Print appendToBody: {}:{}", key, val);
            body.append(key).append(URLEncoder.encode(val, UTF_8));
        }
    }
}

发送分批短信示例

需额外引入maven 依赖:

        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20180130</version>
        </dependency>

  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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
import com.huawei.apig.sdk.util.Constant;

import com.cloud.apigateway.sdk.utils.Client;
import com.cloud.apigateway.sdk.utils.Request;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SendDiffSms {
    private static final Logger LOGGER = LoggerFactory.getLogger(SendDiffSms.class);

    private static CloseableHttpClient client =  null;

    public static void main(String[] args) throws Exception {
        // 为防止因HTTPS证书认证失败造成API调用失败,需要先忽略证书信任问题
        client = createIgnoreSSLHttpClient();
        sendSms();
    }

    private static void sendSms() throws IOException {
        //必填,请参考"开发准备"获取如下数据,替换为实际值
        String url
            = "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendDiffSms/v1"; //APP接入地址(在控制台"应用管理"页面获取)+接口访问URI
        // 认证用的appKey和appSecret硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全;
        String appKey = "c8RWg3gg************3Y7x1Ile"; //APP_Key
        String appSecret = "q4Ii87Bh************80SfD7Al"; //APP_Secret
        String sender = "csms12345678"; //国内短信签名通道号或国际/港澳台短信通道号
        String templateId1 = "8ff55eac1d0b478ab3c06c3c6a492300"; //模板ID1
        String templateId2 = "8ff55eac1d0b478ab3c06c3c6a492300"; //模板ID2

        //条件必填,国内短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称
        //国际/港澳台短信不用关注该参数
        String signature1 = "华为云短信测试"; //签名名称1
        String signature2 = "华为云短信测试"; //签名名称2

        //必填,全局号码格式(包含国家码),示例:+86151****6789,多个号码之间用英文逗号分隔
        String[] receiver1 = {"+86151****6789", "+86152****7890"}; //模板1的接收号码
        String[] receiver2 = {"+86151****6789", "+86152****7890"}; //模板2的接收号码

        //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
        String statusCallBack = "";

        /**
         * 选填,使用无变量模板时请赋空值 String[] templateParas = {};
         * 单变量模板示例:模板内容为"您的验证码是${1}"时,templateParas可填写为{"111111"}
         * 双变量模板示例:模板内容为"您有${1}件快递请到${2}领取"时,templateParas可填写为{"3","人民公园正门"}
         * 查看更多模板规范和变量规范:产品介绍>短信模板须知和短信变量须知
         */
        String[] templateParas1 = {
            "123456"
        }; //模板1变量,此处以单变量验证码短信为例,请客户自行生成6位验证码,并定义为字符串类型,以杜绝首位0丢失的问题(例如:002569变成了2569)。
        String[] templateParas2 = {
            "234567"
        }; //模板2变量,此处以单变量验证码短信为例,请客户自行生成6位验证码,并定义为字符串类型,以杜绝首位0丢失的问题(例如:002569变成了2569)。

        //smsContent,不携带签名名称时,signature请填null
        List<Map<String, Object>> smsContent = new ArrayList<Map<String, Object>>();
        Map<String, Object> item1 = initDiffSms(receiver1, templateId1, templateParas1, signature1);
        Map<String, Object> item2 = initDiffSms(receiver2, templateId2, templateParas2, signature2);
        if (null != item1 && !item1.isEmpty()) {
            smsContent.add(item1);
        }
        if (null != item2 && !item2.isEmpty()) {
            smsContent.add(item2);
        }

        //请求Body
        String body = buildRequestBody(sender, smsContent, statusCallBack);
        if (null == body || body.isEmpty()) {
            System.out.println("body is null.");
            return;
        }

        Request request = new Request();
        request.setKey(appKey);
        request.setSecret(appSecret);
        request.setMethod("POST");
        request.setUrl(url);
        request.addHeader("Content-Type", "application/json");
        request.setBody(body);
        LOGGER.info("Print the body: {}", body);

        try {
            // Sign the request.
            HttpRequestBase signedRequest = Client.sign(request, Constant.SIGNATURE_ALGORITHM_SDK_HMAC_SHA256);
            // Print request header parameters: Authorization
            LOGGER.info("Print the allHeaders: {}", Arrays.toString(signedRequest.getAllHeaders()));
            HttpResponse response = client.execute(signedRequest);
            // Print the status line of the response.
            LOGGER.info("Print the status line of the response: {}", response.getStatusLine().toString());
            // Print the header fields of the response.
            Header[] resHeaders = response.getAllHeaders();
            for (Header h : resHeaders) {
                LOGGER.info("Processing Header with name: {} and value: {}", h.getName(), h.getValue());
            }
            // Print the body of the response.
            HttpEntity resEntity = response.getEntity();
            if (resEntity != null) {
                LOGGER.info("Processing Body with name: {} and value: {}", System.getProperty("line.separator"),
                    EntityUtils.toString(resEntity, "UTF-8"));
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    public static CloseableHttpClient createIgnoreSSLHttpClient() throws Exception {
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null,  (x509CertChain, authType) -> true).build();
        return HttpClients.custom().setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)).build();
    }

    static String buildRequestBody(String sender, List<Map<String, Object>> smsContent, String statusCallBack) {
        if (null == sender || null == smsContent || sender.isEmpty() || smsContent.isEmpty()) {
            System.out.println("buildRequestBody(): sender or smsContent is null.");
            return null;
        }
        JSONArray jsonArr = new JSONArray();

        for (Map<String, Object> it : smsContent) {
            jsonArr.put(it);
        }

        Map<String, Object> data = new HashMap<String, Object>();
        data.put("from", sender);
        data.put("smsContent", jsonArr);
        if (null != statusCallBack && !statusCallBack.isEmpty()) {
            data.put("statusCallback", statusCallBack);
        }

        return new JSONObject(data).toString();
    }

    /**
     * 构造smsContent参数值
     */
    static Map<String, Object> initDiffSms(String[] receiver, String templateId, String[] templateParas,
        String signature) {
        if (null == receiver || null == templateId || receiver.length == 0 || templateId.isEmpty()) {
            System.out.println("initDiffSms(): receiver or templateId is null.");
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("to", receiver);
        map.put("templateId", templateId);
        if (null != templateParas && templateParas.length > 0) {
            map.put("templateParas", templateParas);
        }
        if (null != signature && !signature.isEmpty()) {
            map.put("signature", signature);
        }

        return map;
    }

}

接收状态报告

需要引入的maven依赖为:org.springframework:spring-web:5.3.21(样例版本)

 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
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {
    /**
     * 同步短信回执
     */
    @PostMapping("/report")
    public void smsHwReport(@RequestParam String smsMsgId,  //	发送短信成功时返回的短信唯一标识。
                            @RequestParam(required = false) String total,     //	长短信拆分后的短信条数。当短信未拆分时该参数取值为1。
                            @RequestParam(required = false) String sequence,  //	长短信拆分后的短信序号,当total参数取值大于1时,该参数才有效。当短信未拆分时该参数取值为1。
                            @RequestParam String status,    //	短信状态报告枚举值,常见取值请参考“API参考”
                            @RequestParam(required = false) String source,    //	短信状态报告来源:1:短信平台自行产生的状态报告。2:短信中心返回的状态报告。3:华为平台产生的状态报告。
                            @RequestParam(required = false) String updateTime,//	短信资源的更新时间,通常为短信平台接收短信状态报告的时间,为UTC时间,格式为:yyyy-MM-dd'T'HH:mm:ss'Z',该时间会通过urlencode转义为%3a。//	当短信平台未收到短信中心上报的状态报告时,会自行构造状态报告,该状态报告中不携带“updateTime”参数。
                            @RequestParam(required = false) String orgCode,   //	透传南向网元状态码,仅国际/港澳台短信状态报告携带,国内短信不涉及。//	当南向网元未返回状态码时不携带该参数。
                            @RequestParam(required = false) String extend,    //	扩展字段,由用户在发送短信的请求中携带。若用户发送短信时未携带extend参数,则状态报告中也不会携带extend参数。
                            @RequestParam(required = false) String to) {      //	本条状态报告对应的短信的接收方号码,仅当状态报告中携带了extend参数时才会同时携带该参数。
        System.out.println("  ================receive smsStatusReport ======================");
        System.out.println("smsMsgId: " + smsMsgId);
        System.out.println("total: " + total);
        System.out.println("sequence: " + sequence);
        System.out.println("status: " + status);
        System.out.println("source: " + source);
        System.out.println("updateTime: " + updateTime);
        System.out.println("orgCode: " + orgCode);
        System.out.println("extend: " + extend);
        System.out.println("to: " + to);
    }
}

接收上行短信

需要引入的maven依赖为:org.springframework:spring-web:5.3.21(样例版本)

 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
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PostMapping;

@RestController
public class DemoController {
     /*
     * @param smsMsgId   上行短信的唯一标识。
     * @param from       上行短信发送方的号码。
     * @param to         上行短信接收方的号码。
     * @param body       上行短信发送的内容。
     * @param createTime //	上行短信创建时间,即短信平台接收到用户发送的上行短信的时间(采用标准UTC格式,例如:2018-02-12T15:30:20Z。不同编程语言中的时间格式转换方式不同,部分语言可参考表 不同编程语言的时间格式)。
     *                   //	在控制台创建应用时配置需要“接收上行短信回复时间”后,平台才会在Body中附带此字段,该字段只对http协议的短信生效。
     */
    @PostMapping("/upSMS")
    public void receiveHwSms(@RequestParam String smsMsgId,
                             @RequestParam String from,
                             @RequestParam String to,
                             @RequestParam String body,
                             @RequestParam(required = false) String createTime) {
        System.out.println("  ================receive upSMS ======================");
        // 打印上面的RequestParam
        System.out.println("  smsMsgId: " + smsMsgId);
        System.out.println("  from: " + from);
        System.out.println("  to: " + to);
        System.out.println("  body: " + body);
        System.out.println("  createTime: " + createTime);
    }
}

分享:

    相关文档

    相关产品