SpringBoot + Redis实现用户信息登录的缓存

news2025/1/17 21:46:37

🍎前言

🍐项目的背景

背景:🍉当我们在完成用户信息登录时,我们往往每次都会在数据库中查询用户的记录,生成token并返回给前端,不过这样会有一定的问题。

🍐造成的问题

问题:🍉每次都需要访问数据库进行查询操作,是否显得麻烦,是否会给数据库造成一定的压力?

🍐解决的方案

解决方案:🍉我们通过实现redis数据库进行用户数据的缓存,并且设置一下缓存的过期时间,从而下次再登录时,就能从redis数据库缓存中获取数据了

🍎项目的版本

🍉jdk:17

🍉springboot:3.0.2

🍉redis版本:5.0.14

🍉maven版本:3.8.8

🍉idea版本:2023

🍐引入相关依赖

我们再pom.xml引入一下redis的依赖

 <!--        redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

在application.yaml配置文件配置一下redis数据库的依赖

spring:
  data:
    redis:
      host: localhost
      port: 6379
      password: 123456
      database: 1
      timeout: 3000ms #最大等待时间,超时则抛出异常,否则请求一直等待
      lettuce:
        pool:
          max-active: 20  #最大连接数,负值表示没有限制,默认8
          max-wait: -1    #最大阻塞等待时间,负值表示没限制,默认-1
          max-idle: 8     #最大空闲连接,默认8
          min-idle: 0     #最小空闲连接,默认0

🍉注意:想要使用redis做缓存,我们必须得把我们相关的实体类实现一个序列化接口为Serializable

否则无法存储在redis中

🍎创建控制层

🍉这里我就以用户的账号和密码做登录来查询用户数据。

🌕这里先上代码,我们下面的几个对象一个个做说明

🍉redisTemplate:创建了redis模板对象

🍉userService:对user的业务层,里面写了根据用户名和密码查询用户的信息

🍉fileUploadUtil:文件上传的工具类,这里不展开讲

下面是重点了

🍉redisCacheUtils:创建了一个用于获取redis中数据缓存的工具类对象,这个后面再讲

🌕在我们的/login的接口部分中使用redisCacheUtils调用了一个方法,并且传递了以下三个对象

分别是:

🍉redisTemplate

🍉userService

🍉userDTOLogin

🌕注意:为什么需要这么传呢?由于登录的方式可能不止这一个,我们可能有许多的登陆方式,但是每次传递的最后一个参数实体类对象不一致,所以存储的key也会有相应的变化

@RestController
@RequestMapping("/pcClientUser/Login")
@Slf4j
@RequiredArgsConstructor
public class LoginController {
    // redis模板对象
    private final RedisTemplate redisTemplate;
    // user相关的业务层
    private final UserService userService;
    // 文件上传工具类
    private final FileUploadUtil fileUploadUtil;
    // 创建用户获取redis中数据缓存的工具类
    private final RedisCacheUtils redisCacheUtils;   

/**
     * 用户账号密码登录
     *
     * @param userDTOLogin
     * @return
     */
    @PostMapping("/login")
    public Result Login(@RequestBody UserDTOLogin userDTOLogin) {
        log.info("用户登录");
        UserLoginVO userInfo = redisCacheUtils.FindRedisCacheUserInfo(redisTemplate, userService, userDTOLogin);
        return Result.success(Constants.LOGIN.getValue(), userInfo);
    }
}

🍉这里是我的UserDtoLogin的代码,这里面的也就是前端传过来的账号密码

package com.sxy.recordnetwork.DTO.USER;

import lombok.*;

@NoArgsConstructor
@AllArgsConstructor
@Data
@ToString
@Builder
public class UserDTOLogin {
    // 账号
    private String userName;
    // 密码
    private String passWord;

}

🍉接下类我们来看看redisCacheUtils这个类里面有什么奇妙之处吧?

🍎创建一个redisCacheUtils工具类

package com.sxy.recordnetwork.Utils;

