上篇博文具体讲了RabbitMQ的知识,这篇博文就实际应用一下RabbitMQ,并借助阿里云进行发送短信验证码的功能。
如果要使用阿里云的短信服务,就需要在阿里云的官网上申请。
首先登录阿里云,支付宝或者淘宝登录即可。
登录完就是上面这个界面,然后在产品与服务中找到云通信下面的短信服务。
如果没有开通,直接点击开通,因为博主已经开通了,所以进来就是这个界面。
框框中的东西"签名管理",“模板管理”,需要根据自己的情况自己申请的,然后等系统通过即可。
当然,阿里云还提供了发送短信的代码Demo,这个读者可以自行查阅。
需求:用户通过手机号注册,需要手机发送验证码。填写正确的验证码,就可以完成注册。
此项目还是基于另一篇博文:《SpringBoot中使用RabbitMQ消息中间件》
因为这里还是要使用消息中间件,所以,先导入Maven依赖。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
<dependency>
<groupId>com.aliyungroupId>
<artifactId>aliyun-java-sdk-coreartifactId>
<version>4.1.0version>
dependency>
要用到阿里云,所以也要将依赖导入。
然后修改配置文件。
spring:
# 配置rabbitmq
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
# 阿里云相关配置
aliyun:
sms:
accessKeyId:
accessKeySecret:
signName1:
templateCode1:
上面是RabbitMQ的配置,下面是阿里云的配置,accessKeyId和accessKeySecret如图所示。
通过这里点进去就能看到。下面两个自定义配置就是刚才需要申请的"签名管理",“模板管理”,只有申请通过之后,才能使用。
创建生产者,发送短信验证码。
因为要与数据库交互,博主这里使用了MySQL数据库,使用JPA来操作,同时这里还使用了Redis。
如果使用其他数据库或者其他ORM框架的读者,需要使用博主的例子修改的话,也没有什么影响!
创建一个实体类,User
@Data
@Entity
@Table(name = "qf_user")
@ApiModel(value = "User", description = "用户")
public class User implements Serializable {
@Id
@ApiModelProperty(value = "主键")
private String id;
@ApiModelProperty(value = "手机")
private String mobile;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "盐值")
private String salt;
@Column(name = "nick_name")
@ApiModelProperty(value = "昵称")
private String nickName;
@ApiModelProperty(value = "性别")
private String sex;
@ApiModelProperty(value = "生日")
private Date birthday;
@ApiModelProperty(value = "头像")
private String avatar;
@ApiModelProperty(value = "邮箱")
private String email;
@Column(name = "reg_date")
@ApiModelProperty(value = "注册日期")
private Date regDate;
@Column(name = "update_date")
@ApiModelProperty(value = "修改日期")
private Date updateDate;
@Column(name = "last_date")
@ApiModelProperty(value = "最后登录日期")
private Date lastDate;
}
因为这是博主项目中的一部分,为了方便,我就直接拷贝过来了。
关于dao层的部分就不上代码了,就一个增删改查而已。下面是service层
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private RabbitTemplate rabbitTemplate;
@Value("${spring.redis.key.mobile}")
private String verifyCodeKey;
public void save(User user) {
user.setRegDate(new Date());
user.setUpdateDate(new Date());
user.setLastDate(new Date());
userRepository.save(user);
}
/**
*发送短信
*/
public void sendMobileMessage(String mobile) {
//生成六位随机数
String verifyCode = RandomStringUtils.randomNumeric(6);
//写入redis缓存
redisTemplate.opsForValue().set(verifyCodeKey + mobile, verifyCode, 5, TimeUnit.MINUTES);
//发给用户
Map<String, String> stringMap = Maps.newHashMap();
stringMap.put("mobile", mobile);
stringMap.put("verifyCode", verifyCode);
//使用了direct模式
rabbitTemplate.convertAndSend(RabbitConstant.MOBILE_ROUTING_KEY, stringMap);
//记录到日志中
boolean enabled = log.isDebugEnabled();
if (enabled) {
log.debug("mobile:[{}],verifyCode:[{}]", mobile, verifyCode);
}
}
/**
*注册
*/
public ResultBean register(User user, String code) {
//判断redis中是否存在
String verifyCode = redisTemplate.opsForValue().get(verifyCodeKey + user.getMobile());
if (StringUtils.isEmpty(verifyCode)) {
return new ResultBean(new CustomerException("短信验证码为空"), -1);
}
if (!verifyCode.equals(code)) {
return new ResultBean(new CustomerException("验证码错误!"), 100);
}
save(user);
return new ResultBean();
}
}
里面有很多变量,博主都提取出来了,不可能将所有代码都放入,如果不明白的读者,可以给博主留言,博主一定会回答。
基本上生产者就完成了。执行上面的代码,就将验证码放入Redis缓存中,将手机号和验证码封装成Map放入消息队列中,可以作为一个伪发送短信的功能,只有等到发送短息的服务中的消费者来消费队列中的消息时,才能真正的发送验证码。
接着,将创建消息的消费者。实际上,这里需要提取出另一个服务,专门发送手机短信的服务。博主这里将其提取出来并封装了发送短信的工具类。
/**
* @ClassName: SmsUtil
* @Author: 清风一阵吹我心
* @Description: TODO 阿里云发送短信验证码的工具类
* @Date: 2019/10/26 13:37
* @Version 1.0
**/
@Component
public class SmsUtil {
private static final String regionId = "cn-hangzhou";
/**
* 产品域名
*/
private static final String DOMAIN = "dysmsapi.aliyuncs.com";
/**
* 系统规定参数。取值:SendSms
*/
private static final String ACTION = "SendSms";
/**
* 可以得到当前配置文件中所有的信息
*/
@Autowired
private Environment environment;
/**
* //TODO
* 发送短信
*
* @param phoneNumbers 手机号
* @param signName 短信签名名称
* @param templateCode 短信模板ID
* @param templateParam 参数
* @return com.aliyuncs.CommonResponse
*/
public CommonResponse sendSms(String phoneNumbers, String signName, String templateCode, String templateParam) {
String accessKeyId = environment.getProperty("aliyun.sms.accessKeyId");
String accessKeySecret = environment.getProperty("aliyun.sms.accessKeySecret");
//调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "5000");
System.setProperty("sun.net.client.defaultReadTimeout", "5000");
DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
IAcsClient client = new DefaultAcsClient(profile);
CommonRequest request = new CommonRequest();
request.setMethod(MethodType.POST);
request.setDomain(DOMAIN);
request.setVersion("2017-05-25");
request.setAction(ACTION);
//待发送手机号
request.putQueryParameter("PhoneNumbers", phoneNumbers);
//短信签名
request.putQueryParameter("SignName", signName);
//短信模板Id
request.putQueryParameter("TemplateCode", templateCode);
//短信模板变量对应的实际值,JSON格式。如果JSON中需要带换行符,请参照标准的JSON协议处理。
request.putQueryParameter("TemplateParam", templateParam);
//上行短信扩展码,无特殊需要此字段的用户请忽略此字段。
//request.putQueryParameter("SmsUpExtendCode", "0000");
//外部流水扩展字段
//request.putQueryParameter("OutId", "0000");
CommonResponse commonResponse = null;
try {
commonResponse = client.getCommonResponse(request);
} catch (ClientException e) {
e.printStackTrace();
}
return commonResponse;
}
}
上面的代码在阿里云提供的文档中都有详细介绍,博主这里只是做了简单的修改。
发送短信的工具类完成后,需要用到RabbitMQ了,将消息队列中的消息消费掉,发送真正的短信到用户的手机上。
@Slf4j
@Component
@RabbitListener(queues = RabbitConstant.MOBILE_ROUTING_KEY)
public class MobileMessageListener {
@Autowired
private SmsUtil smsUtil;
@Value("${aliyun.sms.signName1}")
private String signName1;
@Value("${aliyun.sms.templateCode1}")
private String templateCode1;
@RabbitHandler
public void messageHandler(Map<String, String> map) {
String mobile = map.get("mobile");
String verifyCode = map.get("verifyCode");
boolean debugEnabled = log.isDebugEnabled();
if (debugEnabled) {
log.debug("手机号:[{}],验证码:[{}]", mobile, verifyCode);
}
String templateParam = "{" + "code" + ":" + verifyCode + "}";
smsUtil.sendSms(mobile, signName1, templateCode1, templateParam);
}
}
因为功能并不复杂,通过文档就能够实现的。博主这里只是做一个简单的讲解。
昨天博主看腾讯视频,发现《烈火英雄》可以看了,以前本来想去电影院看的,但是都没时间去,主要是因为“一个人不想出去”,emmmm~ 然后博主就借来一个腾讯视频的会员,把电影看了一遍。基本上,全程都是揪着心看的。觉得这个电影拍的太好了。真的觉得"人名英雄"太伟大了。心中也与那句“此生无悔入华夏,来生愿在种花家”,产生了共鸣。
千言万语都没有看一遍来的实际,如果有读者读到这里,并且还没有看过《烈火英雄》的,博主强烈建议大家去看呢,但是,首先要做好心理准备啊。
努力不一定成功,但不努力一定不成功