黑马点评项目总结1-使用Session发送验证码和登录login和 使用Redis存储验证码和Redis的token登录
黑马先是总结了从session实现登录,然后是因为如果使用了集群方式的服务器的话,存在集群共享session互相拷贝效率低下的问题,接着引出了速度更快的内存型的kv数据库Redis,
使用Session发送验证码和登录login
举个例子:
原来的发送验证码和登录的例子,直接在session中存验证码6
@Overridepublic Result sendCode(String phone, HttpSession session) {if(RegexUtils.isPhoneInvalid(phone)){return Result.fail("手机号格式错误");}//我这里瞎勾八写的验证码是6,图省事session.setAttribute("code","6");return Result.ok();}
从session中获取验证码,然后与从表单输入的验证码相比较,如果一致,那么就是验证码正确,query()方法是查询tb_user中的用户,利用phone字段查询用户,然后如果查询出来用户那么就利用这个电话字段创建用户user对象,如果没查出来,就自动创建新的用户,然后存在UserHolder里面,UserHolder是用静态ThreadLocal存储的User对象。
@Override public Result login(LoginFormDTO loginFormDTO, HttpSession session) {String phone = loginFormDTO.getPhone();if(RegexUtils.isPhoneInvalid(phone)){return Result.fail("手机号格式错误");}String code = (String) session.getAttribute("code");if(code == null || !code.equals("6")){return Result.fail("验证码错误");}User user = query().eq("phone", phone).one();if(user == null){user = createUser(phone);}session.setAttribute("user",user);UserHolder.saveUser(user);return Result.ok();}
接着如果登录的话,前端界面用户的界面是访问/user/me来返回用户信息,注意这里的me函数一定要返回user,否则黑马点评的界面会又再次跳转到登录界面,非常✓8。黑马点评项目登录有好几次都是因为这个UserHolder的UserDTO为空导致又跳转到登录界面,非常✓8。
@GetMapping("/me")public Result me(){// TODO 获取当前登录的用户并返回UserDTO user = UserHolder.getUser();log.debug("me:{}", user);return Result.ok(user);}
使用Redis存储验证码和Redis的token登录
UserServicelmpl.java,注意,我们使用Redis返回token的时候,Key是token,存储的是UserMap,UserMap是存储了UserDTO信息的,UserDTO存储了用户信息,包括他的phone,因此,token是和电话号码存在一一对应关系的!!我们后续拦截器拦截的时候,获取了Token之后,利用获取到的Token去Redis里面查询的时候就知道是哪个用户了!!!
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {@Resource private StringRedisTemplate stringRedisTemplate;@Overridepublic Result sendCode(String phone, HttpSession session) {if(RegexUtils.isPhoneInvalid(phone)){return Result.fail("手机号格式错误");}//使用了Redis存储验证码,Key是LOGIN_CODE_KEY,value是6stringRedisTemplate.opsForValue().set(RedisConstants.LOGIN_CODE_KEY,"6",RedisConstants.LOGIN_CODE_TTL,TimeUnit.MINUTES);log.debug("发送验证码成功");return Result.ok();}@Override public Result login(LoginFormDTO loginFormDTO, HttpSession session) {String phone = loginFormDTO.getPhone();if(RegexUtils.isPhoneInvalid(phone)){return Result.fail("手机号格式错误");}//从内存式的Redis数据库中获取验证码,Key是LOGIN_CODE_KEY,value是6String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY );String code = loginFormDTO.getCode();if(code == null || !code.equals(cacheCode)){return Result.fail("验证码错误");}User user = query().eq("phone", phone).one();if(user == null){user = createUser(phone);}String token = UUID.randomUUID().toString(true);//不存储User,只存储UserDTO,减轻存储压力,避免存储敏感信息UserDTO userDTO= BeanUtil.copyProperties(user,UserDTO.class);//把UserDTO信息转化为HashMapMap<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));String tokenKey = LOGIN_USER_KEY + token;//把登录的这个用户以hashMap方式存储到Redis之中,token为Key,取出来的Value才是UserDTOstringRedisTemplate.opsForHash().putAll(tokenKey,userMap);//设置用户的登录过期时间,防止Redis存储太多用户信息导致内存占用很多stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);UserHolder.saveUser(userDTO);
// 返回tokenreturn Result.ok(token);}private User createUser(String phone) {User user = new User();user.setPhone(phone);user.setNickName("user"+ RandomUtil.randomString(10));return user;}
}
拦截器设置:
拦截器前端

拦截器后端
LoginInterceptor.java
UserServicelmpl.java的@Override public Result login(LoginFormDTO loginFormDTO, HttpSession session)函数return Result.ok(token);直接返回了token到前端界面,前端界面再把这个token存储到请求头的’authorization’里面。
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {private StringRedisTemplate stringRedisTemplate;public LoginInterceptor(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}@Override // 拦截请求public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("authorization");//根据authorization获取tokenif (StrUtil.isBlank(token)) {response.setStatus(401);return false;}//根据token从Redis里面获取UserMapMap<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(LOGIN_USER_KEY + token);//把UserMap从HashMap形式转化为Java Bean。UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);//存储到UserHolder的ThreadLocal里面UserHolder.saveUser(userDTO);//刷新过期时间stringRedisTemplate.expire(LOGIN_USER_KEY + token, RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);// 放行return true;}@Override // 拦截响应public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 移除用户UserHolder.removeUser();}
}
相关文章:
黑马点评项目总结1-使用Session发送验证码和登录login和 使用Redis存储验证码和Redis的token登录
黑马先是总结了从session实现登录,然后是因为如果使用了集群方式的服务器的话,存在集群共享session互相拷贝效率低下的问题,接着引出了速度更快的内存型的kv数据库Redis, 使用Session发送验证码和登录login 举个例子:…...
【大模型】Vllm基础学习
前言:vllm是一个大语言模型高速推理框架,旨在提高大模型的服务效率。优势是内存管理,实现的核心是pageattetion算法。仅在gpu上加速,不在cpu加速。 目录 1. PageAttention2. 实践2.1 安装2.2 离线推理2.3 适配OpenAI的api 1. Page…...
使用vue动态给同一个a标签添加内容 并给a标签设置hover,悬浮文字变色,结果鼠标悬浮有的字上面不变色
如果Vue的虚拟DOM更新机制导致样式更新不及时,你可以尝试以下几种方法来解决这个问题: 确保使用响应式数据: 确保你使用的数据是响应式的,并且任何对这些数据的更改都会触发视图的更新。在Vue中,你应该使用data对象中的…...
【ajax实战06】进行文章发布
本文章目标:收集文章内容,并提交服务器保存 一:基于form-serialize插件收集表单数据 form-serialize插件仅能收集到表单数据,除此之外的数据无法收集到 二:基于axios提交到服务器保存 三:调用alert警告…...
Codeforces Round 954 (Div. 3)(A~E)
目录 A. X Axis B. Matrix Stabilization C. Update Queries D. Mathematical Problem A. X Axis Problem - A - Codeforces 直接找到第二大的数,答案就是这个数与其他两个数的差值的和。 void solve() {vector<ll>a;for (int i 1; i < 3; i){int x;…...
基于Java微信小程序同城家政服务系统设计和实现(源码+LW+调试文档+讲解等)
💗博主介绍:✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码数据库🌟感兴趣的可以先收藏起来,还…...
[21] Opencv_CUDA应用之使用Haar级联的对象检测
Opencv_CUDA应用之使用Haar级联的对象检测 Haar级联使用矩形特征来检测对象,它使用不同大小的矩形来计算不同的线和边缘特征。矩形包含一些黑色和白色区域,如下图所示,它们在图像的不同位置居中 类Haar特征检测算法的思想是计算矩形内白色像素和黑色像素之间的差异这个方法的…...
CXL:拯救NVMe SSD缓存不足设计难题-2
LMB提出了基于CXL协议的内存扩展框架和内核模块。该方案利用CXL内存扩展器作为物理DRAM源,旨在提供一个统一的内存分配接口,使PCIe和CXL设备都能方便地访问扩展的内存资源。通过这个接口,NVMe驱动和CUDA的统一内存内核驱动可以直接高效地访问…...
Opencv学习项目6——pyzbar
在之前我们学习了解码图片中的二维码,这次我们开启摄像头来解码视频中二维码 开启摄像头 # 打开摄像头 cap cv2.VideoCapture(0) cap.set(3, 640) # 设置摄像头画面宽度 cap.set(4, 480) # 设置摄像头画面高度 我使用的是笔记本上的摄像头来进行的,…...
Switch 刷安卓11 (LineageOS 18.1) 大气层双系统图文教程
很多朋友手上已经拥有了完成硬破的 Switch ,但又不甘心仅仅使用 Switch 本身的地平线系统,Switch 刷安卓 (Android 11) 会是一个好的选择,虽然 Switch 的 CPU 性能拉跨,但和桌面平台同一设计思路的TegraX1 GPU 可谓是先于时代&…...
Spring Boot与Spring Batch的深度集成
Spring Boot与Spring Batch的深度集成 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将深入探讨在Spring Boot应用中如何实现与Spring Batch的深度集成…...
RTSP协议在视频监控系统中的典型应用、以及视频监控设备的rtsp地址格式介绍
目录 一、协议概述 1、定义 2、提交者 3、位置 二、主要特点 1、实时性 2、可扩展性 3、控制功能 4、回放支持 5、网络适应性 三、RTSP的工作原理 1、会话准备 2、会话建立 3、媒体流控制 4、会话终止 5、媒体数据传输 四、协议功能 1、双向性 2、带外协议 …...
Kotlin基础——异步和并发
同步和异步 同步指的是一种行为:当执行IO操作的时候,在代码层面上我们需要主动去等待结果,直到结果返回阻塞指的是一种状态:当执行IO操作的时候,线程处于挂起状态,就是该线程没有执行了 故同步不是阻塞&a…...
消防认证-防火卷帘
一、消防认证 消防认证是指消防产品符合国家相关技术要求和标准,且通过了国家认证认可监督管理委员会审批,获得消防认证资质的认证机构颁发的证书,消防产品具有完好的防火功能,是住房和城乡建设领域验收的重要指标。 二、认证依据…...
SpringBoot3.3集成knif4j-swagger文档方式和使用案例
springboot3 集成 knif4j : 访问地址: swagger 接口文档默认地址:http://localhost:8080/swagger-ui.html# Knife4j 接口文档默认地址:http://127.0.0.1:8080/doc.html Maven: <dependency><groupId>com.github.x…...
老年服务与管理实训室:制定教学模式
随着我国人口老龄化程度的加深,如何为老年人提供优质的养老服务成为社会关注的重点。作为培养老年服务人才的重要阵地,老年服务与管理实训室应制定科学合理的教学模式,满足行业发展需求,培养出高素质的老年服务专业人才。本文针对老年服务与管理实训室的教学模式展开探讨,提出相…...
4、DDD、中台和微服务的关系
DDD、中台和微服务的关系 1 DDD和中台的本质 领域驱动设计(DDD)和中台在企业架构中有着密切的关系。DDD的本质在于通过对业务领域的深入分析和建模,构建高内聚、低耦合的系统。而中台则是对企业核心业务能力的抽象和封装,以实现…...
【ACM出版,马来西亚-吉隆坡举行】第四届互联网技术与教育信息化国际会议 (ITEI 2024)
作为全球科技创新大趋势的引领者,中国不断营造更加开放的科技创新环境,不断提升学术合作的深度和广度,构建惠及各方的创新共同体。这是对全球化的新贡献,是构建人类命运共同体的新贡献。 第四届互联网技术与教育信息化国际学术会议…...
走进IT的世界
引言 随着高考的结束,对于即将踏入IT(信息技术)领域的新生而言,这个假期不仅是放松身心的时间,更是提前规划、深化专业知识、为大学生活奠定坚实基础的宝贵机会。以下是一份详尽的高考假期预习与规划指南,…...
Linux 时区文件编译器 zic【man 8 zic】
1. NAME(名) zic - 时区编译器 2. SYNOPSIS(概要) zic [-v] [-d directory] [-l localtime] [-p posixrules] [-L leapsecondfilename] [-s] [-y command] [filename ...]3. DESCRIPTION(函数描述) zic…...
FastAdmin二次开发指南:如何基于这套开源CMS源码定制你的专属内容模型?
FastAdmin二次开发实战:从零构建自定义内容模型 在开源CMS领域,FastAdmin以其基于ThinkPHP的优雅架构和丰富的功能模块,成为众多开发者快速构建后台管理系统的首选。但真正体现其价值的,往往是在面对个性化业务需求时的二次开发能…...
Ollama安装路径优化:从C盘迁移到D盘的完整指南
1. 为什么需要迁移Ollama到D盘? 很多AI开发者在Windows系统上初次安装Ollama时,都会遇到一个头疼的问题——默认安装路径在C盘。随着模型文件的不断下载和项目积累,C盘空间很快就会被占满。我自己就经历过C盘爆红的尴尬,系统卡顿不…...
从WiFi4到WiFi7:一张表格看懂所有代际的真实网速差距(附选购建议)
从WiFi4到WiFi7:四代协议性能全景对比与智能组网决策指南 当你在电商平台搜索"WiFi6路由器"时,超过200款不同价位的设备会瞬间涌入视野。从299元的入门款到4999元的旗舰机型,商家宣传的"AX3000"、"BE6500"等参…...
别再踩坑了!AgentScope调用本地MCP服务,用StdIOStatefulClient才是正确姿势
深度解析AgentScope集成MCP服务的正确实践:从协议匹配到高效调试 在AI应用开发领域,服务集成是构建复杂系统的关键环节。当开发者尝试将AgentScope与MCP服务结合时,往往会遇到各种意料之外的连接问题。这些问题的根源通常不在于代码逻辑本身&…...
Vivado实战:从零封装自定义接口IP核的完整流程
1. 为什么需要封装自定义IP核 第一次接触FPGA开发时,我总喜欢把整个工程的所有代码都堆在一个项目里。直到某天需要复用之前的HDMI显示模块时,才发现要手动复制几十个文件,还得逐个修改端口连接。这种重复劳动让我意识到:封装IP核…...
别再被MPU6050的偏航角坑了!手把手教你用MPU9250(或外接HMC5883L磁力计)彻底解决零飘问题
彻底解决MPU6050偏航角零飘:硬件升级与磁力计融合实战指南 在无人机、平衡车和机器人姿态控制领域,MPU6050曾是许多开发者的首选惯性测量单元(IMU)。这款经典的六轴传感器以低廉的价格和稳定的性能赢得了市场,但它的一个致命缺陷让无数工程师…...
Magika:AI驱动的文件类型检测神器,准确率高达99%+
Magika:AI驱动的文件类型检测神器,准确率高达99% 【免费下载链接】magika 项目地址: https://gitcode.com/GitHub_Trending/ma/magika 你是否曾经遇到过这样的情况:下载了一个文件却不知道它是什么格式?或者在处理大量文件…...
一文搞懂 Spring Cloud:从入门到实战的微服务全景指南(建议收藏)
如果你正在做后端开发,或者正在准备找实习/秋招,那你一定绕不开一个关键词:微服务。 而在 Java 技术栈中,微服务的“标配方案”,就是今天的主角——Spring Cloud。 很多同学第一次接触 Spring Cloud 时,都…...
攻防世界 misc题GFSJ1129-【您看我还有机会吗?】
1.工具:010editor、VMware(Ubuntu、binwalk)、在线 Brainfuck解密、CTF-Tools、ImageStrike、7zFM 2.解题: 方法一(最初的解法): 下载附件后,我们打开,发现有一张图片,点击后发现要密码,我发现没有任何密码的提示,怀疑是伪加密(由于篇幅较长,我后续会在写一篇…...
5分钟上手:在浏览器中创造惊艳的流体艺术特效
5分钟上手:在浏览器中创造惊艳的流体艺术特效 【免费下载链接】WebGL-Fluid-Simulation Play with fluids in your browser (works even on mobile) 项目地址: https://gitcode.com/gh_mirrors/web/WebGL-Fluid-Simulation 想要在浏览器中体验令人惊叹的流体…...
