发表于: 2019-10-11 22:30:33
1 1030
今日完成
完成手机发送验证码
1.前端
1.1页面展示
<%--2.手机验证码登录--%>
<h2>手机快捷登录</h2>
<div id="phone-login">
<form role="form" id="phone_form" action="${ctx}/doLogin" method="post">
<%--手机号--%>
<label for="phone">手机号</label>
<input type="text" id="phone" name="phone" placeholder="手机号" onblur="checkPhone();">
<span id="phone_span"></span>
<br>
<%--验证码--%>
<label for="phone_code">验证码</label>
<input type="text" id="phone_code" name="phone_code" placeholder="验证码" onclick="checkPhoneCode();">
<button id="go" onclick="getPhoneCode();">获取验证码</button>
<br>
<%--注册按钮--%>
<button type="submit" class="btn btn-default" id="phone_btn" onclick="checkButton();">登录</button>
<a href = "regist.jsp" >立即注册</a>
</form>
</div>
1.2绑定函数
1.校验手机号:checkPhone
//1.1校验手机号
var flag2 = false;
function checkPhone(){
var phone = $("#phone").val();
phone = phone.replace(/^\s+|\s+$/g,"");
if(!(/^1[3|4|5|8|7|9][0-9]\d{8}$/.test(phone))){
$("#phone_span").text("手机号码非法,请重新输入!").css("color","red");
flag2 = false;
}else{
$.ajax({
type:'post',
url:'/checkPhone',
data: {"phone":phone},
dataType:'json',
success:function(data){
var val = data['message'];
if(val=="success"){
//未注册
$("#phone_span").text("该手机号还未注册!");
flag2 = false;
}else{
//注册
$("#phone_span").text("");
flag2 = true;
}
}
});
}
return flag2;
}
2.手机验证码检查:checkPhoneCode
//1.2手机验证码检查
var p_flag = false;
function checkPhoneCode(){
var reg = /^\d{4}\b/;
var code = $("#phone_code").val();
if(reg.test(code)){
p_flag = true;
}else {
p_flag = false;
}
return p_flag;
}
3.手机倒计时:countDown
function countDown(s){
if(s <= 0){
$("#go").text("重新获取");
$("#go").removeAttr("disabled");
return;
}
/* $("#go").val(s + "秒后重新获取");*/
$("#go").text(s + "秒后重新获取");
setTimeout("countDown("+(s-1)+")",1000);
}
4.获取手机验证码:getPhoneCode
function getPhoneCode(){
if(!flag2){
$("#phone_span").text("手机号码非法或者未注册!").css("color","red");
}else {
// 发送短信给用户手机..
// 1 发送一个HTTP请求,通知服务器 发送短信给目标用户
var phone =$("input[name='phone']").val();// 用户输入的手机号
// 用户输入手机号校验通过
$("#go").attr("disabled", "disabled");
countDown(60);
$.ajax({
method: 'POST',
url: '${ctx}/sendSms',// 发送验证码给ActiveQM, 同时保存验证码到redis数据库
data : {
phone : phone
},
success:function(data) {
var tt = data["msg"];
if(tt){
alert("发送短信成功!");
}else{
alert("发送短信出错,请联系管理员");
}
}
});
}
return false;
}
5.登录:checkButton
function checkButton() {
if(checkPhone()&& checkPhoneCode()){
// 校验用户名和密码
$("#phone_span").text("").css("color","red");
$("#phone_form").submit();
}else {
alert("请输入手机号和6位验证码!");
}
}
2.后端
2.1环境配置:ActiveMQ
1.applicationContext-activemq.xml:就改个监听器
<!-- 扫瞄包-->
<context:component-scan base-package="com.jnshu.activemq" />
<!-- ActiveMQ 连接工厂 -->
<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->
<!-- 如果连接网络:tcp://ip:61616;未连接网络:tcp://localhost:61616 以及用户名,密码-->
<amq:connectionFactory id="amqConnectionFactory" brokerURL="tcp://localhost:61616" userName="admin" password="admin" />
<!-- Spring Caching连接工厂 -->
<!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
<property name="targetConnectionFactory" ref="amqConnectionFactory"></property>
<!-- 同上,同理 -->
<!-- <constructor-arg ref="amqConnectionFactory" /> -->
<!-- Session缓存数量 -->
<property name="sessionCacheSize" value="100" />
</bean>
<!-- Spring JmsTemplate 的消息生产者 start-->
<!-- 定义JmsTemplate的Queue类型 -->
<bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
<!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
<constructor-arg ref="connectionFactory" />
<!-- 非pub/sub模型(发布/订阅),即队列模式 -->
<property name="pubSubDomain" value="false" />
</bean>
<!-- Spring JmsTemplate 的消息生产者 end -->
<!-- 消息消费者 start-->
<!-- 定义Queue监听器 -->
<jms:listener-container destination-type="queue" container-type="default" connection-factory="connectionFactory" acknowledge="auto">
<!-- 默认注册bean名称,应该是类名首字母小写 -->
<jms:listener destination="login_msg" ref="smsAuthenCode"/>
<jms:listener destination="email_msg" ref="emailAuthenCode"/>
</jms:listener-container>
<!-- 消息消费者 end -->
2.web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:spring-mybatis.xml
classpath*:applicationContext-redis.xml
classpath*:applicationContext-activemq.xml
</param-value>
</context-param>
2.2Controller
1.发送手机验证码
/*3.发送手机验证码*/
@RequestMapping("/sendSms")
@ResponseBody
public Map<String,Object> index(Model model, @RequestParam(value = "phone",required = false) final String phone) {
Map map = new HashMap<String,Object>( );
try { // 发送验证码操作
final String code = RandStringUtils.getCode();
log.info("发送的手机号:"+phone+" 发送的验证码:"+code);
redisTemplate.opsForValue().set(phone, code, 60, TimeUnit.SECONDS);// 6 0秒 有效 redis保存验证码
log.info("--------短信验证码为:"+code);
// 调用ActiveMQ jmsTemplate,发送一条消息给MQ
jmsTemplate.send("login_msg", new MessageCreator() {
public Message createMessage(javax.jms.Session session) throws JMSException {
MapMessage mapMessage = session.createMapMessage();
mapMessage.setString("phone", phone);
mapMessage.setString("code", code);
log.info("Mq进去了???");
return mapMessage;
}
});
} catch (Exception e) {
map.put( "msg",false );
}
map.put( "msg",true );
return map;
}
2.3工具类:就改几个地方,其余不变
public class SendMessage {
private static String accessKeyId = "LTAI4FvNF4k2KFUNZV8F6ih1";//你的accessKeyId,参考本文档步骤2
private static String accessKeySecret = "IXhk77Y4oHAWk0951Wl79EtUGWYMV2";//你的accessKeySecret,参考本文档步骤2
private static String setSignName = "技能树验证码";
private static String dayutemplateCode = "SMS_175240801";
public static void sendMessages(String code,String phone){
//设置超时时间-可自行调整
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//初始化ascClient需要的几个参数
final String product = "Dysmsapi";//短信API产品名称
final String domain = "dysmsapi.aliyuncs.com";//短信API产品域名
//替换成你的AK
//初始化ascClient,暂时不支持多region
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId,accessKeySecret);
try {
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
} catch (ClientException e) {
e.printStackTrace();
}
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象
SendSmsRequest request = new SendSmsRequest();
//必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为20个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式
request.setPhoneNumbers(phone);
//必填:短信签名-可在短信控制台中找到
request.setSignName(setSignName);
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode(dayutemplateCode);
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
request.setTemplateParam("{\"code\":\"" + code + "\"}");
//可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setOutId("yourOutId");
//请求失败这里会抛ClientException异常
SendSmsResponse sendSmsResponse = null;
try {
sendSmsResponse = acsClient.getAcsResponse(request);
} catch (ServerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClientException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {
}
}
2.4调用ActiveMQ
@Component
public class SmsAuthenCode implements MessageListener {
public void onMessage(Message message) {
MapMessage mapMessage = (MapMessage) message;
// 调用SMS服务发送短信 SmsSystem阿里大于发送短信给客户手机实现类
try {
// 大于发送短信 Map 来自ActiveMQ 生成者
SendMessage.sendMessages( mapMessage.getString("code"), mapMessage.getString("phone") );
System.out.println( "-----发送消息成功..."+mapMessage.getString("code"));
} catch (Exception e) {//JMS
e.printStackTrace();
}
}
}
3.好处
通过监听器名字的不同,可以区分是邮箱发送的验证码还是手机发送的验证码
其实就是一个中转站,区分消息消费者(接受到验证码的人)和消息生产者(我们),在中转站中调用发送短信的工具类,并记录发送的条数、发送的主体等信息。
也可以直接在Controller中调用工具类
碰到问题
碰到好多问题,就是改上面配置,不懂怎么描述配置还是比较固定的东西,最终配置成这样就能跑了
明日计划
IO流的知识,后天完成文件上传
启发
无
评论