需求: 手机验证码登录,点击发送验证码,输入验证码,登录;
思路:
输入手机号,点击发送验证码按钮,单击事件触发 前端页面校验手机号格式是否正确,如不正确就返回手机号有误,正确就携带手机号发送请求,在发送请求前做一个倒计时效果;后台接收到手机号,生成验证码,并将验证码保存在redis中手机号为key,验证码为value设置一个过期时间,调用发送短信服务传入手机号和验证码;用户接收到验证码,输入验证码,前端同样进行一个校验,校验通过传入后端;后端拿到数据,根据手机号查询验证码,返回结果;
注意事项: 避免出现恶意多次发送验证码,可以对手机号发送的验证码数量进行限制,3小时内最多发送3次验证码;
前端页面:
导入相关的工具js
//获取指定的URL参数值 如:http://localhost/pages/setmeal_detail.html?id=3&name=jackfunction getUrlParam(paraName) {var url = document.location.toString();//alert(url);//从?开始剪切var arrObj = url.split("?");//如果有值表示有参数if (arrObj.length > 1) {//去掉?号以&分隔符在剪切var arrPara = arrObj[1].split("&");var arr;//遍历,拿到在键值对,以=号剪切,得到参数值for (var i = 0; i < arrPara.length; i++) {arr = arrPara[i].split("=");if (arr != null && arr[0] == paraName) {return arr[1];}}return "";}else {return "";}}//获得当前日期,返回字符串function getToday() {var today = new Date();var year = today.getFullYear();var month = today.getMonth() + 1;//0表示1月,1表示2月var day = today.getDate();return (year + "-" + month + "-" + day);}//获得指定日期后指定天数的日期function getSpecifiedDate(date,days) {date.setDate(date.getDate() + days);//获取指定天之后的日期var year = date.getFullYear();var month = date.getMonth() + 1;var day = date.getDate();return (year + "-" + month + "-" + day);}/*** 手机号校验1--以1为开头;2--第二位可为3,4,5,7,8,中的任意一位;3--最后以0-9的9个整数结尾。*/function checkTelephone(telephone) {var reg=/^[1][3,4,5,7,8][0-9]{9}$/;if (!reg.test(telephone)) {return false;} else {return true;}}/*** 身份证号码校验* 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X*/function checkIdCard(idCard){var reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;if(reg.test(idCard)){return true;}else{return false;}}var clock = '';//定时器对象,用于页面30秒倒计时效果var nums = 30;var validateCodeButton;//按钮对象//基于定时器实现30秒倒计时效果function doLoop() {validateCodeButton.disabled = true;//将按钮置为不可点击nums--;if (nums > 0) {validateCodeButton.value = nums + '秒后重新获取';} else {clearInterval(clock); //清除js定时器validateCodeButton.disabled = false;//按钮又可以点击了validateCodeButton.value = '重新获取验证码';nums = 30; //重置时间}}
以下才是登录页面
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no,minimal-ui"><meta name="description" content=""><meta name="author" content=""><link rel="icon" href="../img/asset-favico.ico"><title>登录</title><link rel="stylesheet" href="../css/page-health-login.css" /><link rel="stylesheet" href="../plugins/elementui/index.css" /><script src="../plugins/jquery/dist/jquery.min.js"></script><script src="../plugins/healthmobile.js"></script><script src="../plugins/vue/vue.js"></script><script src="../plugins/vue/axios-0.18.0.js"></script><script src="../plugins/elementui/index.js"></script></head><body data-spy="scroll" data-target="#myNavbar" data-offset="150"><div class="app" id="app"><!-- 页面头部 --><div class="top-header"><span class="f-left"><i class="icon-back"></i></span><span class="center">健康生活</span><span class="f-right"><i class="icon-more"></i></span></div><div style="margin-left: 20px">手机快速登录</div><!-- 页面内容 --><div class="contentBox"><div class="login"><form id='login-form'><div class="input-row"><label>手机号</label><div class="loginInput"><input v-model="loginInfo.telephone" id='account' type="text" placeholder="请输入手机号"><input id="validateCodeButton" @click="sendValidateCode()" type="button" style="font-size: 12px" value="获取验证码"></div></div><div class="input-row"><label>验证码</label><div class="loginInput"><input v-model="loginInfo.validateCode" style="width:80%" id='password' type="text" placeholder="请输入验证码"></div></div><div class="input-row" style="font-size: 12px"><input type="checkbox" checked>阅读并同意《健康生活用户协议》《健康生活隐私条款》</div><div class="btn yes-btn"><a @click="login()" href="#">登录</a></div></form></div></div></div></body><script>var vue = new Vue({el:'#app',data:{loginInfo:{}//登录信息},methods:{//发送验证码sendValidateCode(){//获取用户输入的手机号var telephone = this.loginInfo.telephone;//调用js方法,校验输入的手机号是否合法if(!checkTelephone(telephone)){//校验不通过,提示错误信息this.$message.error("请输入正确的手机号");return false;}//在按钮上显示30秒倒计时效果validateCodeButton = $("#validateCodeButton")[0];//锁定dom对象clock = window.setInterval(doLoop,1000);//定时器方法,可以实现每隔指定的时间调用指定的方法//发送ajax请求,为用户发送手机验证码axios.post("/validateCode/send4Login.do?telephone=" + telephone).then((res) => {if(!res.data.flag){//短信验证码发送失败this.$message.error(res.data.message);}});},//登录login(){//为了防止在输入验证码后手机号更换了或者删除了,发送无效请求,所以这里还要再对手机号进行校验//获取用户输入的手机号var telephone = this.loginInfo.telephone;//调用js方法,校验输入的手机号是否合法if(!checkTelephone(telephone)){//校验不通过,提示错误信息this.$message.error("请输入正确的手机号");return false;}//发送ajax请求,将表单数据提交到Controller进行登录处理axios.post("/member/login.do",this.loginInfo).then((res) => {if(res.data.flag){//登录成功,跳转到会员首页window.location.href = "member.html";}else{this.$message.error(res.data.message);}});}}});</script></html>
后端 发送短信服务详情见/md/?articleId=105281059
发送验证码
/*** 验证码操作*/@RestController@RequestMapping("/validateCode")public class ValidateCodeController {@Autowiredprivate JedisPool jedisPool;//用户在线预约发送验证码@RequestMapping("/send4Order")public Result send4Order(String telephone){//首先调用方法随机生成4位数字验证码Integer validateCode = ValidateCodeUtils.generateValidateCode(4);//给用户发送验证码try{//发送短信可能会出现异常,使用try catchSMSUtils.sendShortMessage(SMSUtils.VALIDATE_CODE,telephone,validateCode.toString());}catch (Exception e){e.printStackTrace();return new Result(false, MessageConstant.SEND_VALIDATECODE_FAIL);}//将验证码保存到redis(有效期5分钟)jedisPool.getResource().setex(telephone + RedisMessageConstant.SENDTYPE_ORDER,300,validateCode.toString());return new Result(true,MessageConstant.SEND_VALIDATECODE_SUCCESS);}//用户手机快速登录发送验证码@RequestMapping("/send4Login")public Result send4Login(String telephone){//随机生成6位数字验证码Integer validateCode = ValidateCodeUtils.generateValidateCode(6);//给用户发送验证码try{SMSUtils.sendShortMessage(SMSUtils.VALIDATE_CODE,telephone,validateCode.toString());}catch (Exception e){e.printStackTrace();return new Result(false, MessageConstant.SEND_VALIDATECODE_FAIL);}//将验证码保存到redis(5分钟)jedisPool.getResource().setex(telephone + RedisMessageConstant.SENDTYPE_LOGIN,300,validateCode.toString());return new Result(true,MessageConstant.SEND_VALIDATECODE_SUCCESS);}}
手机号码登录
@RestController@RequestMapping("/member")public class MemberController {@Autowiredprivate JedisPool jedisPool;@Referenceprivate MemberService memberService;//手机号快速登录@RequestMapping("/login")public Result login(HttpServletResponse response, @RequestBody Map map){String telephone = (String) map.get("telephone");//获取手机号码String validateCode = (String) map.get("validateCode");//获取验证码//从Redis中获取保存的验证码String validateCodeInRedis = jedisPool.getResource().get(telephone + RedisMessageConstant.SENDTYPE_LOGIN);//验证码输入正确if(validateCodeInRedis != null && validateCode != null && validateCode.equals(validateCodeInRedis)){//判断当前用户是否为会员(查询会员表来确定)Member member = memberService.findByTelephone(telephone);if(member == null){//不是会员,自动完成注册(自动将当前用户信息保存到会员表)member.setRegTime(new Date());member.setPhoneNumber(telephone);memberService.add(member);}//向客户端浏览器写入Cookie,内容为手机号Cookie cookie = new Cookie("login_member_telephone",telephone);cookie.setPath("/");cookie.setMaxAge(60*60*24*30);response.addCookie(cookie);//将会员信息保存到RedisString json = JSON.toJSON(member).toString();jedisPool.getResource().setex(telephone,60*30,json);return new Result(true,MessageConstant.LOGIN_SUCCESS);}else{//验证码输入错误return new Result(false, MessageConstant.VALIDATECODE_ERROR);}}}