①实现基于session的登录流程:发送验证码、登录注册、校验登陆状态

在这里插入图片描述

个人简介:Java领域优质创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~
个人主页:.29.的博客
学习社区:进去逛一逛~

在这里插入图片描述

登录功能 实现

  • 实现基于session的登录流程:发送验证码、登录注册、校验登陆状态
    • 🚀流程介绍
      • ①验证码发送
      • ②用户登录、注册
      • ③校验登录状态
    • 🚀代码实现


实现基于session的登录流程:发送验证码、登录注册、校验登陆状态


🚀流程介绍

登录流程

①验证码发送

  • 发送验证码

    • 用户输入手机号,点击发送按钮进行手机号提交,程序会校验手机号是否合法,不合法时要求用户重新输入手机号,合法则在后台生成对应的验证码并保存至session,之后通过短信方式将验证码发送给用户。

      • 什么是HttpSession?

      • HttpSession是Java Web中的一个接口,它提供了一种在服务器端存储和检索用户相关信息的机制。当用户第一次访问Web应用程序时,服务器会为该用户创建一个唯一的session ID,并将该ID存储在一个名为JSESSIONID的cookie中,然后将该ID与一个新的HttpSession对象相关联。在用户与Web应用程序交互期间,可以使用HttpSession对象来存储和检索与该用户相关的信息。当用户关闭浏览器或超过session超时时间时,session对象将被销毁。

        以下是获取和使用HttpSession对象的常用方法:

        1.获取HttpSession对象:

         HttpSession session = request.getSession();
        

        2.向session中存储数据:

         session.setAttribute("key", value);
        

        3.从session中获取数据:

         Object value = session.getAttribute("key");
        

        4.从session中删除数据:

         session.removeAttribute("key");
        

        5.使session失效:

         session.invalidate();
        

②用户登录、注册

  • 注册、登录
    • 用户将手机号、验证码输入,后台从session中获取验证码与用户输入的验证码进行比对校验,如果不一致则无法通过校验,提示用户验证码错误,验证码一直则后台根据手机号查询用户,若用户不存在,则为用户创建账号信息并保存至数据库中,最后无论用户是否存在,都将用户的信息保存至session中,方便后续业务获取当前用户信息。

③校验登录状态

  • 校验登陆状态

    • 用户在客户端发起请求时,Cookie会携带用户的 JsessionId 后台,后台根据 JsessionId 从session中获取用户信息,如果没有用户信息就表示未登录,会对请求进行拦截,如果有用户信息,将其存入到本地线程 ThreadLocal 中并放行。

      • 为什么使用ThreadLocal:

        • 每个用户其实对应都是去找tomcat线程池中的一个线程来完成工作的, 使用完成后再进行回收,既然每个请求都是独立的,所以在每个用户去访问我们的工程时,我们可以使用threadlocal来做到线程隔离,每个线程操作自己的一份数据。
      • 什么是 JsessionId ?

        • JSessionId是Java Web应用程序中的一个会话标识符,用于跟踪用户与Web应用程序之间的会话。当用户第一次访问Web应用程序时,服务器会为该用户创建一个唯一的JSessionId,并将其存储在cookie中。在随后的请求中,浏览器会将该cookie发送回服务器,以便服务器可以识别用户并维护会话状态。

          在Java Web应用程序中,可以使用HttpSession对象来访问和管理会话状态。




🚀代码实现

