漯河商城网站建设,下载的html文件打开乱码,wordpress自定义文章添加标签,给几个那方面网站网址手机验证码登录 1、需求分析2、数据模型3、代码开发-交互过程4、代码开发-准备工作5、代码开发-修改LoginCheckFilter6、代码开发-接口开发7、前端代码介绍8、启动测试 1、需求分析
为了方便用户登录#xff0c;移动端通常都会提供通过手机验证码登录的功能。
手机验证码登录…手机验证码登录 1、需求分析2、数据模型3、代码开发-交互过程4、代码开发-准备工作5、代码开发-修改LoginCheckFilter6、代码开发-接口开发7、前端代码介绍8、启动测试 1、需求分析
为了方便用户登录移动端通常都会提供通过手机验证码登录的功能。
手机验证码登录的优点:
方便快捷无需注册直接登录使用短信验证码作为登录凭证无需记忆密码安全
登录流程输入手机号获取验证码输入验证码点击登录登录成功 注意:通过手机验证码登录手机号是区分不同用户的标识。 2、数据模型
通过手机验证码登录时涉及的表为user表即用户表。结构如下: 3、代码开发-交互过程
在开发代码之前需要梳理一下登录时前端页面和服务端的交互过程:
在登录页面(front/page/login.html)输入手机号点击【获取验证码】按钮页面发送ajax请求在服务端调用短信服务API给指定手机号发送验证码短信在登录页面输入验证码点击【登录】按钮发送ajax请求在服务端处理登录请求
开发手机验证码登录功能其实就是在服务端编写代码去处理前端页面发送的这2次请求即可。
4、代码开发-准备工作
在开发业务功能前先将需要用到的类和接口基本结构创建好:
实体类UserMapper接口UserMapper业务层接口UserService业务层实现类UserServicelmpl控制层Usercontroller工具类SMSutils、ValidateCodeutils
工具类SMSutils阿里云短信服务
package com.mannor.reggie_take_out.Utils;import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;/*** 短信发送工具类*/
public class SMSUtils {/*** 发送短信* param signName 签名* param templateCode 模板* param phoneNumbers 手机号* param param 参数*/public static void sendMessage(String signName, String templateCode,String phoneNumbers,String param){DefaultProfile profile DefaultProfile.getProfile(cn-hangzhou, , );IAcsClient client new DefaultAcsClient(profile);SendSmsRequest request new SendSmsRequest();request.setSysRegionId(cn-hangzhou);request.setPhoneNumbers(phoneNumbers);request.setSignName(signName);request.setTemplateCode(templateCode);request.setTemplateParam({\code\:\param\});try {SendSmsResponse response client.getAcsResponse(request);System.out.println(短信发送成功);}catch (ClientException e) {e.printStackTrace();}}}
工具类ValidateCodeutils生成验证码
package com.mannor.reggie_take_out.Utils;import java.util.Random;/*** 随机生成验证码工具类*/
public class ValidateCodeUtils {/*** 随机生成验证码* param length 长度为4位或者6位* return*/public static Integer generateValidateCode(int length){Integer code null;if(length 4){code new Random().nextInt(9999);//生成随机数最大为9999if(code 1000){code code 1000;//保证随机数为4位数字}}else if(length 6){code new Random().nextInt(999999);//生成随机数最大为999999if(code 100000){code code 100000;//保证随机数为6位数字}}else{throw new RuntimeException(只能生成4位或6位数字验证码);}return code;}/*** 随机生成指定长度字符串验证码* param length 长度* return*/public static String generateValidateCode4String(int length){Random rdm new Random();String hash1 Integer.toHexString(rdm.nextInt());String capstr hash1.substring(0, length);return capstr;}
}
5、代码开发-修改LoginCheckFilter LoginCheckFilter过滤器的开发此过滤器用于检查用户的登录状态。我们在进行手机验证码登录时发送的请求需要在此过滤器处理时直接放行。注释1 在LoginCheckFilter过滤器中扩展逻辑判断移动端用户登录状态注释4-1:
package com.mannor.reggie_take_out.filter;import com.alibaba.fastjson.JSON;
import com.mannor.reggie_take_out.common.BaseContext;
import com.mannor.reggie_take_out.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;WebFilter(filterName LoginCheckFilter, urlPatterns /*)
Slf4j
public class LoginCheckFilter implements Filter {//路径匹配器支持通配符public static final AntPathMatcher PATH_MATCHER new AntPathMatcher();Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request (HttpServletRequest) servletRequest;HttpServletResponse response (HttpServletResponse) servletResponse;// 1、获取本次请求的URIString requestURI request.getRequestURI();log.info(拦截到请求{}, requestURI);//定义不需要处理的路径String[] urls new String[]{/employee/login,/employee/logout,/backend/**,/front/**,/common/**,/user/login, //移动端登录/user/sendMsg //移动端发送短信};// 2、判断本次请求是否需要处理boolean check check(urls, requestURI);// 3、如果不需要处理则直接放行if (check) {filterChain.doFilter(request, response);log.info(本次请求{}不需要处理, requestURI);return;}// 4-1、判断员工登录状态如果已登录则直接放行if (request.getSession().getAttribute(EmployeeId) ! null) {log.info(用户已经登录用户id为{}, request.getSession().getAttribute(EmployeeId));//将id存入线程变量aLong employeeId (Long) request.getSession().getAttribute(EmployeeId);BaseContext.setCurrentId(employeeId);filterChain.doFilter(request, response);return;}// 4-1、判断用户登录状态如果已登录则直接放行if (request.getSession().getAttribute(user) ! null) {log.info(用户已经登录用户id为{}, request.getSession().getAttribute(user));//将id存入线程变量aLong userId (Long) request.getSession().getAttribute(EmployeeId);BaseContext.setCurrentId(userId);filterChain.doFilter(request, response);return;}// 5、如果未登录则返回未登录结果,通过输出流方式向客户端相应数据log.info(用户未登录);response.getWriter().write(JSON.toJSONString(R.error(ONT_LOGIN)));return;}public boolean check(String[] urls, String requestURI) {for (String url : urls) {boolean match PATH_MATCHER.match(url, requestURI);if (match) {return true;}}return false;}
}6、代码开发-接口开发
package com.mannor.reggie_take_out.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mannor.reggie_take_out.Utils.SMSUtils;
import com.mannor.reggie_take_out.Utils.ValidateCodeUtils;
import com.mannor.reggie_take_out.common.R;
import com.mannor.reggie_take_out.entity.User;
import com.mannor.reggie_take_out.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpSession;
import java.util.Map;RestController
Slf4j
RequestMapping(/user)
public class UserController {Autowiredprivate UserService userService;/*** 发送短信验证码** param user* param session* return*/PostMapping(/sendMsg)public RString sendMsg(RequestBody User user, HttpSession session) {//获取手机号String phone user.getPhone();if (StringUtils.isNotEmpty(phone)) {//生成随机的6位验证码String code ValidateCodeUtils.generateValidateCode(6).toString();log.info(code{}, code);//调用阿里云提供的短信服务API完成发送短信//SMSUtils.sendMessage(杨自强的博客,SMS_462036405,phone,code);//需要将生成的验证码保存到Sessionsession.setAttribute(phone, code);return R.success(短信验证码发送成功);}return R.error(短信验证码发送失败);}PostMapping(/login)public RUser login(RequestBody Map map, HttpSession session) {log.info(map{}, map);//获取手机号String phone map.get(phone).toString();//获取验证码String code map.get(code).toString();//从Session中获取保存的验证码Object codeInSession session.getAttribute(phone);//进行验证码的比对页面提交的验证码和Session中保存的验证码比对)if (codeInSession ! null codeInSession.equals(code)) {// 如果能够比对成功说明登录成功LambdaQueryWrapperUser lambdaQueryWrapper new LambdaQueryWrapper();lambdaQueryWrapper.eq(User::getPhone, phone);User user userService.getOne(lambdaQueryWrapper);if (user null) {//判断当前手机号对应的用户是否为新用户如果是新用户就自动完成注册user new User();user.setPhone(phone);user.setStatus(1);userService.save(user);}session.setAttribute(user,user.getId());return R.success(user);}return R.error(登录失败);}
}7、前端代码介绍
登录页面
!DOCTYPE html
html langen
headmeta charsetutf-8meta http-equivX-UA-Compatible contentIEedge!-- 上述3个meta标签*必须*放在最前面任何其他内容都*必须*跟随其后 --meta nameviewportcontentwidthdevice-width, initial-scale1.0, maximum-scale1.0,user-scalableno,minimal-uititle菩提阁/titlelink relicon href../images/favico.ico!--不同屏幕尺寸根字体设置--script src../js/base.js/script!--element-ui的样式--link relstylesheet href../../backend/plugins/element-ui/index.css/!--引入vant样式--link relstylesheet href../styles/vant.min.css/!-- 引入样式 --link relstylesheet href../styles/index.css/!--本页面内容的样式--link relstylesheet href../styles/login.css/
/head
body
div idlogin v-loadingloadingdiv classdivHead登录/divdiv classdivContainerel-input placeholder 请输入手机号码 v-modelform.phone maxlength20//el-inputdiv classdivSplit/divel-input placeholder 请输入验证码 v-modelform.code maxlength20//el-inputspan clickgetCode获取验证码/span/divdiv classdivMsg v-ifmsgFlag手机号输入不正确请重新输入/divel-button typeprimary :class{btnSubmit:11,btnNoPhone:!form.phone,btnPhone:form.phone} clickbtnLogin登录/el-button
/div
!-- 开发环境版本包含了有帮助的命令行警告 --
script src../../backend/plugins/vue/vue.js/script
!-- 引入组件库 --
script src../../backend/plugins/element-ui/index.js/script
!-- 引入vant样式 --
script src../js/vant.min.js/script
!-- 引入axios --
script src../../backend/plugins/axios/axios.min.js/script
script src../js/request.js/script
script src../api/login.js/script
/body
scriptnew Vue({el: #login,data() {return {form: {phone: ,code: },msgFlag: false,loading: false}},computed: {},created() {},mounted() {},methods: {getCode() {this.form.code const regex /^(13[0-9]{9})|(15[0-9]{9})|(17[0-9]{9})|(18[0-9]{9})|(19[0-9]{9})$/;if (regex.test(this.form.phone)) {this.msgFlag false//this.form.code (Math.random()*1000000).toFixed(0) //随机生成数sendMsgApi({phone: this.form.phone})} else {this.msgFlag true}},async btnLogin() {if (this.form.phone this.form.code) {this.loading trueconst res await loginApi(this.form)this.loading falseif (res.code 1) {sessionStorage.setItem(userPhone, this.form.phone)window.requestAnimationFrame(() {window.location.href /front/index.html})} else {this.$notify({type: warning, message: res.msg});}} else {this.$notify({type: warning, message: 请输入手机号码});}}}})
/script
/html登录的js文件
function loginApi(data) {return $axios({url: /user/login,method: post,data})
}function loginoutApi() {return $axios({url: /user/loginout,method: post,})
}function sendMsgApi(data) {return $axios({url: /user/sendMsg,method: post,data})
}
8、启动测试
前端发起页面请求进行测试。