开发者学堂课程【全面讲解 Spring Cloud Alibaba 技术栈(知识精讲+项目实战)第四阶段:短信服务 Api 介绍】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/686/detail/11915
短信服务 Api 介绍
研究短信文档 Api 的使用,打开帮助文档。
有 SDK 参考新版、开发指南旧版,使用的是旧版文档。
需要关注的有两部分,第一部分是 API 文档,具体的定义了每个 API的详细参数以及返回值。
第二个是 SDK 以及 DEMO
如果 API 文档看不特别清楚,可以下载相关的 DEMO 进行查看。
首先来关注一下API文档,选择 Java,里面有 API 短信发送,短信查询,短信消息以及批量发送。
API文档
HTTP协议及签名
JAVA
短信发送APl(SendSms)-- -JAVA
短信查询
API(QuerySendDetalls)--- JAVA
短信消息API---JAVA
短信批量发送
API(SendBatchSms)
PHP
1、短信发送 API (SendSms)---Java
调用 SendSms 发送短信
(1)请求参数
第一部分是 API 的名称、怎么调用,第二部分是给 API 传递、打成参数,第三个是 API 会给哪些响应,如何根据响应来判断 API 是否调用成功,入参、出参就是返回值。
第一个是手机号,第二个是签名,第三个是模板 code 。
模板是取得模板 code 码,因为已经明确说明要的是 template code
最后一个叫 TemplateParam 模板参数,申请模板的时候常见模板库是有变量的,需要给变量传递实际的值,这是存在的意义,需要 JSON,调用方法需要传递的请求参数。
中间两个已经准备好,上面手机号和下面手机号需要用的时候再来准备好。
(2)返回数据
返回数据第一个叫回执的ID,也是短信发送以后在内部的流水号,可以关注也可以不关注,意义不是特别大。第二个是 Code 代码比较重要,OK 是成功,如果不是 OK 就有问题,Message 一般用在当出现错误的时候,根据具体的消息来判断错误原因。后边还有request ID 是请求时的一个内部的 ID 号,意义也不是特别大,主要关注的是 code 码和 message 码。
2、短信查询(QuerySendDetails)
调用 QuerySendDetails 接口查看短信发送记录和发送状态。
短信查询也有详细的介绍
(1)请求参数
前两个跟分页相关,短信查询会涉及到很多,手机号、发送时间还有流水号,流水号可以根据某一条流水具体查询一条短信,如果不想用流水号,可以用时间来查询,查询某一个时间段的短信。
(2)返回数据
返回数据里面前两个是返回的状态,下面是返回的具体信息,包括采购 ID,短信的明细还有一段时间发送的总条数,明细是一个数组,里面是一个个的发送出去短信的具体信息。
关于短信消息 API---Java、短信批量发送两个 API,可以参照学习方式了解。
3、功能测试
第1步:引入阿里云服务依赖
<!--短信发送-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alicloud-sms</artifactid>
</dependency>
第2步:使用阿里云提供的 Demo 测试短信发送
public class smsDemo {
//产品名称:云通信短信API产品,开发者无需替换
static final String product = "Dysmsapi";
//产品域名,开发者无需替换
static final String domain ="dysmsapi.aliyuncs.com";
//TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
static final string accessKeyId = "yourAccessKeyId";
static final string accessKeySecret="yourAccessKeySecret":
//产品名称:云通信短信 API 产品,开发者无需替换
static final String domain ="dysmsapi.aliyuncs.com".
//TODO 此处需要替换成开发者自己的 AK(在阿里云访问控制台寻找)
static final string accessKeyId ="yourAccesskeyId";
static final string accessKeySecret="yourAccessKeySecret":
//短信发送
public static SendSmsResponse sendSmsO throws
clientExcep tion {
//可自助调整超时时间
S
ystem.setProperty("sun.net.client.defaultConnectTimeout","10000");
System.setProperty("sun.net.client.defaultReadTimeout","10000");
//初始化 acsc1ient,暂不支持 region 化
IclientProfile profile =DefaultProfile.getProfile("cn-hangzhou ",accessKeyId,
accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou","cn-hangzhou",product,domain);
IAcsClient acsClient=new DefaultAcsClient(profile);
//组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request=newSendSmsRequest;
//必填:待发送手机号
request.setPhoneNumbers(
“
150000000”;)
//必填:短信签名-可在短信控制台中找到 request.setsignName("云通信");//必填:短信模板-可在短信控制台中找到
request.setTemplateCode("SMS_100000);
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时。此处的值为
request.setTemplateParam("{\"name":\"Tom ",\"code ": "123\"}");
//选填-上行短信扩展码(无特殊需求用户请忽略此字段)
//request.setSmsUpExtendCode("90997");
//可选:outid为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setoutId("youroutId");
//hint 此处可能会抛出异常.注意 catch
SendSmsResponse sendSmsResponse=acsclientqetAcsRespon
se(request);
return sendsmsResponse:
}
//短信查询
public static QuerySendDetailsResponse auerySendDetails
(Strina bizid) throws clientException{
//可自助调整超时时间
system.setProperty("sun.net.client.defaultConnectTimeout","10000");
System.setProperty("sun.net.client.defaultReadTimeout","10000");
//初始化 acsc1ient,暂不支持 region 化
IclientProfile profile=DefaultProfile.getProfile("cn-hangzhou",accessKeyId
accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou","cn-hangzhou",product,domain);
IAcsclient acsclient=newDefaultAcsClient(profile):
//组装请求对象
QuerySendDetailsRequest request=new
QuerySendDetailsReq
uest);
//必填-号码
request.setPhoneNumber(15000);
//可选-流水号
request.setBizId(bizId);
//必填-发送日期 支持30天内记录查询,格式yyyyMMdd
SimpleDateFormat
ft=newSimpleDateFormat("yyyyMMdd");
request.setSendDate(ft.format(newDate0));
//必填-页大小
request.setPageSize(10L);
//必填-当前页码从1开始计数
request.setCurrentPage(1L);
//hint 此处可能会抛出异常,注意 catch
QuerySendDetailsResponse querySendDetailsResponse
acsclient.getAcsResponse(request);
return querySendDetailsResponse;
}
public static void main(String[] args) throws
clientException, InterruptedException {
//发短信
SendSmsResponse response=sendSms);
System.out.print1n("短信接口返回的数据----------------");
System.outprint1n("Code="+responsegetCode());
system.out.print1n("Message="+response.getMessage());
System.out.print1n("RequestId="+response.getRequestIdo)
:System.outprint1n("BizId="+response.getBizIdO));
Thread.s1eep(3000L);
//查明细
if(response.getCode()!
=nu11&&responsegetCode().equa1s("OK")){
QuerySendDetailsResponse querySendDetailsResponse=
querySendDetails(responsegetBizId());
System.out.print1n("短信明细查询接口返回数据----------------");
System.out.print1n("Code="+querySendDetai1sResponsegetCode());
system.out.print1n("Message="+
querySendDetailsResponsegetMessage());
int i =0;
for(QuerySendDetai1sResponse.SmsSendDetai1DTO smsSendDetai1DTO:
querysendDetailsResponsegetSmsSendDetai1DTOs
(
))
{
System.out.print1n("SmsSendDetai1DTo["+i+"]:");
SystemLout.print1n("Content="+smsSendDetai1DTo.getContent());
System.out.print1n("ErrCode="+smsSendDetai1DOgetErrCode());
S
ystem.out.print1n("OutId="+
smsSendDetailDTo.getutid());
S
ystem.out.print1n("phoneNum="+
smsSendDetailDTOgetPhoneNum(());
System.out.print1n("ReceiveDate="+smsSendDetailo.aetReceiveDate)):
System.out.print1n("SendDate="+smsSendDetai1DogetsendDate());
System.out.print1n("Sendstatus="+smsSendDetailDo.getSendStatus()):
System.out.print1n("Template="+smsSendDetai1DTogetTemplateCode());}
System.out.print1n("TotalCount="+querySendDetai1sResponsegetTotalCount())
System.out.print1n("RequestId="+querySendDetailsResponsegetRequestid
(
));
}
}
}
Demo 来自 SDK 及 DEMO 下载,里面提供好了 Demo 案例,只需要下载对应的版本
找到用户微服务 pom.xml 加入依赖:
<groupid>org.springtramework.boot/groupia>
<artifactId>spring-boot-starter-web</artifactid>
</dependenay>
<!--shop-common-->
<dependenay>
<groupId>com.itheima</groupid>
<artifactId>shop-common</artifactid><version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupid>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactid
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactid<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmg</groupId><artifactId>rocketma-client</artifactId><version>4.4.0</version>
</dependency>
<!--短信发送-->
<dependency>
<groupId>com.alibaba.cloud</groupid>
<artifactId>spring-cloud-alicloud-sms</artifactid>
</dependenay>
</dependencies>
新建一个 Demo
import com.aliyuncs.DefaultAcsClient; import
com.alivuncs.
IAcsclient;
import
com.aliyuncs.dysmsapimodelv20170525.uerySendDetailsRequest;
import
com.aliyuncs.dysmsapi.modelv20170525.QuerySendD
etailsResponse
import
com.aliyuncs.dysmsapi.modelv20170525.SendSmsRequest
; import
com.aliyuncs.dysmsapi.model.v20170525.SendsmsR
esponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profileIclientProfile;
import iava.text.SimpleDateFormat;
public class SmsDemoTest {
//产品名称:云通信短信API产品,开发者无需替换
static final String product = "Dysmsapi";
//产品域名,开发者无需替换
static final String domain ="dysmsapi.aliyuncs.com";
//TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
static final string accessKeyId = "yourAccessKeyId";
static final string accessKeySecret="yourAccessKeySecret":
//产品名称:云通信短信 API 产品,开发者无需替换
static final String domain ="dysmsapi.aliyuncs.com".
//TODO 此处需要替换成开发者自己的 AK(在阿里云访问控制台寻找)
static final string accessKeyId ="yourAccesskeyId";
static final string accessKeySecret="yourAccessKeySecret":
//短信发送
public static SendSmsResponse sendSmsO throws
clientExcep tion {
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout","10000");
System.setProperty("sun.net.client.defaultReadTimeout","10000");
//初始化 acsc1ient,暂不支持 region 化
IclientProfile profile =DefaultProfile.getProfile("cn-hangzhou ",accessKeyId,
accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou","cn-hangzhou",product,domain);
IAcsClient acsClient=new DefaultAcsClient(profile);
//组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request=newSendSmsRequest;
//必填:待发送手机号
request.setPhoneNumbers(
“
150000000”;)
//必填:短信签名-可在短信控制台中找到 request.setsignName("云通信");//必填:短信模板-可在短信控制台中找到
request.setTemplateCode("SMS_100000);
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时。此处的值为
request.setTemplateParam("{\"name":\"Tom ",\"code ": "123\"}");
//选填-上行短信扩展码(无特殊需求用户请忽略此字段)
//request.setSmsUpExtendCode("90997");
//可选:outid为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setoutId("youroutId");
//hint 此处可能会抛出异常.注意 catch
SendSmsResponse
sendSmsResponse=acsclientqetAcsRespon
se(request);
return sendsmsResponse:
}
//短信查询
public static QuerySendDetailsResponse auerySendDetails
(Strina bizid) throws clientException{
//可自助调整超时时间
system.setProperty("sun.net.client.defaultConnectTimeout","10000");
System.setProperty("sun.net.client.defaultReadTimeout","10000");
//初始化 acsclient,暂不支持 region 化
IclientProfile profile=DefaultProfile.getProfile("cn-hangzhou",
accessKeyId
,
accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou","cn-hangzhou",product,domain);
Acsclient acsclient=newDefaultAcsClient(profile):
//组装请求对象
QuerySendDetailsRequest request=new QuerySendDetailsReq
uest);
//必填-号码
request.setPhoneNumber(15000);
//可选-流水号
request.setBizId(bizId);
//必填-发送日期 支持30天内记录查询,格式yyyyMMdd
SimpleDateFormat ft=newSimpleDateFormat("yyyyMMdd");
request.setSendDate(ft.format(newDate
(
));
//必填-页大小
request.setPageSize(10L);
//必填-当前页码从1开始计数
request.setCurrentPage(1L);
//hint 此处可能会抛出异常,注意 catch
QuerySendDetailsResponse querySendDetailsResponse
acscli
ent.getAcsResponse(request);
return querySendDetailsResponse;
}
public static void main(String[] args) throws
clientException, InterruptedException {
//发短信
SendSmsResponse response=sendSms);
System.out.print1n("短信接口返回的数据----------------");
System.outprint1n("Code="+responsegetCode());
system.out.print1n("Message="+response.getMessage());
System.out.print1n("RequestId="+response.getRequestIdo)
:System.outprint1n("BizId="+response.getBizIdO));
Thread.s1eep(3000L);
//查明细
if(response.getCode()!
=nu11&&responsegetCode().equa1s("OK")){
QuerySendDetailsResponse querySendDetailsResponse=
querySendDetails(responsegetBizId());
System.out.print1n("短信明细查询接口返回数据----------------");
System.out.print1n("Code="+querySendDetai1sResponsegetCode());
system.out.print1n("Message="+
querySendDetailsResponsegetMessage());
int i =0;
for(QuerySendDetai1sResponse.SmsSendDetai1DTO
smsSendDetai1DTO:
querysendDetailsResponsegetSmsSendDetai1DTOs
(
))
{
System.out.print1n("SmsSendDetai1DTo["+i+"]:");
SystemLout.print1n("Content="+smsSendDetai1DTo.getContent());
System.out.print1n("ErrCode="+smsSendDetai1DOgetErrCode());
S
ystem.out.print1n("OutId="+
smsSendDetailDTo.getutid());
S
ystem.out.print1n("phoneNum="+smsSendDetailDTOgetPhoneNum(());
System.out.print1n("ReceiveDate="+smsSendDetailo.aetReceiveDate)):
System.out.print1n("SendDate="+smsSendDetai1DogetsendDate());
System.out.print1n("Sendstatus="+smsSendDetailDo.getSendStatus()):
System.out.print1n("Template="+smsSendDetai1DTogetTemplateCode());}
System.out.print1n("TotalCount="+querySendDetai1sResponsegetTotalCount())
System.out.print1n("RequestId="+querySendDetailsResponsegetRequestid
(
));
}
}
}
第一个是短信发送,第二个是短信查询,有几个变量需要注意,前两个变量是阿里云内部的一些东西,不需要改默认就可以,下边两个是认证的密钥、ID以及密钥,做申请的时候申请了三部分东西,只用到了两个,第一个认证秘钥没有使用
可以通过输入手机号显示出来,把一对密钥拷过来,然后把一段替换掉就可以,一定替换成自己的。
接下来是发送短信,发送短信需要大家填入的东西都在一块,手机号填一下、模板的 code 填一下,签名填,需要设置的模板里面的参数,比如 code 代码需要自己写一下,主要替换掉就可以其他的不用管,这是短信发送 API 的使用,接下来短信查询也很简单的,提供了一个参数,按照要按照流水 ID查,不想用流水 ID 查,可以通过手机号、时间段进行简修改解锁条件。
4、下单之后发送短信
(1)在shop-user模块中加入sms依赖
<!--短信发送-->
<dependency>
<groupId>com.alibaba.cloud</groupid>
<artifactId>spring-cloud-alicloud-sms</artifactid></
dependency>
(2)将阿里短信给出的 demo 封装成工具类
public class Smsutil {
//替换成自己申请的accessKeyId
private static string accessKeyId ="LTAIML1f8NKYXn1M";//
替换成自己申请的accessKeySecret
private statiq string accesskeysecret =
"hqyw0zTNzeSIFnZhM
EkOazxvvcr3Gj";
static final string product = "Dysmsapi";
static final string domain ="dysmsapi.aliyuncs.com";
/**
*发送短信
*
* @param phoneNumbers 要发送短信到哪个手机号
*
@
param signName 短信签名[必须使用前面申请的]
*
@
param templateCode 短信短信模板
ID[必须使用前面申请的]
*@param param 模板中${
code
}位置传递的内容
*/
public static void sendsms(string phoneNumbers, String
signName, String templateCode, String param) {
try {
System.setProperty("sun.net.client.defaultConnectTimeout","10000");
System.setProperty("sun.net.client.defaultReadTimeout","10000");
//初始化
acsclient,暂不支持
region
化
I
clientProfile profile =DefaultProfile.getProfile("cn-hangzhou",
accesskeyId,accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou"."cn-hangzhou".product.domain):
IAcsclient acsclient=newDefaultAcsclient(profile);
SendSmsRequest request=new SendSmsRequest);
request.setPhoneNumbers(phoneNumbers); request.setsignName(signName);
request.setTemplateCode(templateCode);
request.setTemplateParam(param);
request.setoutId("yourOutId");
SendSmsResponse
sendSmsResponse=acsc1ientgetAcsRespo
nse(request);
if (!"ok".equa1s(sendSmsResponse.getCode())){
throw new
RuntimeException(sendSmsResponsegetMessage
());}
} catch (Exception e) {
e.printstackTrace
();
throw new RuntimeException("发送短信失败")
;
}
}
}
(3)修改短信发送的服务
//发送短信的服务
@s1f4j
@Service
@RocketMQMessageListener(consumerGroup ="shop",topic = "order-topic")
public class SmsService implements RocketMQListener<Ord er>{
@Override
public void onMessage(Order order){
log.info("收到一个订单信息{},接下来发送短信",
JSON.toJSONString(order));
//这里可以调用 userDao 查询出 user 的 telephone
SmsUti1.sendSms("telephone","黑马旅游网","SMS_170836451 ","{\"code\":\"验证码
\"}");
}
}
拷过来,新建一个工具类放在 user 里面,new 一个包
包里面放一个 Sms
package com.itheima.utils;
import com.aliyuncs.DefaultAcsClient;
importcom.aliyuncs.IAcsclient;
import
com.alivuncs.dvsmsapimodel.v20170525.SendmsRec
uest;
import
com.aliyuncs.dysmsapimodelv20170525.SendSmsResp
onse;
import com.aliyuncs.profile.DefaultProfile
;
import com.aliyuncs.profile.IclientProfile;
@slf4j
public class Smsutil {
//替换成自己申请的accessKeyId
private static string accessKeyId ="LTAIML1f8NKYXn1M";//
替换成自己申请的accessKeySecret
private statiq string accesskeysecret =
"hqyw0zTNzeSIFnZhM
EkOazxvvcr3Gj";
static final string product = "Dysmsapi";
static final string domain ="dysmsapi.aliyuncs.com";
/**
*发送短信
*
* @param phoneNumbers 要发送短信到哪个手机号
*
@
param signName 短信签名[必须使用前面申请的]
*
@
param templateCode 短信短信模板
ID[必须使用前面申请的]
*@param param 模板中${
code
}位置传递的内容
*/
public static void sendsms(string phoneNumbers, String
signName, String templateCode, String param) {
try {
System.setProperty("sun.net.client.defaultConnectTimeout","10000");
System.setProperty("sun.net.client.defaultReadTimeout","10000");
//初始化
acsclient,暂不支持
region
化
I
clientProfile profile =DefaultProfile.getProfile("cn-hangzhou",
accesskeyId,accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou"."cn-hangzhou".product.domain):
IAcsclient acsclient=newDefaultAcsclient(profile);
SendSmsRequest request=new SendSmsRequest);
request.setPhoneNumbers(phoneNumbers);
request.setsignName(signName);
request.setTemplateCode(templateCode);
request.setTemplateParam(param);
request.setoutId("yourOutId");
SendSmsResponse
sendSmsResponse=acsc1ientgetAcsRespo
nse(request);
if (!"ok".equa1s(sendSmsResponse.getCode())){
log.info(“发送短信失败,{},
sendSmsResponse
);
throw new
RuntimeException(sendSmsResponsegetMessage
());
}
} catch (Exception e) {
log.info(“发送短信失败,{},e);
throw new RuntimeException("发送短信失败")
;
}
}
}
把发送短信的 API 进行了抽取,因为本次要演示的只有发送,而对于查询可以自己去抽取一下,把必须要填的或者查询条件放在位置,上面有标识,要看发送到哪个手机号,短信签名是社么,短信模板是什么以及模板要传递的内容是什么,把规定查询的参数往上翻,把这些东西变成了一些参数放在方法请求里面,如果返回值不是 OK 直接抛了一个异常,如果比较正规的话里面要打一个日志出来,如果发送成功没有任何异常触发。
第一个把密钥替换成自己的,第二个是要调用方法把四个参数传进来,四个参数手机号自己定、签名用申请的模板、param 自己定。