【SpringBoot】31 Session + Redis 实战

Gitee

https://gitee.com/Lin_DH/system

介绍

【SpringBoot】30 Cookie、Session、Token https://blog.csdn.net/weixin_44088274/article/details/144241595

背景

Spring Session 是 Spring 的一个子项目,它提供了一种管理用户会话信息的方法,无论是在单服务的应用程序中,还是在分布式系统中,都能运用。Spring Session 提供了一种机制,可以将应用服务器的会话(HttpSession)抽象化,使得开发者可以在不同的环境下使用系统的 API 来管理会话。

Spring Session

原理

Spring Session 使支持集群会话变得简单,无需绑定到特定应用程序容器的解决方案。

  • HttpSession:以通用的方式替代应用程序容器(如 Tomcat)中(Servlet 容器实现)的 HttpSession,实现了会话数据的外部存储,并支持在请求头(Header)中提供 sessionId,方便提供 RESTful API。
  • WebSocket:提供在接收 WebSocket 消息时保持 HttpSession 活跃的能力。
  • WebSession:允许以与应用程序容器无关的方式替换 Spring WebFlux 的 WebSession。
  • 配置类:提供了几个关键配置类,如 RedisHttpSessionConfiguration 和 SpringHttpSessionConfiguration,用于配置 Redis 作为会话数据的存储源。
  • SessionRepositoryFilter:SessionRepositoryFilter 是 Spring Session 的核心组件之一,它负责在请求处理之前和之后与会话存储进行交互,以确保会话数据的正确加载和保存。
    在这里插入图片描述

组成

Spring Session Core:提供核心的 Spring 会话功能和 Api。
Spring Session Data Redis:提供 SessionRepository 和 ReactiveSessionRepository 的实现,支持 Redis 和配置。
Spring Session JDBC:提供由关系型数据库和配置支持所支持的 SessionRepository 实现。
Spring Session Hazelcast:提供由 Hazelcast 和配置支持所支持的 SessionRepository 实现。

Redis 实现分布式 Session

在这里插入图片描述
在分布式系统中,通常会将 Session 存储在 Redis 中来实现分布式 Session,这样可以在多台服务器之间共享 Session 数据。实现分布式 Session 通常使用 Redis 的 Hash 结构。
1)用户登录:当用户登录成功后,服务端会生成一个唯一的 SessionId(通常是一串随机字符串,如 UUID)。
2)存储 Session:将用户的会话信息(如用户ID,权限信息等)与 SessionId 关联,并存储在 Redis 中,Redis 使用 Hash 结构来存储这些数据,其中 SessionID 作为 Hash 的 Key,用户的会话信息作为 Hash 的 Value。
3)设置 Cookie:将 SessionId 通过 Cookie 发送到客户端浏览器,客户端每次请求时都需要携带上 Cookie。
4)请求处理:在客户端每次发起请求时,服务端会检查 Cookie 中的 SessionId,服务端用该 SessionId 从 Redis 中检索对应的 Session 数据。
5)认证与授权:通过检索到的 Session 数据,服务端可以验证用户身份,并根据用户的会话信息进行授权。
Session 过期:设置 Session 过期时间,当用户长时间不活动或者显式退出登录时,服务端会从 Redis 中删除对应的 Session 数据。
在这里插入图片描述
在这里插入图片描述

代码实现

依赖

pom.xml

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 实现对 Spring Session 使用 Redis 作为数据源的自动化配置 --><dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId></dependency><!-- 实现对 Spring Data Redis 的自动化配置 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><exclusions><!-- 去掉对 Lettuce 的依赖,因为 Spring Boot 优先使用 Lettuce 作为 Redis 客户端 --><exclusion><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId></exclusion></exclusions></dependency><!-- 引入 Jedis 的依赖,这样 Spring Boot 实现对 Jedis 的自动化配置 --><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency>

配置

application.yml

spring:redis:host: localhostport: 6379
#    password:#Redis数据库号,默认为0database: 0    #连接超时时间,单位为毫秒    timeout: 10#对应 RedisProperties.Jedis 内部类jedis:pool:#连接池最大连接数,默认为8,使用负数表示没有限制max-active: 8 #默认连接池最大空闲的连接数,默认为8,使用负数表示没有限制max-idle: 8#默认连接池最小空闲的连接数,默认为0,允许设置0和正数min-idle: 0#连接池最大阻塞等待时间,单位为毫秒,默认为-1,表示不限制max-wait: -1

