此文章主要介绍 阿里云短信服务 的使用,可根据实际业务需求自行编写代码
想实现 阿里云短信服务,必须的有阿里云的账号,此处文章前的你们是不是有备而来?点击下方注册 OR 登录到阿里云
登录成功后,进入到短信服务的控制台,可看到如下界面,具体菜单功能我就 不一一介绍了,相信大家都能从字面上大体了解。
下面我将开始介绍短信服务需要的主要配置 - 点击国内消息--签名管理--添加签名
短信签名:相信大家在右上角处 都能查看控制台提供的文档,我叙述的肯定不如文档写的全面,那我再此举一个通俗易懂的简单实例,帮助大家更好的去理解。
【天猫超市】水果!1!元!包!邮!还送15元红包!仅限今天,错过后悔!椱ァ製这段描述¥rCIuYr5yL91¥后到手机淘宝 回t退订
【腾讯科技】王者荣耀四周岁庆典明日开启,参与活动得婉儿周年庆限定,26日皮肤返场,登录抽百万内测!url.cn/5vKYnEb 回T退订
此处是我收到的2条短信,其中【天猫超市】与【腾讯科技】即为签名,大家可以 查看一下自己手机里面的短信,是不是发现每条短信开头部分都是【XXXX】,是不是发现自己以前从来没 注意过观察过,现在看来是不是特别神奇?
上面的申请签名的过程我就不过多叙述了,大家应该都能轻易获取到,下面我将介绍 短信模板
短信模版,即具体发送的短信内容。
此处我也不再举例,相信大家根据上面实例都能理解的很透彻。
签名与模板配置完后,在实际开发中还需要添加访问阿里API的密钥
首先点击右上角用户,添加一个处理短信的用户
添加完成后,自动跳转到用户信息页面,自行保存 AccessKeySecret
,关闭页面后,你将再也看不到 AccessKeySecret
,这个很重要
注意
此处的账户信息AccessKey ID 与 AccessKeySecret 在项目中进行使用,请谨慎保存
给账户授权, 使账户可以管理短信服务
当 签名与 模板 申请下来以后,可以在线进行测试,具体参数介绍请查看API文档
此时收到短信了没?写到此处,控制台 配置 与 测试 便结束了,相信大家的签名与模板都能申请下来,接下来我们将进入代码的世界,准备好了吗?
上面 SDK Demo中已经给出实例,我将结合实际需求写一个小Demo;
需求:发送短信验证码进行用户注册,且60秒内不能重复发送短信,验证码有效期为5分钟
环境准备:装有 RabbitMQ,Redis 环境的虚拟机
1.pom文件
xml <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--阿里云短信服务-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.1.0</version>
</dependency>
<!--阿里云json转换包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.43</version>
</dependency>
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--rabbitMq服务-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.application.yml配置(IP、端口 根据实际环境自行配置)
yamlspring:
#redis地址 端口号默认6379
redis:
host: 192.168.80.129
#rabbitmq配置
rabbitmq:
host: 192.168.80.131
port: 5672
username: guest
password: guest
publisher-confirms: true # 消息发送到交换机确认机制,是否确认回调
#自定义配置项
sms:
accessKeyId: 填写控制台配置用户时,记录的用户accessKeyId
accessSecret: 填写控制台配置用户时,记录的用户accessSecret
signName: 申请的签名 #签名
templateCode: 模板的CODE #模板CODE
domain: dysmsapi.aliyuncs.com
action: SendSms #API 的名称
3.常量定义
java/**
* 常量定义
* @author: diego
* @create: 2019/10/9
*/
public class DataDict {
//redis-key 手机号限流前缀
public final static String SMS_PHONE_NUMBER = "sms:phone:";
//redis-key 验证码前缀
public final static String SMS_PHONE_VERIFICATION = "sms:phone:verification:";
}
4.属性定义
javaimport lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 配置项属性
* @author: diego
* @create: 2019/10/9
*/
@Data
@Component
@ConfigurationProperties(prefix = "sms")
public class SmsProperties {
private String accessKeyId;
private String accessSecret;
private String SignName;
private String templateCode;
private String domain;
private String action;
@Override
public String toString() {
return "SmsProperties{" +
"accessKeyId='" + accessKeyId + '\'' +
", accessSecret='" + accessSecret + '\'' +
", SignName='" + SignName + '\'' +
", templateCode='" + templateCode + '\'' +
", domain='" + domain + '\'' +
", action='" + action + '\'' +
'}';
}
}
5.短信工具类
javaimport com.alibaba.fastjson.JSON;
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;
import com.aliyuncs.utils.StringUtils;
import com.example.demo.dict.DataDict;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 短信发送工具类
* @author: diego
* @create: 2019/10/9
*/
@Slf4j
@Component
@EnableConfigurationProperties(SmsProperties.class)
public class SmsUtils {
@Autowired
SmsProperties smsProperties;
@Autowired
StringRedisTemplate redisTemplate;
/**
* 短信发送方法
* demo:https://api.aliyun.com/?spm=a2c4g.11186623.2.13.63ee50a4NKRQsm#/?product=Dysmsapi&lang=JAVA
* @param phoneNumbers
* @param signName
* @param templateCode
* @return
*/
public CommonResponse SendSms(String phoneNumbers,String signName,String templateCode,String templateParam){
try {
//限流校验
val s = redisTemplate.boundValueOps(DataDict.SMS_PHONE_NUMBER + phoneNumbers).get();
if(StringUtils.isNotEmpty(s)){
System.err.println(s);
if (System.currentTimeMillis() - Long.valueOf(s) < 60000){
log.info("手机号码发送频繁,稍后再试!");
return null;
}
}
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou",
smsProperties.getAccessKeyId(), smsProperties.getAccessSecret());
IAcsClient client = new DefaultAcsClient(profile);
CommonRequest request = new CommonRequest();
request.setMethod(MethodType.POST);
request.setDomain(smsProperties.getDomain());
request.setVersion("2017-05-25"); //当前日期 格式:yyyy-MM-dd
request.setAction(smsProperties.getAction());
request.putQueryParameter("PhoneNumbers", phoneNumbers);
request.putQueryParameter("SignName", signName);
request.putQueryParameter("TemplateCode", templateCode);
if(StringUtils.isNotEmpty(templateParam)){
request.putQueryParameter("TemplateParam", templateParam);
}
CommonResponse response = client.getCommonResponse(request);
Map<String,String> map = JSON.parseObject(response.getData(),Map.class);
if("OK".equals(map.get("Code"))){
log.info("短信发送成功!返回消息:"+response.getData());
//短信发送成功,设置计时器 开始限流
redisTemplate.boundValueOps(DataDict.SMS_PHONE_NUMBER + phoneNumbers).set(
String.valueOf(System.currentTimeMillis()),1, TimeUnit.MINUTES);
}else{
log.info("短信发送失败!状态码为:"+map.get("Code")+" 错误信息为:"+map.get("Message"));
}
return response;
} catch (ServerException e) {
e.printStackTrace();
log.info("短信发送失败!服务异常信息为:"+ e);
} catch (ClientException e) {
e.printStackTrace();
log.info("短信发送失败!客户端异常信息为:"+ e);
} catch (Exception e){
e.printStackTrace();
log.info("短信发送失败!异常信息为:"+ e);
}
return null;
}
}
6.短信监听
javaimport com.alibaba.fastjson.JSON;
import com.example.demo.dict.DataDict;
import com.example.demo.sms.SmsProperties;
import com.example.demo.sms.SmsUtils;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.Map;
/**
* 短信监听
* @author: diego
* @create: 2019/10/9
*/
@Component
public class SmsListener {
@Autowired
SmsProperties smsProperties;
@Autowired
SmsUtils smsUtils;
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(
value = "sms_amqp_queue",durable = "true"),
exchange = @Exchange(
value = "sms_amqp_exchange", type = ExchangeTypes.TOPIC),
key = {"#.#"}
)
)
public void listenSmsSend(Map<String,String> map){
//校验map
if(CollectionUtils.isEmpty(map)){
return;
}
//从map中删除key为phone 返回key的值
String phone = map.remove("phone");
//校验返回的key为phone的返回值
if (StringUtils.isEmpty(phone)){
return;
}
System.out.println(JSON.toJSONString(map));
smsUtils.SendSms(phone,smsProperties.getSignName(), smsProperties.getTemplateCode(), JSON.toJSONString(map));
}
}
7.测试
javaimport com.example.demo.dict.DataDict;
import com.example.demo.sms.SmsProperties;
import com.example.demo.sms.SmsUtils;
import lombok.val;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Autowired
SmsProperties smsProperties;
@Autowired
StringRedisTemplate redisTemplate;
@Autowired
SmsUtils smsUtils;
@Autowired
RabbitTemplate rabbitTemplate;
/**
* 获取Application.yml中短信参数配置测试
*/
@Test
public void propertiesTest() {
System.err.println(smsProperties.toString());;
}
/**
* redis连通性测试
*/
@Test
public void redisTest() {
redisTemplate.boundValueOps("test").set("测试redis是否可用!");
val test = redisTemplate.boundValueOps("test").get();
System.out.println(test);
}
/**
* 短信发送服务测试
*/
@Test
public void smsSend() {
smsUtils.SendSms("1510110XXXX",smsProperties.getSignName(),
smsProperties.getTemplateCode(),"{\"code\":\"888888\"}");
}
/**
* 消息队列 - 短信发送服务测试
*/
@Test
public void smsSendToRabbitMQ() {
Map<String,String> map = new HashMap<>();
map.put("phone","1510110XXXX");
map.put("code","888888");
rabbitTemplate.convertAndSend("sms_amqp_exchange", "a.b", map);
//短信验证码有效期
redisTemplate.boundValueOps(DataDict.SMS_PHONE_VERIFICATION+"1510110XXXX").set("888888",5, TimeUnit.MINUTES);
}
}
此处的代码可以根据阿里提供的官方Demo,按照实际业务需求自行编写;
阅读到这里,你是否有一个疑问,我并没有在控制台中购买短信服务套餐,为什么短信发送成功了呢?
哈哈,这是一个比较深的坑,大家此时查看一下控制台中 费用统计,短信服务是预扣,已经开始欠费了
点击上方费用按钮,可查看账户信息,进入账户充值即可
短信服务的账单是 每月一结算,记得保证账户余额充足^_^。
本文作者:柳始恭
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!