springboot+Redis+ ActiveMQ+腾讯云短信服务 实现短信验证码功能

主要思路:
将自己生成的验证码放进activemq中的一个消息队列中(点对点),于此同时,将手机号,验证码以<手机号,验证码>存入redis中,springboot监听该队列,在springboot中接入短信服务的api ,实现发送短信,最后验证时只需判断页面的验证码是否和Redis中键值相匹配。成功将该用户的信息写入mysql数据库。
代码实现及步骤解析
一,创建springBoot服务 (打包方式为jar)
1,添加web,activemq,热部署,腾讯云短信服务的依赖
腾讯云短信服务依赖

<dependency>
			<groupId>com.github.qcloudsms</groupId>
			<artifactId>qcloudsms</artifactId>
			<version>1.0.5</version>
</dependency>

注:只有依赖是没用的,还要去申请使用所需的一些材料:短信签名,短信模板,(如果自己玩的话,建议使用腾讯云,比较好申请,验证申请要一个微信公共号的管理界面截图,具备以下图例中的东西才能发短信)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
只有上述的东西准备好才能使用人家的服务。
2,下载对应的sdk解压,在esclipse测试下就行了,如果不成功大多数是配置参数有问题,腾讯短信对应的java sdk说的很明白。
3,创建springBoot的引导类Application.java
springboot内置了tomcat ,所以不需要在tomcat等容器内启动,添加一些依赖就可以

package itcast_sms_service;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

4,创建短信工具类SmsUtil.java

@Component
public class SmsUtil {
	@Autowired
	private Environment env;
	//发送短信
	public void sendSms(String phoneNumbers,String templateId,ArrayList<String> params,String smsSign) {
		 try {
	            SmsSingleSender ssender = new SmsSingleSender(Integer.parseInt(env.getProperty("appid")), env.getProperty("appkey"));
	            SmsSingleSenderResult result = ssender.sendWithParam("86", 
	            		phoneNumbers, 
	            		Integer.parseInt(templateId), 
	            		params, 
	            		smsSign, "", "");
	            System.out.print(result);
	        } catch (HTTPException e) {
	            // HTTP响应码错误
	            e.printStackTrace();
	        } catch (JSONException e) {
	            // json解析错误
	            e.printStackTrace();
	        } catch (IOException e) {
	            // 网络IO错误
	            e.printStackTrace();
	        }
	}
}

这里主要是一个类 的和一个方法的参数,根据需要的类型填入就行了
sendWithParam(String nationCode, String phoneNumber, int templateId, ArrayList params, String sign, String extend, String ext)
Parameters:nationCode 国家码,如 86 为中国phoneNumber 不带国家码的手机号templateId 信息内容
params 模板参数列表,如模板 {1}…{2}…{3},那么需要带三个参数
sign 签名,如果填空,系统会使用默认签名
extend 扩展码,可填空
ext 服务端原样返回的参数,可填空
这些参数例如appid 和appkey在application.properties 中配置,用自动注入的Environment 进行取值。
5,创建消息监听类SmsListener.Java
监听activeMq对应队列的消息,并调用SmsUtil的sendSms(****);
这里用map来接受消息,那在生产者也得用map封装数据

@Component
public class SmsListener {
	//注入工具类
	@Autowired
	private SmsUtil smsUtil;
	//配置监听的消息队列
	@JmsListener(destination="sms")
	public void onMessage(Map map) {
		String phoneNumbers = map.get("phoneNumbers").toString();
		String templateId = map.get("templateId").toString();
		ArrayList<String> params = new ArrayList<>();
		String[] string = ((String) map.get("params")).split(" ");
		params.add(string[0]);
		params.add(string[1]);
		String smsSign = (String) map.get("smsSign");
		smsUtil.sendSms(phoneNumbers,templateId,params,smsSign);
		smsUtil.receiveSms();
		System.out.println(map);
	}
}

由于springboot有内置的activemq,但是要使用自己的就必须在配置文件中添加

server.port=9003//端口
spring.activemq.broker-url=tcp://192.168.72.129:61616
appid=****
appkey=****
templateId=****
smsSign=****

