黑马点评项目总结1-使用Session发送验证码和登录login和 使用Redis存储验证码和Redis的token登录

黑马先是总结了从session实现登录,然后是因为如果使用了集群方式的服务器的话,存在集群共享session互相拷贝效率低下的问题,接着引出了速度更快的内存型的kv数据库Redis,

使用Session发送验证码和登录login

举个例子:
原来的发送验证码和登录的例子,直接在session中存验证码6

    @Override
    public 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;
    @Override
    public Result sendCode(String phone, HttpSession session) {
        if(RegexUtils.isPhoneInvalid(phone)){
            return Result.fail("手机号格式错误");
        }
        //使用了Redis存储验证码,Key是LOGIN_CODE_KEY,value是6
        stringRedisTemplate.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是6
        String 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信息转化为HashMap
        Map<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才是UserDTO
        stringRedisTemplate.opsForHash().putAll(tokenKey,userMap);
        //设置用户的登录过期时间,防止Redis存储太多用户信息导致内存占用很多
        stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);
        UserHolder.saveUser(userDTO);
//        返回token
        return 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获取token
        if (StrUtil.isBlank(token)) {
            response.setStatus(401);
            return false;
        }
        //根据token从Redis里面获取UserMap
        Map<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();
    }
}

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

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

相关文章

『Django』模型入门教程-操作MySQL

theme: smartblue 点赞 关注 收藏 学会了 本文简介 一个后台如果没有数据库可以说废了一半。日常开发中大多数时候都在与数据库打交道。Django 为我们提供了一种更简单的操作数据库的方式。 在 Django 中&#xff0c;模型(Model)是用来定义数据库结构的类。每个模型类通常对…

kali下安装使用蚁剑(AntSword)

目录 0x00 介绍0x01 安装0x02 使用1. 设置代理2. 请求头配置3. 编码器 0x00 介绍 蚁剑&#xff08;AntSword&#xff09;是一个webshell管理工具。 官方文档&#xff1a;https://www.yuque.com/antswordproject/antsword 0x01 安装 在kali中安装蚁剑&#xff0c;分为两部分&am…

matlab绘制二维曲线,如何设置线型、颜色、标记点类型、如何设置坐标轴、matlab 图表标注、在图中标记想要的点

matlab绘制二维曲线&#xff0c;如何设置线型、颜色、标记点类型、如何设置坐标轴、matlab 图表如何标注、如何在图中标记想要的点 matlab绘制二维曲线&#xff0c;如何在图中标记想要的点。。。如何设置线型、颜色、标记点类型。。。如何设置坐标轴。。。matlab 图表标注操作…

视频网站系统

摘 要 随着互联网的快速发展和人们对视频内容的需求增加&#xff0c;视频网站成为了人们获取信息和娱乐的重要平台。本论文基于SpringBoot框架&#xff0c;设计与实现了一个视频网站系统。首先&#xff0c;通过对国内外视频网站发展现状的调研&#xff0c;分析了视频网站的背景…

潮玩手办盲盒前端项目模版的技术探索与应用案例

一、引言 在数字化时代&#xff0c;随着消费者对个性化和艺术化产品的需求日益增长&#xff0c;潮玩手办和盲盒市场逐渐崭露头角。为了满足这一市场需求&#xff0c;前端技术团队需要构建一个功能丰富、用户友好的在线平台。本文旨在探讨潮玩手办盲盒前端项目模版的技术实现&a…

C++ | Leetcode C++题解之第201题数字范围按位与

题目&#xff1a; 题解&#xff1a; class Solution { public:int rangeBitwiseAnd(int m, int n) {while (m < n) {// 抹去最右边的 1n n & (n - 1);}return n;} };

序列检测器(Moore型)

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 参考代码 描述 请用Moore型状态机实现序列“1101”从左至右的不重叠检测。 电路的接口如下图所示。当检测到“1101”&#xff0c;Y输出一个时钟周期的高电平脉冲。 接口电路图如下&#xff1a; 输入描述&#xff1a…

携程任我行有什么用?

眼看一直到十月份都没啥假期了 五一出去玩买了几张携程的卡&#xff0c;想着买景点门票、酒店啥的能有优惠&#xff0c;但最后卡里的钱没用完不说&#xff0c;还有几张压根就没用出去 但是我又不想把卡一直闲置在手里&#xff0c;就怕过期了 最后在收卡云上99.1折出掉了&…

注意力机制在大语言模型中的应用