import com.sxy.recordnetwork.DTO.USER.UserDTOLogin;
import com.sxy.recordnetwork.DTO.USER.UserDtoEmailLogin;
import com.sxy.recordnetwork.DTO.USER.UserDtoPhoneLogin;
import com.sxy.recordnetwork.VO.User.UserLoginVO;
import com.sxy.recordnetwork.common.Result;
import com.sxy.recordnetwork.enumeration.Constants;
import com.sxy.recordnetwork.service.UserService;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * redis缓存相关操作的工具类
 */
@Component
public class RedisCacheUtils {


    /**
     * 一个用于存储在redis中的用户信息的工具类,适用于所有登录的共同抽离方法
     * 该方法用于从redis中获取用户信息
     *
     * @param redisTemplate
     * @param object
     * @return
     */
    public UserLoginVO FindRedisCacheUserInfo(RedisTemplate redisTemplate, UserService userService, Object object) {
        // 操作hash类型的redis
        HashOperations hashOperations = redisTemplate.opsForHash();
        // hash最外层的key
        String hashKey = Constants.REDIS_USER_INFO_CACHE.getValue();
        // 用户信息
        UserLoginVO userInfo = null;
        // 这里做的是账号密码登录所操作的数据
        if (object instanceof UserDTOLogin userDTOLogin) {
            hashKey += userDTOLogin.getUserName();
            // 找到用户信息直接return
            if (hashOperations.get(hashKey, userDTOLogin.getUserName()) != null) {
                // 转为用户对象
                userInfo = (UserLoginVO) hashOperations.get(hashKey, userDTOLogin.getUserName());
                // 直接返回给前端
                return userInfo;
            }
            // redis中不存在目标用户的数据情况
            // 通过数据库查询用户数据
            userInfo = userService.Login(userDTOLogin);
            // 并且将用户数据存储到redis数据库中
            hashOperations.put(hashKey, userDTOLogin.getUserName(), userInfo);
            // 设置过期时间
            redisTemplate.expire(hashKey, 7200000, TimeUnit.SECONDS);
            return userInfo;
        }
        
        // 不是目标对象直接返回null
        return null;
    }

}

🍉这个类里有一个FindRedisCacheUserInfo这个方法,也就是我控制层调用的这个方法

🍉方法中有三个参数,分别是:redisTemplate模板对象,userService对象,和object对象

🍉这个object对象很有用处。是用来根据不同登录,传递不同的对象来做类型的判断,对不同的登录操作进行存储不同的key和值

🍉首先我们通过redis模板创建一个hash类型的redis

🍉接着有一个最外层的key就是获取hash的key这里有定义为一个枚举类,具体内容可以随意加

🍉创建了一个用户信息UserLoginVo,这里的用户信息就是所有登录之后查询的用户信息进行返回

🍉接下来进行instanceof关键字的类型判断,

🍉判断传过来的类型是否是UserDTOLogin对象,是则创建该对象

🍉得到hashkey对用户名进行拼接得到一个唯一key,我这里的用户名是唯一的所以不用担心会重复

🍐用户信息不存在redis中的情况

🍉这里直接通过对象的参数,查询用户信息的方法。

🍉将用户信息存储到redis中设置hashkey进行put数据

🍉参数列表为(hash唯一key,field为用户名,数据为用户信息)

🍉直接通过redisTemplate对象属性.expire为指定的key设置过期时间

🍉参数列表为:key,时间,单位

🍉返回给控制层视图,最后控制层视图就直接返回数据给前端

🍐用户信息存在redis中的情况

🍉通过hash类型.get方法传入指定参数得到数据

🍉参数列表:hash唯一key,field为用户名

🍉查出来:不等于空就通过key和field,查询redis的用户的信息转为UserLoginVo对象

🍉返回给控制层视图,最后控制层视图就直接返回数据给前端

🍎总结

🍉以上就是今天分享的内容,在用户登录时将数据存储到redis缓存中,下次登录就无需直接访问mysql数据库层,而是直接从redis缓存中读取用户的数据,直接返回。这样就减轻了数据库的压力,以及服务器的压力。

