🍎前言
🍐项目的背景
背景:🍉当我们在完成用户信息登录时,我们往往每次都会在数据库中查询用户的记录,生成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缓存中读取用户的数据,直接返回。这样就减轻了数据库的压力,以及服务器的压力。
如有问题,欢迎在下方评论区留言,感谢大家的支持,给个三连呗~🍒
欢迎大家关注我的微信公众号,里面分享了更多的开发技巧?