业务逻辑实现


  • 统一返回类型 实体类

    • @Data
      @NoArgsConstructor
      @AllArgsConstructor
      public class Result {
          private Boolean success;
          private String errorMsg;
          private Object data;
          private Long total;
      
          public static Result ok(){
              return new Result(true, null, null, null);
          }
          public static Result ok(Object data){
              return new Result(true, null, data, null);
          }
          public static Result ok(List<?> data, Long total){
              return new Result(true, null, data, total);
          }
          public static Result fail(String errorMsg){
              return new Result(false, errorMsg, null, null);
          }
      }
      
      



  • 校验手机号、邮箱、验证码格式

    • public class RegexUtils {
          /**
           * 是否是无效手机格式
           * @param phone 要校验的手机号
           * @return true:符合,false:不符合
           */
          public static boolean isPhoneInvalid(String phone){
              return mismatch(phone, RegexPatterns.PHONE_REGEX);
          }
          /**
           * 是否是无效邮箱格式
           * @param email 要校验的邮箱
           * @return true:符合,false:不符合
           */
          public static boolean isEmailInvalid(String email){
              return mismatch(email, RegexPatterns.EMAIL_REGEX);
          }
      
          /**
           * 是否是无效验证码格式
           * @param code 要校验的验证码
           * @return true:符合,false:不符合
           */
          public static boolean isCodeInvalid(String code){
              return mismatch(code, RegexPatterns.VERIFY_CODE_REGEX);
          }
      
          // 校验是否不符合正则格式
          private static boolean mismatch(String str, String regex){
              if (StrUtil.isBlank(str)) { //Hutool工具:StrUtil
                  return true;
              }
              return !str.matches(regex);
          }
      }
      
      



  • 发送短信验证码 业务

    •     @Override
          public Result sendCode(String phone, HttpSession session) {
              //1. 手机号不合法?
              if(RegexUtils.isPhoneInvalid(phone)){
                  //2. 不合法,返回错误信息
                  return Result.fail("手机号格式错误!");
              }
      
              //3. 借助工具类,生成验证码(Hutool工具)
              String code = RandomUtil.randomNumbers(6);
      
              //4. 保存验证码至session域
              session.setAttribute("code",code);
      
              //5. 发送验证码
              log.debug("发送短信验证码成功,验证码: " + code);  //日志、方便控制台查看
              /*
                  调用验证码服务...(具体逻辑参照具体服务供应商的文档)
              */
      
              //6. 返回ok
              return Result.ok();
          }
      



  • 登录、注册 业务

    •     /**
           *   session实现登录功能
           * @param loginForm
           * @param session
           * @return
           */
          @Override
          public Result login(LoginFormDTO loginForm, HttpSession session) {
              //1. 校验手机号
              String phone = loginForm.getPhone();
              if(RegexUtils.isPhoneInvalid(phone)){
                  //2. 返回错误信息
                  return Result.fail("手机号格式错误");
              }
      
              //3. 校验验证码
              Object cacheCode = session.getAttribute("code");
              String code = loginForm.getCode();
              if(code == null || !code.toString().equals(cacheCode)){
                  //不一致,返回错误信息
                  return Result.fail("验证码错误");
              }
      
              // 一致,根据手机号获取用户
              User user = this.query().eq("phone", phone).one(); //(mybatisPlus提供的Service层方法)
      
              //5. 判断用户是否存在
              if(user == null){
                  //6. 不存在,创建新用户
                  user = new User();
                  user.setPhone(phone); //设置phone
                  user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(10)); //设置随机昵称
                  this.save(user); // 存入数据库(mybatisPlus提供的Service层方法)
              }
      
              //7. 用户存在,存入session域
              session.setAttribute("user", BeanUtil.copyProperties(user, UserDTO.class));
      
              //返回ok
              return Result.ok();
          }
      



  • 创建并设置ThreadLocal 自定义工具类

    • public class UserHolder {
          private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();
      
          public static void saveUser(UserDTO user){
              tl.set(user);
          }
      
          public static UserDTO getUser(){
              return tl.get();
          }
      
          public static void removeUser(){
              tl.remove();
          }
      }
      



  • 校验登陆状态 拦截器

    • /**
       * TODO 登录 拦截器
       * @author .29.
       * @create 2023-11-26 16:37
       */
      
      public class LoginInterceptor implements HandlerInterceptor {
          
          @Override
          public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
              // 1.获取session
              HttpSession session = request.getSession();
      
              //2. 获取用户
              Object user = session.getAttribute("user");
      
              //3. 验证用户是否存在
              if(user == null){
                  //4. 不存在,进行拦截,返回401状态码
                  response.setStatus(401);
                  return false;
              }
      
              //5. 存在,存入ThreadLocal(自定义工具类UserHolder,作用:创建并设置ThreadLocal)
              UserHolder.saveUser((UserDTO) user);
      
              //6. 放行
              return true;
          }
          
      }    
      
      • Spring Boot使用Spring MVC拦截器的步骤如下:

        • 1.创建一个拦截器类并实现HandlerInterceptor接口,该接口包含三个方法:preHandle、postHandle和afterCompletion。preHandle方法在请求处理之前调用,postHandle方法在请求处理之后调用,afterCompletion方法在视图渲染之后调用。

        • 2.在拦截器类上使用@Component@Configuration注解将其声明为Spring组件。

        • 3.创建一个配置类并实现WebMvcConfigurer接口,该接口包含一个addInterceptors方法,用于注册拦截器。

        • 4.在addInterceptors方法中使用addInterceptor方法注册拦截器,并使用addPathPatterns方法指定要拦截的请求路径。



  • 使拦截器生效 SpringMvc配置类

    • /**
       * TODO SpringMVC配置类,使拦截器生效
       * @author .29.
       * @create 2023-11-26 16:49
       */
      @Configuration
      public class MvcConfig implements WebMvcConfigurer {
      
          @Resource
          private StringRedisTemplate stringRedisTemplate;
      
          @Override
          public void addInterceptors(InterceptorRegistry registry) {
              //1. 添加登录拦截器、同时设置无需拦截的路径
              registry.addInterceptor(new LoginInterceptor()).excludePathPatterns(
                      "/shop/**",
                      "/voucher/**",
                      "/shop-type/**",
                      "/upload/**",
                      "/blog/hot",
                      "/user/code",
                      "/user/login"
              ).order(0); //order默认0,order值越大拦截器越后执行
          }
          
      }
      
      