添加配置类

SessionConfiguration.java

package com.lm.system.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;/*** @author DUHAOLIN* @date 2024/11/22*/
@Configuration
@EnableRedisHttpSession // 自动化配置 Spring Session 使用 Redis 作为数据源
public class SessionConfiguration {@Bean(name = "springSessionDefaultRedisSerializer")public RedisSerializer<Object> springSessionDefaultRedisSerializer() {return RedisSerializer.json();}}

添加 @EnableRedisHttpSession 注解,开启自动化配置 Spring Session 使用 Redis 作为数据源。该注解有如下属性:

  • maxInactiveIntervalInSeconds:Session 不活跃后的过期时间,默认为 1800 秒。
  • redisNamespace:在 Redis Key 的统一前缀,默认为 “spring:session”。
  • redisFlushMode:Redis 会话刷新模式。目前有两种,默认为 RedisFlushMode.ON_SAVE。
  • RedisFlushMode.ON_SAVE:请求执行完成时,统一写入 Redis 存储。
  • RedisFlushMode.IMMEDIATE:每次修改 Session 时,立即写入 Redis 存储。
  • cleanupCron:清理 Redis Session 会话过期的任务执行 Cron 表达式,默认为 “0 * * * * *” 每分钟执行一次。虽说 Redis自带 Key 过期机制,但是默认该机制为惰性删除策略,实际过期的 Session 还保存在 Redis 的内存中。所以 Spring Session 通过定时任务,删除 Redis 中过期的 Session,使之尽快释放 Redis 的内存。
    在 springSessionDefaultRedisSerializer() 方法中,定义了一个 Bean 名字为 springSessionDefaultRedisSerializer 的 RedisSerializer Bean,采用 JSON 序列化方式。默认情况下采用 Java 自带的序列化方式,可读性较差,所以需要进行替换。

配置 Redis 序列化

RedisConfig.java

package com.lm.system.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;/*** @author DUHAOLIN* @date 2024/11/13*/
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();    redisTemplate.setConnectionFactory(factory);//设置key序列化方式stringredisTemplate.setKeySerializer(new StringRedisSerializer());//设置value序列化方式json,使用GenericJackson2JsonRedisSerializer替代默认序列化redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());    redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();    return redisTemplate;}}

测试

SessionController.java

package com.lm.system.controller;import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpSession;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;/*** @author DUHAOLIN* @date 2024/11/22*/
@RestController
@RequestMapping("session")
public class SessionController {@PostMapping("set")public void set(HttpSession session, @RequestParam("key") String key, @RequestParam("value") String value) {session.setAttribute(key, value);}@GetMapping("getAll")public Map<String, Object> getAll(HttpSession session) {Map<String, Object> resultMap = new HashMap<>();for(Enumeration<String> names = session.getAttributeNames(); names.hasMoreElements();) {String key = names.nextElement();Object value = session.getAttribute(key);resultMap.put(key, value);}return resultMap;}}

效果图

启动程序后,进行查询,未查询到 Session 数据。
在这里插入图片描述
客户端访问完,到 Redis 客户端进行查询,则能够查询到 Spring Session 保存到 Redis 的 Session 数据。
在这里插入图片描述
每个 Session 对应 Redis 中 两个键值对。

  • 头部:以 spring:session 开头,可以通过 @EnableRedisHttpSession 直接的 redisNamespace 属性进行配置。
  • 结尾:以对应 Session 的 sessionId 结尾。
  • 中间:中间分别是 session、expirations、sessions:expires 。
    从下图该 session 的内容可以看出,其是一个 Redis Hash 数据结构。
    在这里插入图片描述
    客户端发起 set 请求,设置 key 和 value。
    在这里插入图片描述
    此时再次在 Redis 客户端进行查询,则该 Session 信息已经发生改变。
    在这里插入图片描述

Redis 序列化

RedisSerializer

