Redis学习------实战篇----2024/02/28

1.集群的session共享问题

在这里插入图片描述

2.基于Redis实现共享session登录

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


//4.保存验证码到redisstringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY+phone,code,LOGIN_CODE_TTL, TimeUnit.MINUTES);

RedisTemplate
RedisTemplate使用的是JdkSerializationRedisSerializer存入数据,会将数据先序列化成字节数组,然后在存入Redis数据库。

如果数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好的选择

你会看到你的数据不是以可读的形式展现的,而是以字节数组显示

当然从Redis获取数据的时候,也会默认将数据当做字节数组转化,这样就会导致一个问题,当需要获取的数据,不是以字节数组存在redis当中,而是正常的可读的字符串的时候,

RedisTemplate就无法获取导数据,这个时候获取到的值就是NULL。这个时候StringRedisTempate就派上了用场。

StringRedisTemplate使用的是StringRedisSerializer,当你的redis数据库里面本来存的是字符串数据,或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可。

当redis中存入的数据是可读形式而非字节数组时,使用redisTemplate取值的时候会无法获取导出数据,获得的值为null。可以使用 StringRedisTemplate 试试。

文章来源


出现报错
java.lang.ClassCastException: class java.lang.Long cannot be cast to class java.lang.String (java.lang.Long and java.lang.String are in module java.base of loader ‘bootstrap’)
at org.springframework.data.redis.serializer.StringRedisSerializer.serialize(StringRedisSerializer.java:36) ~[spring-data-redis-2.3.9.RELEASE.jar:2.3.9.RELEASE]

在这里插入图片描述
原因是这个类的属性是Long,不是String类型

解决方法
Map<String, Object> userMap = BeanUtil.beanToMap(userDTO,
new HashMap<>(),
CopyOptions.create()
.setIgnoreNullValue(true)
.setFieldValueEditor((fieldName,fieldValue)->fieldValue.toString()));


在这里插入图片描述

这段代码是使用了 BeanUtil 类中的 beanToMap 方法将一个 userDTO 对象转换为一个 Map<String, Object> 类型的对象。在转换过程中,使用了 CopyOptions 类的 create 方法创建了一些配置选项,包括忽略空值和字段值编辑器。

在这里,setIgnoreNullValue(true) 表示忽略空值,即在转换过程中忽略掉值为 null 的属性;setFieldValueEditor((fieldName,fieldValue)->fieldValue.toString()) 则表示对字段值进行编辑,将字段值转换为字符串类型。

通过这段代码,可以将 userDTO 对象的属性值以键值对的形式存储到 userMap 中,且在此过程中满足了忽略空值和字段值编辑的需求。