至此,短信微服务ok ,这是一个独立的服务。
二,根据业务需求,创建生产者,也就是项目中需要短信服务的模块,一般都在注册页面中使用,新用户注册实际就是在数据库中添加一条信息。我的项目用的dubbox架构(面向服务),在注册这个模块中向dubbox注册userService服务,在dubbox中userService则为服务的提供者,模块的web层是服务的消费者,也就是userController,userController在页面接受到页面的请求,如:发送验证码(电话号等信息将返回),验证码校验(电话号,用户输入的验证码等信息将返回), 完成注册 等。通过dubbox向userService服务请求具体的方法,如:发送验证码,验证码校验。而userService服务则向activemq发送消息:我要发送一条消息,消息的内容是什么,等信息。然后,springboot短信服务会监听到该消息 ,根据消息的具体内容,发送短信到用户。在验证码校验阶段,由于在请求发送验证码时,userService就把产生的验证码或电话号 存入Redis数据库中,在去向activemq发消息,所以在验证时只需要校验用户输入的验证码是否Redis数据库的电话号是否一致。

参数:手机号
请求
发送消息/参数:手机号,系统验证码
向Redis写:<手机号,系统验证码>
用户请求发送验证码
web层
Dubbox/服务中心
service层服务
ActiveMq
Redis
监听到消息:手机号/验证码
向消息中的手机号发送验证码
短信服务
ActiveMQ
用户

以上是注册模块的大致流程图。主要代码如下
1,前端采用angularjs框架,用户点击发送验证码,
页面

<input type="text" ng-model="smsCode" placeholder="短信验证码" 
class="input-xfat input-xlarge">  
<a ng-click="sendCode()">获取短信验证码</a>			

前端service层

//发送验证码
	this.sendCode=function(phone){
		return $http.get("../user/sendCode.do?phone="+phone);
	}

前端控制层,调用前端service层

	//发送验证码
	$scope.sendCode=function(){
		if($scope.entity.phone==null){
			alert("请输入手机号");
			return;
		}
		userService.sendCode($scope.entity.phone).success(
			function(response){
				alert(response.message);
			}	
		);
	}

2,后端采用springmvc
web层,注入服务层UserService

//发送验证码
	@RequestMapping("/sendCode")
	public Result sendCode(String phone) {
		if(!PhoneFormatCheckUtils.isChinaPhoneLegal(phone)) {
			return new Result(false, "手机格式不正确");
		}
		try {
			userService.createCode(phone);//创建验证码
			return new Result(true, "短信验证吗发送成功");
		} catch (Exception e) {
			e.printStackTrace();
			return new Result(true, "短信验证码发送失败");
		}
	}

service层 发送消息并保存数据到Redis
需要注入Redis和 jmsTemplate消息服务,目的队列名smsDestination(这是在配置文件中配置的,点对点)
注意的是,这里验证码的生成方式是用随机函数,也可以用别的策略,这种不是最好的,有时间试一试别的

//生成验证码并发送到消息队列
	@Override
	public void createCode(final String phone) {
		//生成6位随机数
		final String code =  (long) (Math.random()*1000000)+"";
		System.out.println("验证码====="+code);
		redisTemplate.boundHashOps("smsCode").put(phone, code);
		System.out.println(phone);//便于后台验证
		System.out.println(templateId+smsSign);
		//短信模板参数
		//发送activemq
		jmsTemplate.send(smsDestination, new MessageCreator() {
			@Override
			public Message createMessage(Session session) throws JMSException {
				MapMessage mapMessage = session.createMapMessage();
				mapMessage.setString("phoneNumbers", phone);//电话号
				mapMessage.setString("templateId", templateId);//模板id
				mapMessage.setString("smsSign", smsSign);//签名id
				mapMessage.setString("params", code+" "+"1");
				System.out.println("参数"+code);
				return mapMessage;
			}
		});
	}

至此,发送验证码的功能就ok了,可以看到,各个功能,服务的耦合度很低 ,各个模块之间的联系都是通过网络进行的,远程调用(rpc),例如在发送验证码的过程中,userService 服务通过activemq进行发送短信验证码,这样做就可以减少服务器的压力,提高该服务的效率,他不必关心怎样去发送短信,也不需要等待响应,提高了用户体验。这里用Redis数据库作验证数据的存储,读取时间短就不用说了,可以为其设置过时间,如果使用mysql的话,会增加主要业务数据访问的压力,过期时间没法解决,除非删除数据,这又带来了数据库的访问压力。Redis存储的数据结构多样,用mysql没那么方便。
关于验证码 的校验就是配置SpringDateRedis调用 redisTemplate的方法,对系统的验证码和用户输入的验证码进行比较,一致则成功。整个功能的思路很重,
附上成功的图片:
在这里插入图片描述
在这里插入图片描述
如果有不大对的地方,望批证。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值