1. 在首次获取session后,将sessionid作为键将对应session域信息序列化后保存到redis数据库内
  2. 需要获取session域信息时,拿着request携带的cookie中的sessionId值向redis数据库查找对应的数据,并反序列化为Session对象
    /*** 保存session** @param req 请求信心* @return 结果*/@GetMapping("/saveSession")public AjaxResult saveSession(HttpServletRequest req){System.out.println(new Date()+":::"+req.getSession().getId());HttpSession session = req.getSession();session.setAttribute("num",num++);String sessionString = JSON.toJSONString(session);redisFullUtil.set(session.getId(),sessionString);return AjaxResult.success(session.getId()+"::"+session.getAttribute("num"));}/*** 获取保存的session** @param req 请求信息* @return 结果*/@GetMapping("/getSession")public AjaxResult getSession(HttpServletRequest req){System.out.println(new Date()+":::"+req.getSession().getId());String sessionString = redisFullUtil.get(req.getSession().getId());HttpSession session = JSON.parseObject(sessionString, HttpSession.class);return AjaxResult.success(session.getAttribute("num"));}

程序运行后直接报错

com.alibaba.fastjson.JSONException: illegal setter

原因是redis序列化依赖于set和get方法,session中有些数据属性是没有的,

spring-session-data-redis

转变思路一番搜索,现有技术是如何实现session分离,发现spring-session-data-redis就是专门做这件事的,还帮我们完成了大部分的工作,只需要做一些简答的配置工作即可完成session的分离

1. pom引入依赖

<!-- spring boot 与 redis 应用的基本配置 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency><!-- spring session 与redis 应用环境基本配置, 需要开启redis后才可以使用, 不然启动会报错 -->
<dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId>
</dependency>

2. 配置: application.yml

spring:redis:database: 0host: 你的redisipport: 6379password: 你的redis密码pool:max-idle: 8min-idle: 0max-active: 8max-wait: 1timeout: 5000session:store-type: redisredis:hostname: 你的redisipport: 6379pawssword: 你的redis密码

3. 增加配置类

SessionConfig.Class

package org.huber.sharesession.config;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.DefaultCookieSerializer;import javax.validation.Valid;/*** @Classname SessionConfig* @Description TODO* @Date 2020/1/17 12:43* @Author by Ren Jie*/
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class SessionConfig {@Value("{$redis.hostname}")private String hostName;@Value("${redis.port}")private int port;@Beanpublic RedisStandaloneConfiguration connectionFactory() {RedisStandaloneConfiguration jedisConnectionFactory = new RedisStandaloneConfiguration();jedisConnectionFactory.setHostName(hostName);jedisConnectionFactory.setPort(port);return jedisConnectionFactory;}@Beanpublic DefaultCookieSerializer defaultCookieSerializer(){DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer();defaultCookieSerializer.setCookiePath("/");return defaultCookieSerializer;}
}

核心就在这个反序列化上

package org.huber.sharesession.config;import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;/*** @Classname SessionInitializer* @Description TODO* @Date 2020/1/17 12:47* @Author by Ren Jie*/
public class SessionInitializer extends AbstractHttpSessionApplicationInitializer {public SessionInitializer(){super(SessionConfig.class);}
}

结果测试

  1. 开启会话,获取sessionid
  2. 重启服务器
  3. 再次访问后台,获取sessionid
    如果是同一个sessionid,则说明session分离成功
package org.huber.sharesession.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;/*** @Classname SessionController* @Description TODO* @Date 2020/1/17 12:49* @Author by Ren Jie*/
@RestController
@RequestMapping("/shareSession/session")
public class SessionController {@GetMapping("/setSession")public String setSession(HttpServletRequest req){String sessionId = req.getSession().getId();System.out.println("sessionId = " + sessionId);return sessionId;}
}

演示如下:

完了还是可能有问题:

我们来看看redis的序列化:

对redis进行配置,实现发序列化,因为reids序列化已经实现了,这里就不用再对序列化进行研究了(redis序列化见文章:DefaultSerializer requires a Serializable payload but received an object of type [select.system.dto.User] - 叶语婷 - 博客园)。

这里对key和value分别进行反序列化,进而在redis中生成字符型的key和对象型value。

/*** @author yeyuting* @create 2021/2/19*/
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();RedisSerializer<String> redisSerializer = new StringRedisSerializer();template.setConnectionFactory(factory);//key序列化方式template.setKeySerializer(redisSerializer);//value序列化template.setValueSerializer(new JdkSerializationRedisSerializer());//value hashmap序列化template.setHashValueSerializer(redisSerializer);//key haspmap序列化template.setHashKeySerializer(redisSerializer);return template;}}

执行后redis中是这样的

可知,key反序列话成功了,但是value对象反序列化失败了,接着就将注意力转移到value对象的反序列化中来。

当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。 用JdkSerializationRedisSerializer序列化的话,被序列化的对象必须实现Serializable接口。在存储内容时,除了属性的内容外还存了其它内容在里面,总长度长,且不容易阅读。我们要求是存储的数据可以方便查看,也方便反系列化,方便读取数据。JacksonJsonRedisSerializer和GenericJackson2JsonRedisSerializer,两者都能系列化成json,但是后者会在json中加入@class属性,类的全路径包名,方便反系列化。前者如果存放了List则在反系列化的时候如果没指定TypeReference则会报错java.util.LinkedHashMap cannot be cast to 。

