阿里云短信服务
新建短信微服务
微服务结构如下
配置文件yml
spring:
application:
name: message-service
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatisdemo?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=true&serverTimezone=Asia/Shanghai
username: root
password: 123456
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
redis:
host: 192.168.0.113
port: 6379
database: 0
timeout: 18000000
lettuce:
pool:
max-active: 20
max-wait: -1 #最大阻塞时间 负数表示没有限制
max-idle: 5
min-idle: 0
server:
port: 8006
依赖管理
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.1</version>
</dependency>
<!-- fastjson 可以把对象等格式快速转换成json格式-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
开通阿里云短信服务
添加签名管理与模板管理
(1) 添加模板
(2)添加签名管理
编写发送短信接口
编写Controller,根据手机号发送短信
业务逻辑
为了避免重复发送短信,利用redis缓存将发送的验证码存于redis中并设置过期时间。
如果缓存中存在则不发送短信,若缓存中验证码code不存在或者过期了,则继续发送短信。
缓存中存储的方式 KEY(phoneNumber)--Value(code)手机号--验证码
1、 传入手机号,判断缓存中是否存在验证码code且判断是否为空
若存在且不为空,直接返回 return R.ok(); 不执行任何其他操作
2、 若缓存中不存在,则在后端生成验证码并将验证码传给阿里云具体过程如下
1、 后端生成验证码可以生成四位、六位或任意位数,在这里封装一个产生四位随机数的工具类
2、 校验手机号格式是否正确,不正确直接返回
3、 创建阿里云客户端,设置上传相关参数
4、 设置手机号、申请到的签名名称以及模板编号
5、 设置后端生成好的验证码,注意需要传入JSON格式,将String类型转成Json格式后再传入
6、 发送请求,返回请求是否成功结果 true/false
3、 判断是否发送成功
如果发送成功则将验证码以 KEY(phoneNumber)--Value(code)存在缓存中并返回 return R.ok().message("短信发送成功");
如果发送失败,则返回 return R.error().message("短信发送失败");
随机数工具类
package com.guli.common.utils;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
/**
* 获取随机数
*
*
*
*/
public class RandomUtil {
private static final Random random = new Random();
private static final DecimalFormat fourdf = new DecimalFormat("0000");
private static final DecimalFormat sixdf = new DecimalFormat("000000");
public static String getFourBitRandom() {
return fourdf.format(random.nextInt(10000));
}
public static String getSixBitRandom() {
return sixdf.format(random.nextInt(1000000));
}
/**
* 给定数组,抽取n个数据
* @param list
* @param n
* @return
*/
public static ArrayList getRandom(List list, int n) {
Random random = new Random();
HashMap<Object, Object> hashMap = new HashMap<Object, Object>();
// 生成随机数字并存入HashMap
for (int i = 0; i < list.size(); i++) {
int number = random.nextInt(100) + 1;
hashMap.put(number, i);
}
// 从HashMap导入数组
Object[] robjs = hashMap.values().toArray();
ArrayList r = new ArrayList();
// 遍历数组并打印数据
for (int i = 0; i < n; i++) {
r.add(list.get((int) robjs[i]));
System.out.print(list.get((int) robjs[i]) + "\t");
}
System.out.print("\n");
return r;
}
}
Controller代码实现
package com.doubleStrong.online.controller;
import com.doubleStrong.online.service.MessageService;
import com.guli.common.constants.R;
import com.guli.common.utils.RandomUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author Double strong
* @date 2020/3/28 17:52
*/
@RestController
@RequestMapping("/eduMessage/msg")
@CrossOrigin
public class MessageController {
@Autowired
private MessageService messageService;
@Autowired
private RedisTemplate<String,String> redisTemplate;
// 发送短信的方法
// 后台接收手机号,通过阿里云短信服务实现
@GetMapping("/send/{phoneNumber}")
public R sendMessage(@PathVariable("phoneNumber") String phoneNumber)
{
// 判断缓存中是否有code,没过期就存在,就直接从缓存中拿code
String code = redisTemplate.opsForValue().get(phoneNumber);
// 拿到code之后判断是否为空
if (!StringUtils.isEmpty(code))
{
return R.ok();
}
// 这个四位验证码由后端采用随机数生成,你想生成几位生成几位
// 在这里用四位随机数
String code1 = RandomUtil.getFourBitRandom();
// 将生成的四位随机数传给阿里云
Map<String,Object> param=new HashMap<>();
param.put("code",code1);
// 将code以map集合的形式发给阿里云
Boolean Success= messageService.send(param,phoneNumber,"SMS_186945759");
if(Success==true)
{
// 如果发送成功,就把把redis成功的验证码放到redis缓存中,并且设置该缓存的有效时间5分钟
redisTemplate.opsForValue().set(phoneNumber,code1,5, TimeUnit.MINUTES);
return R.ok().message("短信发送成功");
}
else
{
return R.error().message("短信发送失败");
}
}
}
ServiceImpl代码实现
package com.doubleStrong.online.service.Impl;
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.doubleStrong.online.service.MessageService;
import com.guli.common.constants.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import java.util.Map;
/**
* @author Double strong
* @date 2020/3/28 17:54
* 将电话号码和四位的验证码发送给阿里云
* 由阿里云根据电话号码发送后端生成的code
*
* 如何设置验证码分钟有效
* 利用redis过期时间,解决验证码过期时间
* 实现方法
* 每次发送成功之后,把验证码存放在redis中,并设置过期时间
*
*/
@Service
public class MessageServiceImpl implements MessageService {
// 用redis模板来存放code,并设置过期时间
// <String,String> <phone,code>的键值对模板
// 五分钟之内有效的话,如果有效直接从缓冲中获取而不用重复调用,
@Override
public Boolean send(Map<String, Object> param, String phoneNumber,String templateCode) {
// 判断手机号码是否为空,严格的来说要判断手机号码格式是否正确
if(StringUtils.isEmpty(phoneNumber)) return false;
// (regionId, accessKey, accessSecret)
DefaultProfile profile=DefaultProfile.getProfile("default", "****************", "*******************");
// 创建一个客户端
//默认设置 设置相关参数
IAcsClient client = new DefaultAcsClient(profile);
CommonRequest request = new CommonRequest();
request.setMethod(MethodType.POST);
request.setDomain("dysmsapi.aliyuncs.com");
request.setVersion("2017-05-25");
request.setAction("SendSms");
// 设置手机号
request.putQueryParameter("PhoneNumbers", phoneNumber);
// 设置签名名称 (我申请的签名的名称)
request.putQueryParameter("SignName", "谷粒在线教育验证码功能");
// 申请的模板编号
request.putQueryParameter("TemplateCode", templateCode);
// 加上我的验证码
// 要求传入的验证码是json格式 {"code": "asdassss..."}, JSONObject.toJSONString(param)就是转换成json字符串格式
request.putQueryParameter("TemplateParam",JSONObject.toJSONString(param));
//
try {
// 最终发送请求
CommonResponse response = client.getCommonResponse(request);
System.out.println(response.getData());
return response.getHttpResponse().isSuccess();
} catch (ServerException e) {
e.printStackTrace();
} catch (ClientException e) {
e.printStackTrace();
}
return false;
}
}