如有问题,欢迎在下方评论区留言,感谢大家的支持,给个三连呗~🍒

欢迎大家关注我的微信公众号,里面分享了更多的开发技巧?

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】文件描述符——万字详解

目录​​​​​​​ 前言 预备知识 复习C语言的文件接口 写方式打开文件 追加方式打开文件 读方式打开文件 系统的文件接口 open close write read 文件描述符 0 & 1 & 2 理解文件描述符 文件描述符的分配规则 重定向的本质 dup2 理解Linux下一切…

vue+springboot+websocket实时聊天通讯功能

前言 在我的前一篇文章里 vuespringboot实现聊天功能 &#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388; 实现了最最基础的聊天功能&#xff0c;可以通过聊天互相给对方发送信息 &#x1f388;&#x1f388;&#x1f388;&…

每日一题 — 最小覆盖子串

76. 最小覆盖子串 - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a;暴力遍历哈希表 解法二&#xff1a;滑动窗口哈希表 定义left和right初始化为零&#xff0c;固定left&#xff0c;先向右遍历right&#xff0c;放到哈希表中这个时候我们需要统计有效字符的个数&…

企业智能EDM邮件群发推广软件哪个好?

精准、高效的电子邮件营销已经成为企业触达潜在客户、维护现有客户关系以及提升品牌影响力不可或缺的手段。在这其中&#xff0c;云衔科技以其独树一帜的智能EDM邮件营销系统解决方案&#xff0c;为企业带来了革命性的市场推广体验。 云衔科技凭借前瞻性的战略眼光和深厚的AI技…

抖音在线点赞任务发布接单运营平台PHP网站源码 多个支付通道+分级会员制度

抖音在线点赞任务发布接单运营平台PHP网站源码&#xff0c;多个支付通道分级会员制度。 介绍 1、代理裂变&#xff0c;静态返佣/动态返佣均可设置。 2、自动机器人做任务&#xff0c;任务时间可设置&#xff0c;机器人价格时间可设置。 3、后台可设置注册即送X天机器人。 …

RT-Thread在Win10下编译出现 unsupported pickle protocol: 5解决方案

调试背景&#xff1a; 在WIN10下编译RT-Thread源码&#xff1a;对象处理器平台是Microchip SAMA5D27-SOM1-EK评估板。 unsupported pickle protocol: 5 编译出现报错:ValueError : unsupported pickle protocol: 5 $ scons scons: Reading SConscript files ... Newlib ver…

c语言题目之求最大公约数

题目内容&#xff1a;求最大公约数 给定两个数&#xff0c;求这两个数的最大公约数 例如&#xff1a; 输入&#xff1a;20 40 输出&#xff1a;20 什么叫最大公约数&#xff1f; 方法分析&#xff1a; 提示&#xff1a;这里我们用辗转相除法&#xff1a; 例如&#xff1a;输…

七月论文审稿GPT第4.5版:通过15K条paper-review数据微调Llama2 70B(含各种坑)