在大语言模型中&#xff0c;注意力机制&#xff08;Attention Mechanism&#xff09;用于捕获输入序列中不同标记&#xff08;token&#xff09;之间的关系和依赖性。这种机制可以动态地调整每个标记对当前处理任务的重要性&#xff0c;从而提高模型的性能。具体来说&#xff0…

Py之dashscope:dashscope的简介、安装和使用方法、案例应用之详细攻略

Py之dashscope&#xff1a;dashscope的简介、安装和使用方法、案例应用之详细攻略 目录 dashscope的简介 1、产品的主要特点和优势包括&#xff1a; dashscope的安装和使用方法 1、安装 2、使用方法 dashscope的案例应用 1、通义千问-Max&#xff1a;通义千问2.5系列 2…

Ubuntu Nvidia GPU驱动安装和故障排除

去官网 菜单列表下载&#xff0c;或者直接下载驱动 wget https://cn.download.nvidia.com/XFree86/Linux-x86_64/550.54.14/NVIDIA-Linux-x86_64-550.54.14.run 安装驱动 /data/install/NVIDIA-Linux-x86_64-550.54.14.run 执行命令&#xff0c;显示GPU情况 出错处理&…

lodash 中的 isObject 以及 isPlanObject

所以说 用isObject 检测返回true的类型 远不止Object 如果要判断一个值是否为普通对象&#xff0c;可以使用isPlainObject

技术速递|Visual Studio Code 的 .NET MAUI 扩展现已正式发布

作者&#xff1a;Maddy Montaquila 排版&#xff1a;Alan Wang 今天&#xff0c;我们非常高兴地宣布 .NET MAUI VS Code 扩展插件结束了预览阶段&#xff0c;并将包含一些期待已久的新功能 - 包括 XAML IntelliSense 和 Hot Reload&#xff01; 什么是 .NET MAUI 扩展插件&…

密码学及其应用 —— 对称加密技术

1. 对称加密、流加密和块加密 1.1 对称加密 对称加密&#xff08;也称为密钥加密&#xff09;是一种加密方式&#xff0c;其中加密和解密使用相同的密钥。这种加密方法基于二进制层面的操作&#xff0c;如XOR&#xff08;异或&#xff09;、SHIFT&#xff08;位移&#xff09;…

浅谈linux(1)

文章目录 一、linux1.1、使用终端xshell登陆到云服务器上1.2、linux一些常用命令1.2.1、一些快捷键1.2.2、关于目录的操作1.2.3、关于文件的命令1.2.4、关于目录的命令1.2.5、vim 针对文件进行编辑 一、linux linux 操作系统&#xff0c;我使用的是发行版&#xff0c;Centos7。…

【LeetCode】七、树、堆、图

文章目录 1、树结构2、二叉树3、二叉树的遍历4、堆结构&#xff08;Heap&#xff09;5、堆化6、图 1、树结构 节点、根节点、叶子节点&#xff1a; 高度、深度、层三者的示意图&#xff1a; 2、二叉树 相比其他树&#xff0c;二叉树即每个节点最多两个孩子&#xff08;两个分…

ActiveMQ camel

游览器输入地址: http://127.0.0.1:8161/admin/ 访问activemq管理台 账号和密码默认为: admin/admin# yml配置的密码也是如下的密码 activemq:url: failover:(tcp://localhost:61616)username: adminpassword: adminComponent public class ActiveMqReceiveRouter extends Rout…

手写SpringMVC之调度器DispatcherServlet

DispatcherServlet&#xff1a;分发、调度 根据上一节&#xff0c;已经实现了将controller的方法添加到容器中&#xff0c;而DispatcherServlet的作用就是接收来自客户端的请求&#xff0c;然后通过URI的组合&#xff0c;来找到对应的RequestMapping注解的方法&#xff0c;调用…

C语言 | Leetcode C语言题解之第201题数字范围按位与

题目&#xff1a; 题解&#xff1a; int rangeBitwiseAnd(int m, int n) {while (m < n) {// 抹去最右边的 1n & (n - 1);}return n; }

vue3 【提效】自动导入框架方法 unplugin-auto-import 实用教程

是否还在为每次都需要导入框架方法而烦恼呢&#xff1f; // 每次都需手动导入框架方法 import { ref } from vuelet num ref(0)用 unplugin-auto-import 来帮你吧&#xff0c;以后只需这样写就行啦&#xff01; let num ref(0)官方示例如下图 使用流程 1. 安装 unplugin-au…