在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/195860.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JS:获取当前日期是本年度的第几周

问题 根据当前的日期&#xff08;比如年月日&#xff09;&#xff0c;来得到当前日期属于本年度的第几周 解决 代码&#xff1a; // 获取当前日期是本年的第几周 //参数&#xff1a; a为年 b为月 c为日 function getYearWeek(a, b, c) {var date1 new Date(a, parseInt(b)…

通过火狐Firefox浏览器在设备间留言、传递备注消息

如果多台设备间没有都安装微信、飞书这种可以通过文件传输助手备注消息的APP&#xff0c;那么可通过火狐浏览器在设备间留言。 原理&#xff1a;火狐支持把当前设备的一个浏览器标签页发送到其他设备 那么我们只需要把要留言的文本记录到一个网页&#xff0c;然后发送到其他设…

【前端首屏加载速度优化(0): 谷歌浏览器时间参数】

DOMContentLoaded 浏览器已经完全加载了 HTML&#xff0c;DOM树构建完成&#xff0c;但是像是 <img> 和样式表等外部资源可能并没有下载完毕。 Load DOM树构建完成后&#xff0c;继续加载 html/css 中的外部资源&#xff0c;加载完成之后&#xff0c;视为页面加载完成。…

四川开启智能巡河形式,无人机水利行业应用再创新

在四川省某区域&#xff0c;复亚智能无人机系统以其独特的机场网格化部署得到成功应用&#xff0c;覆盖了该区域内多条市级、省级河流&#xff0c;成为水利行业的新亮点。这一先进系统以无人机水利行业应用为核心&#xff0c;通过网格化和信息化手段&#xff0c;实现了对水域环…

吉利展厅 | 透明OLED拼接2x2:科技与艺术的完美融合

产品&#xff1a;4块55寸OLED透明拼接屏 项目地点&#xff1a;南宁 项目时间&#xff1a;2023年11月 应用场景&#xff1a;吉利展厅 在2023年11月的南宁&#xff0c;吉利展厅以其独特的展示设计吸引了众多参观者的目光。其中最引人注目的亮点是展厅中央一个由四块55寸OLED透…

Mysql并发时常见的死锁及解决方法

使用数据库时&#xff0c;有时会出现死锁。对于实际应用来说&#xff0c;就是出现系统卡顿。 死锁是指两个或两个以上的事务在执行过程中&#xff0c;因争夺资源而造成的一种互相等待的现象。就是所谓的锁资源请求产生了回路现象&#xff0c;即死循环&#xff0c;此时称系统处于…

Jetpack Compose中适应性布局的新API

Jetpack Compose中适应性布局的新API 针对大屏幕优化的新组合件。 使用新的Material适应性布局&#xff0c;为手机、可折叠设备和平板电脑构建应用程序变得更加简单&#xff01;市场上各种不同尺寸的Android设备的存在挑战了构建应用程序时对屏幕尺寸的通常假设。开发者不应该…

AI辅助工具

任务拆解工具 Magic ToDo - GoblinTools 可用的AI搜索和对话工具&#xff1a;chatgpt 梦畅AI

《山水间的家》第二季收官,国台酒业解锁中国式浪漫

执笔 | 洪大大 编辑 | 萧 萧 近日&#xff0c;由国台酒特别支持的大型文旅探访节目《山水间的家》第二季在总台央视综合频道&#xff08;CCTV-1&#xff09;正式收官。 第二季节目以家庭为视角切入&#xff0c;先后走进江苏、四川、重庆、江西、湖北、贵州、浙江等地24个特色…