前言 当我们3月下旬微调完Mixtral 8x7B之后(更多详见&#xff1a;七月论文大模型&#xff1a;含论文的审稿、阅读、写作、修订 )&#xff0c;下一个想微调的就是llama2 70B 因为之前积攒了不少微调代码和微调经验&#xff0c;所以3月底apple便通过5K的paper-review数据集成功…

Tensorflow2.0笔记 - 使用卷积神经网络层做CIFA100数据集训练(类VGG13)

本笔记记录CNN做CIFAR100数据集的训练相关内容&#xff0c;代码中使用了类似VGG13的网络结构&#xff0c;做了两个Sequetial&#xff08;CNN和全连接层&#xff09;&#xff0c;没有用Flatten层而是用reshape操作做CNN和全连接层的中转操作。由于网络层次较深&#xff0c;参数量…

鲁棒无监督人群计数与定位

鲁棒无监督人群计数与定位 摘要1 IntroductionMethod 摘要 现有的群体计数模型需要大量的训练数据&#xff0c;而这些数据的标注过程耗时且繁琐。为了解决这个问题&#xff0c;作者提出了一种简单而有效的人群计数方法&#xff0c;通过采用一种名为“Segment-Everything-Every…

高精度算法(1)

前言 今天来讲一讲高精度算法&#xff0c;我们说一个数据类型&#xff0c;有它的对应范围比如int类型最多 可以包含到负2的31次方到2的31次方减一 其实大概就是20亿左右那么其他的类型也同样如此 那么&#xff0c;如何解决一个很大很大的数的运算呢&#xff1f; 我们今天介…

gemini国内能用吗

gemini国内能用吗 虽然 Gemini 的具体功能和性能还未完全公开&#xff0c;但基于 Google 在 AI 领域的强大背景和技术实力&#xff0c;已经火出圈了&#xff0c;很多小伙伴已经迫不及待想了解一下它有什么优势以及如何快速使用上 首先我们来讲一下gemini的优势 多模态能力&a…

43、二叉树-验证二叉搜索树

思路&#xff1a; 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 所以对于当前节点来说&#xff1a;我的左节点要小于我&#xff0c;我的右节点要大于我&a…

顺序表详解(C语言实现)

顺序表介绍 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构&#xff0c;一般情况下采用数组存 储。在数组上完成数据的增删查改。 顺序表一般可以分为&#xff1a; 1. 静态顺序表&#xff1a;使用定长数组存储元素。 2. 动态顺序表&#xff1a;使…

世界500强:破解“智慧核能”数智化成功转型密码

近日&#xff0c;实在智能携手中国核能行业协会信息化专业委员会在中国人工智能小镇成功举办“基于大模型的RPA数字员工在核能行业实战应用案例专项培训”&#xff0c;中国核工业集团、中国广核集团、国家电力投资集团等企事业单位共同参加。中核集团作为我国核科技工业的主体&…

screen常用命令

screen是一个在Linux系统中常用的命令行终端模拟器&#xff0c;它允许用户在一个单一终端会话中管理多个终端窗口。以下是一些常用的screen命令 1、创建一个新的screen会话并命名 screen -S <name>2、control a d &#xff1a;分离&#xff08;detach&#xff09;当前的…

TensorRT从入门到了解(2)-学习笔记

目录 1.TensorRT的高性能部署简介2.TensorRT驾驭方案3.如何正确导出onnx4.动态batch和动态宽高的实现5.实现一个自定义插件6.关于封装7.YoloV5案例8.Retinaface案例9.高性能低耦合10.YOLOX集成参考 1.TensorRT的高性能部署简介 tensorRT&#xff0c;nvidia发布的dnn推理引擎&a…

Kotlin语法快速入门--变量声明(1)

Kotlin语法入门–变量声明&#xff08;1&#xff09; 文章目录 Kotlin语法入门--变量声明&#xff08;1&#xff09;一、变量声明1、整型2、字符型3、集合3.1、创建array数组3.2、创建list集合3.3、不可变类型数组3.4、Set集合--不重复添加元素3.5、键值对集合Map 4、kotlin特有…

yolov8 区域计数

yolov8 区域计数 1. 基础2. 计数功能2.1 计数模块2.2 判断模块 3. 主代码4. 实验结果5. 源码 1. 基础 本项目是在 WindowsYOLOV8环境配置 的基础上实现的&#xff0c;测距原理可见上边文章 2. 计数功能 2.1 计数模块 在指定区域内计数模块 def count_objects_in_region(bo…

浅谈rDNS在IP情报建设中的应用

在当今数字化世界中&#xff0c;互联网已经成为人们日常生活和商业活动中不可或缺的一部分。在这个庞大而复杂的网络生态系统中&#xff0c;IP地址是连接和识别各种网络设备和服务的基础。然而&#xff0c;仅仅知道一个设备的IP地址并不足以充分理解其在网络中的角色和行为。为…