第一步、准备工作
1、登录阿里云,完成认证
注意,推广短信只有升级为企业认证之后才可启用
2、开通短信服务
搜索短信服务产品
3、充值余额或购买短信包
第二步、配置签名和模板(可选)
如果签名和模板是固定的,并不需要在自己的系统中进行配置的话,可以在阿里云上直接配置
第三步、代码集成
1、API文档
https://help.aliyun.com/document_detail/101300.html?spm=5176.12207334.0.0.14dd1cbeCdW42y
2、通过阿里云提供的OpenAPI Explorer,可以方便地生成SDK代码示例
3、发送短信(以Spring Boot项目为例)
阿里的发送短信接口分为两种:SendSms和SendBatchSms
SendSms接口支持在一次请求中向多个不同的手机号码发送同样内容的短信。
SendBatchSms接口支持一次请求中分别向多个不同的手机号码发送不同签名和模版内容的短信
PS:具体的入参和返回数据含义请查看文档
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
/*
pom.xml
com.aliyun
aliyun-java-sdk-core
4.0.3
*/
public class SendSms {
public static void main(String[] args) {
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "", "");
IAcsClient client = new DefaultAcsClient(profile);
CommonRequest request = new CommonRequest();
request.setSysMethod(MethodType.POST);
request.setSysDomain("dysmsapi.aliyuncs.com");
request.setSysVersion("2017-05-25");
request.setSysAction("SendSms");
request.putQueryParameter("RegionId", "cn-hangzhou");
request.putQueryParameter("PhoneNumbers", "号码一,号码二");
//指第二步中配置的签名,在签名名称一列查看。必须是已添加、并通过审核的短信签名
request.putQueryParameter("SignName", "签名");
//指第二步中配置的模板,模板CODE一列查看。必须是已添加、并通过审核的短信签名
request.putQueryParameter("TemplateCode", "短信模板Code");
//模板变量(可选)
//假设模板内容为: 尊敬的会员你好,本店将于${date}举办会员日活动,欢迎大家前来体验
//那么TemplateParam变量的值就应该为: {"date": "2020年5月1日"}
request.putQueryParameter("TemplateParam", "模板变量对应的实际值,以JSON格式传值");
try {
CommonResponse response = client.getCommonResponse(request);
//返回的是一个JSON字符串,根据Code属性是否为OK可以判断请求是否发送成功
String data = response.getData();
//业务逻辑处理……
/*
{
"Message": "OK",
"RequestId": "7B7926EA-63E9-4A0A-9922-CB789DE1063C",
"BizId": "854708979485869922^0",
"Code": "OK"
}
*/
} catch (ServerException e) {
e.printStackTrace();
} catch (ClientException e) {
e.printStackTrace();
}
}
}
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
/*
pom.xml
com.aliyun
aliyun-java-sdk-core
4.0.3
*/
public class SendBatchSms {
public static void main(String[] args) {
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "", "");
IAcsClient client = new DefaultAcsClient(profile);
CommonRequest request = new CommonRequest();
request.setSysMethod(MethodType.POST);
request.setSysDomain("dysmsapi.aliyuncs.com");
request.setSysVersion("2017-05-25");
request.setSysAction("SendBatchSms");
request.putQueryParameter("RegionId", "cn-hangzhou");
//接收短信的手机号码,JSON数组格式。
request.putQueryParameter("PhoneNumberJson", "[\"号码一\",\"号码二\"]");
//短信签名名称,JSON数组格式,短信签名的个数必须与手机号码的个数相同
request.putQueryParameter("SignNameJson", "[\"签名一\",\"签名二\"]");
//模板Code只能有一个
request.putQueryParameter("TemplateCode", "模板Code");
//短信模板变量对应的实际值,JSON数组格式,模板变量值的个数必须与手机号码的个数相同
//即使模板内容没有变量,使用SendBatchSms接口也需要传TemplateParamJson,形如[{},{}]
request.putQueryParameter("TemplateParamJson", "[{\"name\":\"A\"},{\"name\":\"B\"}]");
try {
CommonResponse response = client.getCommonResponse(request);
//返回的是一个JSON字符串,根据Code属性是否为OK可以判断请求是否发送成功
String data = response.getData();
//业务逻辑处理……
} catch (ServerException e) {
e.printStackTrace();
} catch (ClientException e) {
e.printStackTrace();
}
}
}
4、接收消息回执
用户成功接收系统的短信后,会产生一个消息回执
用户回复系统的短信,则产生了一个上行消息
阿里云短信服务提供了以下几种回执消息类型
上行短信指用户发送给通信服务提供商的短信,用于定制某种服务、完成某种查询、或是办理某种业务等。通过订阅SmsReport短信下行状态报告,可以获知每条短信的发送情况,了解短信是否达到终端用户的状态与相关信息。
与上行短信相对应的是下行短信。下行是指用户收到的短信,例如运营商发送的消息通知、业务提醒等短信。通过订阅SmsUp上行短信消息,可以获知终端用户回复短信的内容。
订阅SignSmsReport签名审核状态消息之后,如果通过API接口AddSmsSign申请短信签名,可以获取签名的审核状态消息。
订阅TemplateSmsReport模板审核状态消息之后,如果通过API接口AddSmsTemplate申请短信模板,可以获取模板的审核状态消息。
我们可以通过MNS消息队列消费模式和HTTP批量推送模式来接收短信的回执消息和上行短信内容。其中,对于SmsUp、SmsReport类型的消息,两种方式都可以使用;对于SignSmsReport、TemplateSmsReport类型的消息,阿里云短信服务只提供了HTTP批量推送模式。
HTTP批量推送模式比较简单,就是当阿里云接收到运营商的消息回执或上行消息时,阿里云会调用系统的HTTP接口,以POST方式传递JSON数据过来,我们自己的应用系统只需要写好接口,将接口的外网访问地址配置在阿里云上(下图)
PS:使用HTTP批量推送模式,第⼀次推送失败后,间隔1分钟、5分钟、10分钟、30分钟、60分钟、60分钟、60分钟、60分钟、60分钟后会进⾏重推,直⾄推送成功为⽌。如果推送10次后仍失败,不再重试
我们重点讲MNS消息队列消费模式,官方提供的demo(JAVA MNS SDK)不是那么简洁,并且有些依赖还需要手动安装到Maven仓库或者将这些依赖放在项目目录下,以System Scope的方式引入(官方的demo也是以这种方式引入的依赖)
com.aliyun
aliyun-java-sdk-core
4.1.0
com.aliyun.alicom
alicom-mns-receive-sdk
1.0.1
system
${project.basedir}/lib/alicom-mns-receive-sdk-1.0.1.jar
com.aliyun.mns
aliyun-sdk-mns
1.1.8
com.aliyun
aliyun-java-sdk-dybaseapi
1.0.0
system
${project.basedir}/lib/aliyun-java-sdk-dybaseapi-1.0.0.jar
import com.alicom.mns.tools.MessageListener;
/**
* 接收SmsReport类型回执消息Service
*/
public interface ReceiveSmsUpMessageService extends MessageListener {
}
import com.aliyun.mns.model.Message;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 接收SmsReport类型回执消息Service实现
*/
@Slf4j
@Service
public class ReceiveSmsUpMessageServiceImpl implements ReceiveSmsUpMessageService {
private Gson gson=new Gson();
@Override
public boolean dealMessage(Message message) {
String messageBodyAsString = message.getMessageBodyAsString();
log.info(messageBodyAsString);
try{
Map contentMap = gson.fromJson(messageBodyAsString, HashMap.class);
//TODO 根据文档中具体的消息格式进行消息体的解析
String phone_number = (String) contentMap.get("phone_number");
String biz_id = (String) contentMap.get("biz_id");
Boolean success = (Boolean) contentMap.get("success");
String send_time = (String) contentMap.get("send_time");
String err_code = (String) contentMap.get("err_code");
String err_msg = (String) contentMap.get("err_msg");
boolean flag = (success==null || !success) ? false : true;
//TODO 这里开始编写您的业务代码
}catch(com.google.gson.JsonSyntaxException e){
log.error("error_json_format:"+ messageBodyAsString,e);
//理论上不会出现格式错误的情况,所以遇见格式错误的消息,只能先delete,否则重新推送也会一直报错
return true;
} catch (Throwable e) {
//您自己的代码部分导致的异常,应该return false,这样消息不会被delete掉,而会根据策略进行重推
return false;
}
//消息处理成功,返回true, SDK将调用MNS的delete方法将消息从队列中删除掉
return true;
}
}
import com.alicom.mns.tools.DefaultAlicomMessagePuller;
import com.alicom.mns.tools.MessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
* 这里的类实现了ApplicationRunner,表示当该bean被加载进Spring上下文时自动运行run()方法
* 当然也可以参考官方提供的demo,以普通的main方法启动监听
*/
@Component
public class ReceiveMessageUtil implements ApplicationRunner {
@Autowired
private ReceiveSmsUpMessageService receiveSmsUpMessageService;
@Override
public void run(ApplicationArguments args) throws Exception {
//TODO 此处需要替换成开发者自己的AK信息
String accessKeyId=SMSConstants.ACCESS_KEY_ID;
String accessKeySecret=SMSConstants.ACCESS_KEY_SECRET;
/*
* 云通信产品下所有的回执消息类型:
* 1:短信回执:SmsReport,
* 2:短息上行:SmsUp
* 3:语音呼叫:VoiceReport
* 4:流量直冲:FlowReport
*/
//接收SmsUp类型回执消息
createPuller().startReceiveMsg(accessKeyId, accessKeySecret, "SmsUp", SMSConstants.SMS_UP_QUEUE_NAME, receiveSmsUpMessageService);
}
private DefaultAlicomMessagePuller createPuller() {
DefaultAlicomMessagePuller puller=new DefaultAlicomMessagePuller();
//设置异步线程池大小及任务队列的大小,还有无数据线程休眠时间
puller.setConsumeMinThreadSize(6);
puller.setConsumeMaxThreadSize(16);
puller.setThreadQueueSize(200);
puller.setPullMsgThreadSize(1);
//和服务端联调问题时开启,平时无需开启,消耗性能
puller.openDebugLog(false);
return puller;
}
}