org.springframework.data.redis.serializer.RedisSerializer 接口,Redis 序列化接口,用于 Redis KEY 和 VALUE 的序列化。

RedisSerializer.java

public interface RedisSerializer<T> {@Nullablebyte[] serialize(@Nullable T t) throws SerializationException;@NullableT deserialize(@Nullable byte[] bytes) throws SerializationException;}

定义了对象 和二进制数组的转换。
Redis Client 传递给 Redis Server 是传递的 KEY 和 VALUE 都是二进制值数组。
RedisSerializer 的实现类:
在这里插入图片描述
主要分为四类:JDK 序列化方式、String 序列化方式、JSON 序列化方式、XML 序列化方式。

JDK序列化方式

介绍

org.springframework.data.redis.serializer.JdkSerializationRedisSerializer ,默认情况下,RedisTemplate 使用该数据列化方式。
RedisTemplate#afterPropertiesSet() 方法,在 RedisTemplate 未设置序列化的情况下,使用 JdkSerializationRedisSerializer 作为序列化实现。在 Spring Boot 自动化配置 RedisTemplate Bean 对象时,就未设置。
绝大情况下,不会使用该序列化,如下图所示,写入的 KEY 前会携带 16 进制字符,而通过该 KEY 获取的 VALUE 也携带有 16 进制字符,获取的结果不方便阅读。
在 ObjectOutputStream#writeString(String str,boolean unshared) 代码中,实际是:标志位 + 字符串长度 + 字符串内容。
注:测试之前如果前面配置了序列化(RedisConfig.java)需要先注释 @Configuration 注解。

测试代码

RedisTest.java

package com.lm.system;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import javax.annotation.Resource;/*** @author DUHAOLIN* @date 2024/11/29*/
@SpringBootTest
@RunWith(value = SpringJUnit4ClassRunner.class)
public class RedisTest {@Resourceprivate RedisTemplate redisTemplate;@Testpublic void test01() {redisTemplate.opsForValue().set("name", "Jack");}}

效果图

在这里插入图片描述

String序列化方式

org.springframework.data.redis.serializer.StringRedisSerializer,字符串和二进制数组的直接转换。

StringRedisSerializer.java

private final Charset charset;@Override
public String deserialize(@Nullable byte[] bytes) {return (bytes == null ? null : new String(bytes, charset));
}@Override
public byte[] serialize(@Nullable String string) {return (string == null ? null : string.getBytes(charset));
}

绝大多数情况下,KEY 和 VALUE 使用的此序列化方式。而 VALUE 的序列化和反序列化,需要开发人员自己在逻辑调用 JSON 方法来序列化。
org.springframework.data.redis.serializer.GenericToStringSerializer ,使用 Spring ConversionService 实现 对象和 String 的转换,从而 String 和二进制数组的转换。
序列化的过程,首先 对象通过 ConversionService 转换成 String ,然后 String 再序列化成二进制数组。

JSON 序列化方式

1)org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer,使用 Jackson 实现 JSON 的序列化方式是支持所有类。

GenericJackson2JsonRedisSerializer.java

public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName) {this(new ObjectMapper());// simply setting {@code mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)} does not help here since we need// the type hint embedded for deserialization using the default typing feature.mapper.registerModule(new SimpleModule().addSerializer(new NullValueSerializer(classPropertyTypeName)));//<1>if (StringUtils.hasText(classPropertyTypeName)) {mapper.enableDefaultTypingAsProperty(DefaultTyping.NON_FINAL, classPropertyTypeName);//<2>} else {mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);}
}

<1> 如果传入 classPropertyTypeName 属性,使用传入对象的 classPropertyTypeName 属性对应的值,作为默认类型(Default Typing)。
<2> 如果未传入 classPropertyTypeName 属性,则使用传入对象的类全名,作为默认类型(Default Typing)。
2)org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer,使用 Jackson 实现 JSON 的序列化方式,并且显示指定 类型。

Jackson2JsonRedisSerializer.java

