本文导读
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 |
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 依赖,如下:
1 2 3 4 5 |
<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 176 177 178 |
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.ap-southeast-1.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 = {}; * 单变量模板示例:模板内容为"您的验证码是${NUM_6}"时,templateParas可填写为{"111111"} * 双变量模板示例:模板内容为"您有${NUM_2}件快递请到${TXT_20}领取"时,templateParas可填写为{"3","人民公园正门"} * ${DATE}${TIME}变量不允许取值为空,${TXT_20}变量可以使用英文空格或点号替代空值,${NUM_6}变量可以使用0替代空值 * 查看更多模板和变量规范:产品介绍>模板和变量须知 */ 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); } } |
父主题: 特殊AK/SK认证(推荐)