TS版LangChain实战:基于文档的增强检索(RAG) | 京东云技术团队

LangChain LangChain是一个以 LLM &#xff08;大语言模型&#xff09;模型为核心的开发框架&#xff0c;LangChain的主要特性&#xff1a; 可以连接多种数据源&#xff0c;比如网页链接、本地PDF文件、向量数据库等允许语言模型与其环境交互封装了Model I/O&#xff08;输入…

实用又好用Mybatis-Plus版的EasyCode模板

1&#xff1a;插件下载 Plugins中搜索EasyCode,并且下载安装 2&#xff1a;模板编写 2.1&#xff1a;entity.vm.java模板 ##引入宏定义 $!{define.vm}##使用宏定义设置回调&#xff08;保存位置与文件后缀&#xff09; #save("/entity", "DO.java")##使…

03 项目运行

前面两篇文章对项目架构+源码架构做了分析,这篇文章先将服务部署一下,能够让大家有个直观的感受。 组件资源 项目运行的各种组件已经为你准备好了,有需要的直接百度云盘下载: 链接:https://pan.baidu.com/s/1hN6qf20gamMHPmA_qXwsLg提取码:o4k9MySQL数据库创建 找到的…

四川天蝶电子商务有限公司真实可靠吗?

随着数字经济的不断发展&#xff0c;抖音电商服务日益成为企业拓展销售渠道、提升品牌影响力的关键一环。在这样的大背景下&#xff0c;四川天蝶电子商务有限公司凭借其专业的服务能力和创新的技术手段&#xff0c;迅速崛起为抖音电商服务领域的领军企业。 四川天蝶电子商务有限…

Ubuntu系统Springboot项目Nginx安装(编译安装方式)

1.下载 nginx官网下载 Index of /download/ 2.解压 这里我下载的1.25.3版本&#xff0c;系统是ubuntu 解压 tar -zxvf nginx-1.25.3.tar.gz 3.编译安装 安装前需要执行安装一些系统依赖 3.1安装PCRE库 ubuntu&#xff1a;执行以下命令 sudo apt-get install libpcre…

每日一练2023.11.28———N个数求和【PTA】

题目链接&#xff1a; L1-009 N个数求和 题目要求&#xff1a; 本题的要求很简单&#xff0c;就是求N个数字的和。麻烦的是&#xff0c;这些数字是以有理数分子/分母的形式给出的&#xff0c;你输出的和也必须是有理数的形式。 输入格式&#xff1a; 输入第一行给出一个正整…

【影刀RPA_写入日期到飞书表格】

飞书将日期写入多维表格&#xff0c;日期格式需要时毫秒级的时间戳才行。

已知两个链表L1和L2分别表示两个集合,其中元素递增排列。请设计一个算法,用于求出L1与L2的交集,并存放在L1链表中

已知两个链表L1和L2分别表示两个集合&#xff0c;其中元素递增排列。请设计一个算法&#xff0c;用于求出L1与L2的交集&#xff0c;并存放在L1链表中。 代码思路&#xff1a; 我们创建一个辅助链表L3&#xff0c;用于存储L1和L2链表的交集&#xff0c;用s遍历L3各个元素 用p和…

常见加密算法

常见加密算法 加密算法是一种用数学方法对数据进行变换的技术&#xff0c;目的是保护数据的安全&#xff0c;防止被未经授权的人读取或修改。加密算法可以分为三大类&#xff1a;对称加密算法、非对称加密算法和哈希算法&#xff08;也叫摘要算法&#xff09;。 哈希算法 哈…

C++之STL库:string类(用法列举和总结)

前言 大家在学习STL库的时候一定要学会看英文文档&#xff0c;俗话说熟能生巧&#xff0c;所以还得多练&#xff01;在使用string类之前&#xff0c;要包含头文件#include <string>和using namespace std; 文档链接&#xff1a;string - C Reference 一、string——构造…

简易版扫雷+代码分析

前言&#xff1a; 实验一个简易版的扫雷&#xff0c;也要两百来行的代码&#xff0c;因此为了代码整洁&#xff0c;维护起来方便&#xff0c;这里我们和前期实现的三子棋一样&#xff0c;也弄一个游戏的头文件game.h用来装各种头文件以及函数的声明以及宏定义、预处理信息&…