前言:
获取AccessKeyID ,AccessKey Secret我就说个大概,大家可以看官方的帮助文档,进行获取,后面的代码部分并没有给出全部的代码,只是为了提供给大家思路,如果有需要,欢迎留言,我私发给他。
一、前期准备
首先注册一个阿里云账号
然后登录,产品分类,选择短信服务
点击管理控制台
进入到下面的界面就可以通过新手引导,和开发者指南进行操作了
国内消息,进去之后可以添加签名和模板
输入网址:https://ram.console.aliyun.com/users
创建用户
授权
点击你创建好的用户,如下图
进入之后创建AccessKey,就会找到AccessKeyID和AccessKeySecret
我们的目的就是得到下面的四个值:
AccessKeyID不要给别人看
AccessKeyID:你自己的accessKeyId
AccessKeySecret:你自己的AccessKeySecret
模板code:模板CODE
签名:签名名称
二、demo
背景:一个用户的微服务user-service,一个手机短信验证微服务sms-service,此时用户输入自己的手机号,会发送过来一个验证码,由于是两个服务我们采取将验证码存在redis里。由于短信接收具有时长不定性,为了提高程序的响应速度,短信发送采用异步的方式,就是说收到消息后发送短信,我们的用户微服务(user-service)我们通过RabbitMq通知短信微服务(sms-service)发送短信。
1、创建一个短信服务
2、属性抽取
将上面的四个常量抽取到你的yml文件中
application.yml
server:
port: 8086
spring:
application:
name: sms-service
rabbitmq:
host: 152.136.203.163
username: leyou
password: 你自己的密码
virtual-host: /v_leyou
leyou:
sms:
accessKeyId: # 你自己的accessKeyId
accessKeySecret: # 你自己的AccessKeySecret
signName: # 签名名称
verifyCodeTemplate: # 模板名称CODE
3、注入到属性类中
@ConfigurationProperties(prefix = "leyou.sms")
public class SmsProperties {
String accessKeyId;
String accessKeySecret;
String signName;
String verifyCodeTemplate;
// getter和setter省略
}
prefix的值要和yml中一致
4、smsUtils (这个官网有模板,复制黏贴就好,然后简单改改)
@Component
@EnableConfigurationProperties(SmsProperties.class) //使属性类生效
public class SmsUtils {
@Autowired
private SmsProperties prop;
//产品名称:云通信短信API产品,开发者无需替换
static final String product = "Dysmsapi";
//产品域名,开发者无需替换
static final String domain = "dysmsapi.aliyuncs.com";
static final Logger logger = LoggerFactory.getLogger(SmsUtils.class);
public SendSmsResponse sendSms(String phone, String code, String signName, String template) throws ClientException {
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou",
prop.getAccessKeyId(), prop.getAccessKeySecret());
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request = new SendSmsRequest();
request.setMethod(MethodType.POST);
//必填:待发送手机号
request.setPhoneNumbers(phone);
//必填:短信签名-可在短信控制台中找到
request.setSignName(signName);
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode(template);
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
request.setTemplateParam("{\"code\":\"" + code + "\"}");
//选填-上行短信扩展码(无特殊需求用户请忽略此字段)
//request.setSmsUpExtendCode("90997");
//可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setOutId("123456");
//hint 此处可能会抛出异常,注意catch
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
logger.info("发送短信状态:{}", sendSmsResponse.getCode());
logger.info("发送短信消息:{}", sendSmsResponse.getMessage());
return sendSmsResponse;
}
}
5、SmsListener
@Component
@EnableConfigurationProperties(SmsProperties.class)
public class SmsListener {
@Autowired
private SmsUtils smsUtils;
@Autowired
private SmsProperties prop;
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "LEYOU.SMS.QUEUE", durable = "true"),
exchange = @Exchange(value = "LEYOU.SMS.EXCHANGE", ignoreDeclarationExceptions = "true"),
key={"sms.verify.code"}))
public void listenSms(Map<String, String> msg) throws ClientException {
if(CollectionUtils.isEmpty(msg))
{
//放弃处理
return;
}
String phone=msg.get("phone");
String code=msg.get("code");
if (StringUtils.isBlank(phone)||StringUtils.isBlank(code)){
return;
}
SendSmsResponse resp =this.smsUtils.sendSms(phone,code,prop.getSignName(),prop.getVerifyCodeTemplate());
}
}
6、创建一个用户微服务
7、UserController代码
/**
* 生成短信验证码
* @param phone
* @return
*/
@PostMapping("code")
public ResponseEntity<Void> sendVerifyCode(String phone){
Boolean aBoolean = this.userService.sendVerifyCode(phone);
if (!aBoolean){
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<>(HttpStatus.CREATED);
}
8、UserService
@Autowired
private StringRedisTemplate stringRedisTemplate;
// 验证码前缀,这个是注册,的以后可能还会有订单
static final String KEY_PREFIX = "user:code:phone:";
static final Logger logger = LoggerFactory.getLogger(UserService.class);
public Boolean sendVerifyCode(String phone) {
String code= NumberUtils.generateCode(6);
try {
HashMap<String, String> msg = new HashMap<>();
msg.put("phone",phone);
msg.put("code",code);
this.amqpTemplate.convertAndSend("LEYOU.SMS.EXCHANGE","sms.verify.code",msg);
// 将code存入redis 5分钟失效
this.stringRedisTemplate.opsForValue().set(KEY_PREFIX+phone,code,5, TimeUnit.MINUTES);
return true;
} catch (AmqpException e) {
logger.error("发送短信失败。phone:{},code:{}",phone,code);
return false;
}
}
9、UserMapper
public interface UserMapper extends Mapper<User> {
}
这里需要引用通用mapper 座标
<!-- 通用Mapper启动器 -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
</dependency>
10启动服务,通过postman测试
收到短信