public class Jackson2JsonRedisSerializer<T> implements RedisSerializer<T> {//...public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;/*** 指定类型,和 <T> 要一致。*/private final JavaType javaType;private ObjectMapper objectMapper = new ObjectMapper();}

Jackson2JsonRedisSerializer 序列化类里已经声明了类型,所以序列化的 JSON 字符串,无需在存储一个 @class 属性,用于存储类型。
3)com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer,使用 FastJSON 实现 JSON 的序列化方式,和 GenericJackson2JsonRedisSerializer 一致。
4)com.alibaba.fastjson.support.spring.FastJsonRedisSerializer,使用 FastJSON 实现 JSON 的序列化方式,和 Jackson2JsonRedisSerializer 一致。

XML序列化方式

org.springframework.data.redis.serializer.OxmSerializer,使用 Spring OXM 实现将对象和 String 的转换,从而 String 和二进制数组的转换。

参考链接

【Spring Boot 分布式 Session 入门】https://www.iocoder.cn/Spring-Boot/Distributed-Session/?self

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

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

相关文章

关于网站的权重和百度蜘蛛爬虫的关系

网站的权重和百度蜘蛛爬虫的关系是密切关联的。 网站权重是一个衡量网站在搜索引擎中重要性的概念&#xff0c;它反映了网站在搜索引擎算法中的相对重要程度。而百度蜘蛛爬虫则是百度搜索引擎用来抓取网页内容的工具&#xff0c;通过分析网页的URL、内容、链接等因素来评估网站…

游戏引擎学习第35天

开场介绍 今天的任务是继续改进一个虚拟的瓦片地图系统&#xff0c;使其适合处理更大的世界。我们希望这个系统能管理大范围的游戏世界&#xff0c;其中包含按需存储的小区域。昨天&#xff0c;我们介绍了“内存区域”的概念&#xff0c;用于管理持久性存储。我们计划今天继续…

Leetcode经典题5--轮转数组

题目描述 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 输入输出示例 &#xff1a; 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右…

【JS】简单CSS简单JS写的上传进度条

纯JS写的&#xff0c;简单的上传进度条&#xff0c;当上传的文件较大&#xff0c;加一个动态画面&#xff0c;就不会让人觉得出错了或网络卡了 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"v…

2023 年“泰迪杯”数据分析技能赛B 题企业财务数据分析与造假识别

2023 年“泰迪杯”数据分析技能赛B 题企业财务数据分析与造假识别 一、背景 财务数据是指企业经营活动和财务结果的数据记录&#xff0c;反映了企业的财务状况与经营成果。对行业、企业的财务数据进行分析&#xff0c;就是要评价其过去的经营业绩、衡量现在的财务状况、预测未…

perl Window安装教程

perl Window安装教程 下载地址 https://platform.activestate.com/tangxing806/ActivePerl-5.28/distributions 运行state-remote-installer.exe 按下图截图步骤 检查perl版本 参考文献&#xff1a; perl安装教程

知识图谱9:知识图谱的展示

1、知识图谱的展示有很多工具 Neo4j Browser - - - - 浏览器版本 Neo4j Desktop - - - - 桌面版本 graphX - - - - 可以集成到Neo4j Desktop Neo4j 提供的 Neo4j Bloom 是用户友好的可视化工具&#xff0c;适合非技术用户直观地浏览图数据。Cypher 是其核心查询语言&#x…

【数据分享】1901-2023年我国省市县三级逐年最低气温数据(Shp/Excel格式)

之前我们分享过1901-2023年1km分辨率逐月最低气温栅格数据和Excel和Shp格式的省市县三级逐月最低气温数据&#xff0c;原始的逐月最低气温栅格数据来源于彭守璋学者在国家青藏高原科学数据中心平台上分享的数据&#xff01;基于逐月栅格数据我们采用求年平均值的方法得到逐年最…

HBU深度学习实验15-循环神经网络(2)

LSTM的记忆能力实验 飞桨AI Studio星河社区-人工智能学习与实训社区 (baidu.com) 长短期记忆网络&#xff08;Long Short-Term Memory Network&#xff0c;LSTM&#xff09;是一种可以有效缓解长程依赖问题的循环神经网络&#xff0e;LSTM 的特点是引入了一个新的内部状态&am…

使用windows的包管理工具chocolatey

开发人员&#xff0c;在windows环境下&#xff0c;最头疼的是安装和配置各种环境变量&#xff0c;现在chocolatey 可以一键安装&#xff0c;不需要再去配置环境变量了。比如你安装一个java的环境&#xff0c;仅仅需要你敲几个命令&#xff0c;都能帮你搞定。 我自己已经使用这…

