所需的官方文档
开头先放所需的官方文档的链接汇总,方便查看,下面用到时也会重新放。
- https://support.huaweicloud.com/devg-apisign/api-sign-sdk-java.html
- https://support.huaweicloud.com/api-msgsms/sms_05_0001.html
发送短信的api接口文档(可查看错误码) - https://support.huaweicloud.com/devg-msgsms/sms_04_0018.html
发送短信代码示例(截止到24年8月初,华为云官方公告没有发送短信的sdk,所以只能看这个) - https://support.huaweicloud.com/productdesc-msgsms/sms_faq_0003.html
短信变量规范 - https://console.huaweicloud.com/apiexplorer/#/openapi/MSGSMS/doc?api=CreateTemplate
在线调试,但目前上面只有应用,签名,模板
数据准备
先登录华为云准备以下数据(签名审核时间较长,3个工作日以内;另外华为云想发通知类型短信和验证码类型短信需要两个不同的签名;阿里云是一个签名通用)
截图网页来源:https://support.huaweicloud.com/devg-msgsms/sms_04_0006.html
发送短信
public class HuaweiyunSendSms {
static final String url = "";
static final String appKey = "";
static final String appSecret = "";
//通知类签名通道号
static final String senderNotice = "";
//验证码类签名通道号
static final String senderCode = "";
//签名名称
static final String signature = "";
private static final Logger LOGGER = LoggerFactory.getLogger(HuaweiyunSendSms.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();
}*/
/**
* 调用短信
* @param receiver 接收短信手机号
* @param sender 中国大陆短信签名通道号或全球短信通道号
* @param signature 签名名称
* @param templateId 模板ID
* @param templateParas 模板参数
* @throws Exception
* @return s 发送短信的结果
*/
private static String sendSms(String receiver, String sender, String signature, String templateId, String templateParas) throws Exception {
receiver = "+86" + receiver;
//源头传的是阿里云的param,所以这里处理成华为云的
/*templateParas = HwyTemplate.getHwyParamsById(templateId,templateParas);
templateParas = HwyTemplate.updateHwyParams(templateParas);*/
client = createIgnoreSSLHttpClient();
/*//必填,请参考"开发准备"获取如下数据,替换为实际值
String url = "https://smsapi.cn-north-4.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 null;
}
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, "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) {
String s = EntityUtils.toString(resEntity, "UTF-8");
LOGGER.info("Processing Body with name: {} and value: {}", System.getProperty("line.separator"),
s);
return s;
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
return null;
}
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));
}
}
上面的代码是从官方给的代码示例里改了一点点。把一些参数提出来,更方便调用。此外加了个返回值,返回官方示例那种的响应结果,示例:
{
"result": [
{
"originTo": "+86155****5678",
"createTime": "2018-05-25T16:34:34Z",
"from": "1069********0012",
"smsMsgId": "d6e3cdd0-522b-4692-8304-a07553cdf591_8539659",
"status": "000000",
"countryId": "CN",
"total": 2
}
],
"code": "000000",
"description": "Success"
}
代码改造的来源:
https://support.huaweicloud.com/devg-msgsms/sms_04_0018.html#ZH-CN_TOPIC_0000001606982993__section12610871145
注意事项
参数
华为云短信的电话号码是需要“+86”的,我改后的代码方法中已经加上了。
华为云短信的变量格式与阿里云不同。
华为云是["value1","value2","value3"]
这样一个带中括号的字符串(注意顺序要和模板中的顺序一致)
而阿里云是{"key1":"value1","key2":"value2","key3":"value3}
这样的json字符串。
华为云中yyyy-MM-dd HH:mm:ss这样的日期格式必须分成两个变量来传递。阿里云的一个就可以。
暂时列出这些,详见官方的变量规范文档。
依赖问题
复制完官方给的代码,你会发现没有依赖。最后我是从这个里面找到了一个jar包。
此时可以按官方给的来导入
<dependency>
<!-- 使用时替换为实际路径-->
<systemPath>${project.basedir}/libs/java-sdk-core-XXX.jar</systemPath>
<groupId>com.huawei.apigateway</groupId>
<artifactId>java-sdk-core</artifactId>
<version>SDK版本号</version>
<scope>system</scope>
</dependency>
但是后来编译时过不去,只能又本地安装了一下。
maven本地安装
找到自己Maven的路径,按照图示路径放入jar包
然后在该路径下cmd
执行一段命令
mvn install:install-file -Dfile=java-sdk-core-3.2.5.jar -DgroupId=com.huawei.apigateway -DartifactId=java-sdk-core -Dversion=3.2.5 -Dpackaging=jar
最后把依赖改了就好了
<dependency>
<groupId>com.huawei.apigateway</groupId>
<artifactId>java-sdk-core</artifactId>
<version>3.2.5</version>
</dependency>
发送短信中其他的问题
如果你复制的不是我改之后的代码,而是官方给的代码,即使按照上面的方法添加了依赖,还是会发现少依赖,少了某个常量值。
我的解决方法:还是从下载的示例里找到那个文件,手动把常量值粘贴过来。
获取模板详情的坑
这个接口有个坑,官方提示的是传入模板id,我怎么传怎么错。
后来发现其实应该传入的是模板主键id,这里官方提示有误。