因此保险起见,我们将JdkSerializationRedisSerializer换成GenericJackson2JsonRedisSerializer,修改后的代码如下:

/*** @author yeyuting* @create 2021/2/19*/
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();RedisSerializer<String> redisSerializer = new StringRedisSerializer();template.setConnectionFactory(factory);//key序列化方式template.setKeySerializer(redisSerializer);//value序列化template.setValueSerializer(new GenericJackson2JsonRedisSerializer());//value hashmap序列化template.setHashValueSerializer(redisSerializer);return template;}}

执行后redis缓存内容正常显示,如下:

原理就是将httpSession替换成自己实现的httpsession

参考:1、Redis应用:session分离 【session序列化失败 JSONException异常 spring-session-data-redis实现】_奋斗zhe的博客-CSDN博客

2、Java简单实现session保存到redis的方法示例_李修睿的博客-CSDN博客_java session存入redis

3、

【身份认证与控制二】分布式session共享(序列化问题)相关推荐

  1. 分布式Session共享(二):tomcat+memcached实现session共享 - 萝卜兔子 - 博客园

    分布式Session共享(二):tomcat+memcached实现session共享 - 萝卜兔子 - 博客园 http://www.cnblogs.com/notDog/p/5341219.htm ...

  2. 分布式Session共享和单点登录实现

    文章目录 基于Session的身份认证 简介 实现 分布式Session共享 简介 实现 单点登陆 简介 实现过程 总结 基于Session的身份认证 简介 对于一个Web应用,客户端每次请求时,服务 ...

  3. Spring Boot(十一)Redis集成从Docker安装到分布式Session共享

    2019独角兽企业重金招聘Python工程师标准>>> 一.简介 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并 ...

  4. 分布式Session共享解决方案

    转载自 分布式Session共享解决方案 Session是服务器用来保存用户操作的一系列会话信息,由Web容器进行管理.单机情况下,不存在Session共享的情况,分布式情况下,如果不进行Sessio ...

  5. 分布式Session共享的4类技术方案,与优劣势比较

    分布式Session共享的4类技术方案,与优劣势比较 什么是session 什么是session一致性问题? 分布式session Session一致性解决方案 1.什么是session 服务器为每个 ...

  6. shiro分布式session共享

    当我们开发的程序需要跑在多个tomcat容器或者多台机器上时,shiro的默认session存储就不能满足我们的需求了,其中shiro默认的session是存储在运行jvm内存中的,使用的Abstra ...

  7. java redis实现session共享_redis实现分布式session共享

    在讲解redis分布式session共享之前,我们先聊聊tomcat中session管理机制,包括:请求过程中session操作,sessionid解析过程,servlet获取session流程,以及 ...

  8. SpringBoot 分布式Session共享

    一.在分布式开发时Nginx负载均衡时传统做法是 把session手动存到redis中 1.常用做法redis 客户端发起一个请求,这个请求到达nginx上之后被,nginx转发给tomcatA上,然 ...

  9. java分布式会话redis_详解springboot中redis的使用和分布式session共享问题

    对于分布式使用Nginx+Tomcat实现负载均衡,最常用的均衡算法有IP_Hash.轮训.根据权重.随机等.不管对于哪一种负载均衡算法,由于Nginx对不同的请求分发到某一个Tomcat,Tomca ...

最新文章

  1. 当统计信息不准确时,CBO可能产生错误的执行计划,并在10053 trace中找到CBO出错的位置示例...
  2. 一级指针和二级指以及(void**)在双链表中的应用
  3. 关于使用“JS获取屏幕,浏览器,网页高度宽度”的个人思考
  4. 【linux学习笔记三】链接命令
  5. html方框中能放置图片么,html中的img标签你不知道的那些细节!
  6. IDEA入门之web项目导入jar包
  7. 谈谈DictionaryT1,T2和ListT的问题
  8. Java命令行界面(第12部分):CLAJR
  9. php的缓存机制,PHP缓存机制
  10. 直播丨抢鲜体验-openGauss入门
  11. 三大运营商5G基站大单纷纷落地:华为、中兴、爱立信、大唐移动收获大
  12. 官宣!CSDN 发布 C 站软件工程师能力认证
  13. php模糊搜索 变量,自定义搜索seo变量{param}字符串
  14. 第二阶段冲刺(第十天)
  15. 计算机专业必装软件mac,MAC电脑可运行的常用软件有哪些?
  16. 【题解】HNOI-2015落忆枫音
  17. 认知神经学lecture1---感受与感知
  18. Android 通过短信(H5)跳转到App指定页面
  19. 王道OS-磁盘存储器管理
  20. 先行一步,7大技术创新和突破,阿里云把 Serverless 领域的这些难题都给解了

热门文章

  1. 理解 ActivityExecutionContextManager
  2. max与top的效率
  3. 报错 插入更新_自增主键,三类插入测验答案,在这里。
  4. 计算机网络相关的知识,计算机网络知识整理
  5. python读取ini文件编码格式_Python读取txt(.ini)文件BOM问题
  6. 查linux有哪些task_Java面试手册:Linux高频考点
  7. 移动硬盘拷贝linux文件,Linux下使用移动硬盘拷贝数据
  8. matlab三维feather,matlab高维图形,别地方抄来的
  9. python画图零基础入门教程_Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 6. 条件...
  10. mysql配置读写分离无效_MySQL数据库的同步配置+MySql 读写分离