VTK知识学习(21)- 数据的读写

1、前言 对于应用程序而言&#xff0c;都需要处理特定的数据&#xff0c;VTK应用程序也不例外。 VTK应用程序所需的数据可以通过两种途径获取: 第一种是生成模型&#xff0c;然后处理这些模型数据(如由类 vtkCylinderSource 生成的多边形数据); 第二种是从外部存储介质里导…

QT 中 QString 转换为 Unicode 和 ASCII 的方法

目录 ​编辑 前言 一、QString转换成 Unicode编码 二、QString转换成ASCII编码 三、Unicode编码转换成QString汉字 四、ASCII编码转成QString 五、注意事项 六、总结 前言 在 Qt 开发中&#xff0c;经常会遇到需要将QString中的字符转换为特定编码格式的需求。本文将介…

基于51单片机64位病床呼叫系统设计( proteus仿真+程序+设计报告+原理图+讲解视频)

基于51单片机病床呼叫系统设计( proteus仿真程序设计报告原理图讲解视频&#xff09; 仿真图proteus7.8及以上 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0095 1. 主要功能&#xff1a; 基于51单片机的病床呼叫系统proteus仿…

【OpenDRIVE_Python】使用python脚本更新OpenDRIVE数据中路口Junction名称

示例代码说明&#xff1a; 遍历OpenDRIVE数据中每个路口JunctionID,读取需要变更的路口ID和路口名称的TXT文件,若JunctionID与TXT文件中的ID一致&#xff0c;则将TXT对应的点位名称更新到OpenDRIVE数据中Junction name字段。补充&#xff1a;需要保持TXT和OpenDRIVE数据文件编…

java+ssm+mysql商品管理系统

项目介绍&#xff1a; 使用javassmmysql开发的商品库存管理系统&#xff0c;系统包含管理员&#xff0c;员工角色&#xff0c;功能如下&#xff1a; 管理员&#xff1a;员工管理&#xff1b;供应商管理&#xff1b;客户管理&#xff1b;商品管理&#xff1b;商品进货&#xf…

android studio创建虚拟机注意事项

emulator 启动模拟器的时候&#xff0c;可以用 AVD 界面&#xff0c;也可以用命令行启动&#xff0c;但命令行启 动的时候要注意&#xff0c;系统有两个 emulator.exe &#xff0c;建议使用 emulator 目录下的那个&#xff01;&#xff01; 创建类型为google APIs的虚拟机可从…

小皮面板(PHPSTUDY)配置多个域名或IP

问题描述 小皮面板默认采用nginx的静态部署&#xff0c;按照使用nginx的习惯只需要额外添加一个server即可&#xff0c;但是会发现直接往配置文件里添加新的server是不生效的&#xff0c;小皮的官网论坛几乎已经停止维护&#xff0c;因此资料较少&#xff0c;原本也没有仔细使…

搭建voiceapi实时语音转录/合成github项目教程【windows版】

github项目地址&#xff1a;https://github.com/ruzhila/voiceapi 项目简介&#xff1a;python实现的基于sherpa-onnx的语音转录/合成API 运行环境&#xff1a;windows、python3.10 1.下载项目 git clone https://github.com/ruzhila/voiceapi.git2.新建环境 注意使用python …

网络编程 | TCP套接字通信及编程实现经验教程

1、TCP基础铺垫 TCP/IP协议簇中包含了如TCP、UDP、IP、ICMP、ARP、HTTP等通信协议。TCP协议是TCP/IP协议簇中最为常见且重要的通信方式之一&#xff0c;它为互联网上的数据传输提供了可靠性和连接管理。 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议…

java+ssm+mysql成绩统计分析管理系统

项目介绍&#xff1a; 使用javassmmysql开发的成绩统计分析管理系统&#xff0c;系统包含管理员&#xff0c;教师&#xff0c;学生角色&#xff0c;功能如下&#xff1a; 管理员&#xff1a;首页统计&#xff1b;班级管理&#xff1b;课程管理&#xff1b;学生管理&#xff1…