登录后的数据存储
在这里插入图片描述

    /*** 短信验证码登录* @param loginForm* @param session* @return*/@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {//1.校验手机号String phone = loginForm.getPhone();//2.如果不符合,返回错误信息if(RegexUtils.isPhoneInvalid(phone)){return Result.fail("手机号格式错误");}//3.校验验证码String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);String code = loginForm.getCode();//4.不一致报错if(code==null || !cacheCode.toString().equals(code)){return Result.fail("验证码错误");}//5.根据手机号查询用户是否存在User user = query().eq("phone", phone).one();if (user == null) {//6.不存在,创建新用户user=createUserWithPhone(phone);}//7.保存用户到redis中//7.1随机生成token,作为登录令牌String token = UUID.randomUUID().toString(true);//7.2将User对象转换为Hash存储UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);Map<String, Object> userMap = BeanUtil.beanToMap(userDTO,new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName,fieldValue)->fieldValue.toString()));//7.3存储String tokenKey=LOGIN_USER_KEY+token;stringRedisTemplate.opsForHash().putAll(tokenKey,userMap);//7.4设置token有效期stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);//8.返回tokenreturn Result.ok(token);}

LoginInterceptor.java的代码

    private StringRedisTemplate stringRedisTemplate;public LoginInterceptor(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1. 获取请求头中的tokenString token = request.getHeader("authorization");if ( StrUtil.isBlank(token)) {response.setStatus(401);return false;}String key=RedisConstants.LOGIN_USER_KEY + token;//2. 基于token获取redis中的用户Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);//3.判断用户是否存在if(userMap.isEmpty()){//4.用户不存在进行拦截response.setStatus(401);return false;}//5.查询到的Hash数据转换为UserDto对象UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);// 6.用户存在将用户信息保存到ThreadLocalUserHolder.saveUser((UserDTO) userDTO);//7. 刷新token的有效期stringRedisTemplate.expire(key,RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);//8.放行return HandlerInterceptor.super.preHandle(request, response, handler);}

在这里插入图片描述

3.登录拦截器的优化

在这里插入图片描述
在这里插入图片描述

public class RefreshTokenInterceptor implements HandlerInterceptor {private StringRedisTemplate stringRedisTemplate;public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1. 获取请求头中的tokenString token = request.getHeader("authorization");if ( StrUtil.isBlank(token)) {return true;}String key=RedisConstants.LOGIN_USER_KEY + token;//2. 基于token获取redis中的用户Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);//3.判断用户是否存在if(userMap.isEmpty()){//4.用户不存在进行拦截return true;}//5.查询到的Hash数据转换为UserDto对象UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);// 6.用户存在将用户信息保存到ThreadLocalUserHolder.saveUser(userDTO);//7. 刷新token的有效期stringRedisTemplate.expire(key,RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);//8.放行return HandlerInterceptor.super.preHandle(request, response, handler);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {//移除用户UserHolder.removeUser();HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}
}

public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1.判断是否需要拦截---ThreadLocal中是否有用户if(UserHolder.getUser()==null){response.setStatus(401);return false;}return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {//移除用户UserHolder.removeUser();HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}
}

4.商户查询缓存

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.添加Redis缓存

在这里插入图片描述

@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result queryById(Long id) {//1.从redis中查询缓存String key = CACHE_SHOP_KEY + id;String shopJson = stringRedisTemplate.opsForValue().get(key); //2.判断是否存在//3.存在则直接返回if (StrUtil.isNotBlank(shopJson)){Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}//4.不存在,根据ID查询数据库Shop shop = getById(id);//5.不存在,返回错误if (shop== null){return Result.fail("店铺不存在");}//6.存在,写入redisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop));//7.返回return Result.ok(shop);}
}

缓存商品列表

@Service
public class ShopTypeServiceImpl extends ServiceImpl<ShopTypeMapper, ShopType> implements IShopTypeService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result queryList() {String key = CACHE_TYPE_LIST;String shopJson = stringRedisTemplate.opsForValue().get(key);//查询缓存中是否有数据if(StrUtil.isNotBlank(shopJson)){List<ShopType> shopTypeList = JSONUtil.toList(shopJson, ShopType.class);return Result.ok(shopTypeList);}List<ShopType> shopTypeList = query().orderByAsc("sort").list();//将数据库中的数据保存到缓存中stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shopTypeList));return Result.ok(shopTypeList);}
}

5.缓存更新策略

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.数据库和缓存的双写一致的实现

 @Override@Transactionalpublic Result update(Shop shop) {Long shopId = shop.getId();if (shopId==null){return Result.fail("查询的店铺不存在");}//1.更新数据库updateById(shop);//2.删除缓存stringRedisTemplate.delete(CACHE_SHOP_KEY + shopId);return null;}

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

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

相关文章

java面试题之nginx篇

1. 什么是Nginx&#xff1f; Nginx是一个 轻量级/高性能的反向代理Web服务器&#xff0c;他实现非常高效的反向代理、负载平衡&#xff0c;他可以处理2-3万并发连接数&#xff0c;官方监测能支持5万并发&#xff0c;现在中国使用nginx网站用户有很多&#xff0c;例如&#xff…

Linux NFC 子系统剖析

1.总览 linux源码中NFC在net/nfc下&#xff0c;文件结构如下图&#xff1a; hci&#xff1a;Host Controller Interface 主要是针对NFC的主机-控制器接口协议 nci&#xff1a;NFC Controller Interface 主要是NFC的控制器接口协议&#xff0c;用于NFCC(NFC Controller)和DH(…

mysql学习打卡day25

今日成果&#xff1a; select * from clients where client_id in ( select client_id from invoices group by client_id having count(*) >2 ); -- 另一种写法 select * from clients where client_id any ( select client_id from invoices group by client_id havin…

Android 14 AAOS audio

文章目录 乘客音频投放到主音频区动态路由配置controlhal实现的具体流程control hal AudioGain的callbackAudioModuleChange变化的通知 乘客音频投放到主音频区 场景&#xff1a; 是将乘客区的Media 属性的数据通过主屏区的设备进行播放。具体而言 在副屏user11播放的音乐是输出…

微信小程序 uniapp+vue实习助学岗位系统springboot/php/python/nodejs

&#xff08;一&#xff09;研究目标&#xff1a; 对于本微信小程序实习系统的设计来讲&#xff0c;主要是采用了java语言和mysql数据库来完成对系统的设计&#xff0c;根据某高校的实习系统&#xff0c;提出解决问题的一个可行性方法&#xff0c;可以在手机端就能完成我们的工…

十三、Qt多线程与线程安全

一、多线程程序 QThread类提供了管理线程的方法&#xff1a;一个对象管理一个线程一般从QThread继承一个自定义类&#xff0c;重载run函数 1、实现程序 &#xff08;1&#xff09;创建项目&#xff0c;基于QDialog &#xff08;2&#xff09;添加类&#xff0c;修改基于QThr…

Sql 查询一张表中哪些字段做了外键跟哪些表关联了

要查询一张表中哪些字段做了外键以及它们与哪些表关联了&#xff0c;你可以使用SQL的系统表或信息模式&#xff08;Information Schema&#xff09;来查询。 以下是一个通用的方法&#xff0c;适用于大多数关系型数据库&#xff08;如MySQL, PostgreSQL, SQL Server等&#xf…

网络工程师笔记5

TCP/IP 常见协议 应用层 Telnet 数据网络中提供远程登录服务的标准协议23FTP 传输文件协议21&#xff0c;20HTTP 超文本传输协议80TFTPSNMPSMTPDNSDHCP 传输层 TCPUDP 网络层 ICMPIGMPIP 数据链路层 PPPOE Internet PPP 传输层 传输层协议接收…

【重要公告】BSV区块链协会宣布将启动多项动态安全增强措施

​​发表时间&#xff1a;2024年2月16日 2024年2月16日&#xff0c;瑞士楚格 - BSV区块链协议的管理机构BSV区块链协会&#xff08;以下简称“BSV协会”&#xff09;宣布对其运营模式实施全新的安全架构&#xff0c;其中包括引入网络访问规则和数字资产找回协议&#xff0c;以及…

springSecruity--->和springboot结合的跨域问题

&#x1f926;‍♂️这个是我在springboot中使用springSecruity写一个小demo时遇到的问题&#xff0c;记录下来&#x1f926;‍♂️ 文章目录 跨域请求springboot项目中使用springSecruity导致跨域请求CrossOrigin请求失效解决方法springboot 中的跨域方法 跨域请求 什么是跨…

12.网络游戏逆向分析与漏洞攻防-游戏网络架构逆向分析-游戏网络通信升级与检测建议

上一个内容&#xff1a;接管游戏接收网络数据包的操作 关注我今晚9点半准时更新

密码学在 Web3 钱包中的应用:私钥是什么?bitget钱包为例

在非对称加密演算法中&#xff0c;私钥是一串随机生成的数字&#xff0c;通常以十六进制数表示&#xff08;也就是由0、1、2、3、4、5、6、7、8、9、a、b、c、d、e和f组成&#xff09;。私钥生成后&#xff0c;这串数字被作为一个单向数学函数中的输入值&#xff0c;计算产生的…

YAML管理接口框架配置的最佳实践

管理接口框架配置是构建强大的接口测试框架的关键一环。良好的配置管理可以提高测试效率、可维护性和可扩展性。在本文中&#xff0c;我们将重点介绍使用YAML&#xff08;YAML Ain’t Markup Language&#xff09;来管理接口框架配置的最佳实践&#xff0c;并通过实例演示其用法…

Unity3D 法线贴图的原理详解

前言 Unity3D它提供了丰富的功能和工具&#xff0c;帮助开发者轻松创建出高质量的游戏作品。其中&#xff0c;法线贴图&#xff08;Normal Mapping&#xff09;是一种常用的技术&#xff0c;用于在游戏中模拟出高精度的表面细节&#xff0c;提升游戏画面的真实感和细节感。本文…

MySQL日志(基础知识)

文章目录 前言日志undo logredo logbin log 总结 前言 今天来分享一下MySQL日志。 日志 MySQL 的日志分为 undo log&#xff08;回滚日志&#xff09;、redo log&#xff08;重做日志&#xff09;、bin log&#xff08;归档日志&#xff09;&#xff0c;三中日志的功能各有不…

遍历QMap的方式

在 Qt 中&#xff0c;你可以使用多种方式来迭代 QMap。以下是一些常见的方法&#xff1a; 1.使用范围基础的 for 循环&#xff1a;这是最简单的方法&#xff0c;但是只能在 C11 或更高版本中使用。 QMap<QString, int> map; // 填充 map... for (const auto &key :…

第七十天 APP攻防-微信小程序解包反编译数据抓包APK信息资源提取

第70天 APP攻防-微信小程序&解包反编译&数据抓包&APK信息资源提取 知识点&#xff1a; 0、APK信息资源提取 1、微信小程序致据抓包 2、做信小程序解包反编译 1、信息收集应用8资产提取&权限等 2、漏润发现-反编泽&脱壳&代码审计 3、安全评估组件8散密…

ctfshow——反序列化

文章目录 web 254——啥也没web 255——反序列化对变量进行赋值&#xff08;1&#xff09;web 256——反序列化对变量进行赋值&#xff08;2&#xff09;web 257——对象注入web 258——对象注入(绕过preg_match)web 259 web 254——啥也没 这里就是使用GET传输&#xff0c;use…

SpringMVC02、什么是SpringMVC

2、什么是SpringMVC 2.1、概述 Spring MVC是Spring Framework的一部分&#xff0c;是基于Java实现MVC的轻量级Web框架。 查看官方文档&#xff1a;Web on Servlet Stack 我们为什么要学习SpringMVC呢? Spring MVC的特点&#xff1a; 轻量级&#xff0c;简单易学高效 , 基…

(C语言)Sleep函数,system函数,数组练习,详解与运用

一维数组详解&#xff1a;http://t.csdnimg.cn/zahZF 二维数组详解&#xff1a;http://t.csdnimg.cn/h2mLe 我们看过可一维数组与二维数组&#xff0c;现在我们来进行简单的练习。 题目&#xff1a;编写代码&#xff0c;演⽰多个字符从两端移动&#xff0c;向中间汇聚 1. …