springboot中使用spring-session实现共享会话到redis(二)
上篇文章介绍了springboot中集成spring-session实现了将session分布式存到redis中。这篇在深入介绍一些spring-session的细节。
1、session超时:
在tomcat中,如果要设置session的超时,我们可以在web.xml或者springboot的application.properties中直接配置即可,例如在springboot中设置:
server.session.timeout=1800
但引入了spring-session后,这个配置将不再起作用, 我们需要写一个如下的配置类:
-
import org.springframework.context.annotation.Configuration;
-
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
-
-
@Configuration
-
//maxInactiveIntervalInSeconds 默认是1800秒过期,这里测试修改为60秒
-
@EnableRedisHttpSession(maxInactiveIntervalInSeconds=60)
-
public class RedisSessionConfig{
-
-
}
注:如果不修改session超时,可以不用该配置类。
2、在springboot中使用spring-session完成登录、登出等功能:
1)定义User实体类:
-
public class User implements Serializable {
-
private static final long serialVersionUID = 1629629499205758251L;
-
-
private Long id;
-
private String name;
-
private String pwd;
-
private String note;
-
private Integer dateAuth;
-
private Integer tableAuth;
-
-
//set/get 方法
注:该类需要序列化,因为spring-session会将该对象序列化后保存到redis中。
2)UserController:
-
@RequestMapping("/user")
-
@Controller
-
public class UserController {
-
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
-
-
@Autowired
-
private UserService userService;
-
-
/**
-
* 退出
-
* @param request
-
* @return
-
*/
-
@RequestMapping("/loginOut")
-
@ResponseBody
-
public ResponseMessage loginOut(HttpServletRequest request, HttpServletResponse response) {
-
HttpSession session = request.getSession();
-
if (session != null) {
-
session.setAttribute(session.getId(), null);
-
}
-
return ResponseMessage.ok(Constants.CODE_SUCCESS,null);
-
}
-
-
/**
-
* 登录验证
-
* @param request
-
* @return
-
*/
-
@RequestMapping("/login")
-
public ModelAndView login(HttpServletRequest request,Model model) {
-
-
String name = request.getParameter("username");
-
String password = request.getParameter("password");
-
-
//TODO校验
-
-
Map<String,String> map = new HashMap<>();
-
map.put("name",name);
-
map.put("pwd",password);
-
-
User user = null;
-
try {
-
user = userService.login(map);
-
} catch (Exception e) {
-
logger.error("user login is error...",e);
-
}
-
-
if (user != null) {
-
HttpSession session = request.getSession();
-
session.setAttribute(session.getId(),user);
-
model.addAttribute("user", user);
-
-
logger.info("user login is success,{}",name);
-
return new ModelAndView("redirect:/index");
-
} else {
-
request.setAttribute("errorInfo", "验证失败");
-
return new ModelAndView("login/login");
-
}
-
}
-
}
注:spring-session会通过拦截器的方式往session对象中存放、移除sessionId(session.getId()),所以我们在登录、登出、拦截器中会调用session.setAttribute(session.getId(),user);来判断。
3)session拦截器:
-
public class SessionInterceptor extends HandlerInterceptorAdapter {
-
private static String[] IGNORE_URI = {"/login.jsp", "/login/","/login","/loginIndex", "/error"};
-
private static Logger log = LoggerFactory.getLogger(SessionInterceptor.class);
-
-
@Override
-
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
-
boolean flag = false;
-
String url = request.getRequestURL().toString();
-
-
/*String currentURL = request.getRequestURI(); // 取得根目录所对应的绝对路径:
-
String targetURL = currentURL.substring(currentURL.lastIndexOf("/"), currentURL.length());// 截取到当前文件名用于比较
-
String currentURLTemp = currentURL.replaceAll("/iis/", "");*/
-
-
for (String s : IGNORE_URI) {
-
if (url.contains(s)) {
-
flag = true;
-
break;
-
}
-
}
-
if (!flag) {
-
HttpSession session = request.getSession();
-
Object obj = session.getAttribute(session.getId());//Constants.SESSION_USER
-
if (null == obj) {//未登录
-
String servletPath = request.getServletPath();
-
log.error("session失效,当前url:" + url+";module Paht:"+servletPath);
-
if (request.getHeader("x-requested-with") != null &&
-
request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")){
-
-
response.setHeader("sessionstatus", "timeout");//在响应头设置session状态
-
response.setCharacterEncoding("UTF-8");
-
response.setContentType("text/html;charset=UTF-8");
-
response.getWriter().print("error");
-
} else {
-
response.sendRedirect(request.getContextPath()+"/user/loginIndex");
-
}
-
return false;
-
} else {
-
/*User user = (User)obj;
-
if(!RightUtil.hasRight(currentURLTemp, request)){
-
if(!"iisAdminTmp".equals(user.getName()) && !"/index".equals(targetURL)){
-
//response.sendRedirect(request.getContextPath()+"/login/login");//应该返回到没有权限的页面
-
//request.getRequestDispatcher("/login/login").forward(request, response);
-
return false;
-
}
-
}*/
-
}
-
}
-
return super.preHandle(request, response, handler);
-
}
-
-
@Override
-
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
-
super.postHandle(request, response, handler, modelAndView);
-
}
-
-
}
说明:
我们知道spring-session会自动注入springSessionRepositoryFilter过滤器,每一次的请求都由他来过滤,其本质是:对每一个请求的request进行了一次封装。那么,在Controller里面拿出的request实际上是封装后的request,
调用request.getSession()的时候,实际上拿到是Spring封装后的session。这个session则存储在redis数据库中。
应用通过 getSession(boolean create) 方法来获取 session 数据,参数 create 表示 session 不存在时是否创建新的 session 。 getSession 方法首先从请求的 “.CURRENT_SESSION” 属性来获取 currentSession ,没有 currentSession ,则从 request 取出 sessionId ,然后读取 spring:session:sessions:[sessionId] 的值,同时根据 lastAccessedTime 和 MaxInactiveIntervalInSeconds 来判断这个 session 是否过期。如果 request 中没有 sessionId ,说明该用户是第一次访问,会根据不同的实现,如 RedisSession ,MongoExpiringSession ,GemFireSession 等来创建一个新的 session 。 另外, 从 request 取 sessionId 依赖具体的 HttpSessionStrategy 的实现,spring session 给了两个默认的实现 CookieHttpSessionStrategy 和 HeaderHttpSessionStrategy ,即从 cookie 和 header 中取出 sessionId 。
3、spring-session在redis中的存储结构:
spring:session是默认的Redis HttpSession前缀(redis中,我们常用’:’作为分割符)。如上图,每一个session都会创建3组数据:
1)spring:session:sessions:6e4fb910-34f7-453d-a8c6-2b3cd192e051
hash结构,存储了session信息(实体类的序列化数据)、maxInactiveInterval、创建时间、lastAccessedTime四部分信息。
2)spring:session:sessions:expires:6e4fb910-34f7-453d-a8c6-2b3cd192e051
string结构,value为空。
3)spring:session:expirations:1529395440000:
set结构,存储过期时间记录
注:在spring-session中提到,由于redis的ttl删除key是一个被动行为,所以才会引入了expirations这个key,来主动进行session的过期行为判断。
springsession相关参考:
https://segmentfault.com/a/1190000011091273#articleHeader14
https://blog.csdn.net/lxhjh/article/details/78048201
http://www.infoq.com/cn/articles/Next-Generation-Session-Management-with-Spring-Session
https://qbgbook.gitbooks.io/spring-boot-reference-guide-zh/IV.%20Spring%20Boot%20features/38.%20Spring%20Session.html
原文地址:https://blog.csdn.net/liuxiao723846/article/details/80733565
springboot中使用spring-session实现共享会话到redis(二)的更多相关文章
- SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法
软件152 尹以操 首先谢谢大佬的简书文章:http://www.jianshu.com/p/45ad65690e33# 这篇文章中讲的是spring中使用spring data jpa,使用了xml ...
- 使用Spring Session做分布式会话管理
在Web项目开发中,会话管理是一个很重要的部分,用于存储与用户相关的数据.通常是由符合session规范的容器来负责存储管理,也就是一旦容器关闭,重启会导致会话失效.因此打造一个高可用性的系统,必须将 ...
- (十九)SpringBoot之使用Spring Session集群-redis
一.引入maven依赖 <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEnc ...
- springboot中使用spring security,登录url就出现403错误
参考链接:https://segmentfault.com/q/1010000012743613 有两个controller,一个是所有用户可以访问的@RequestMapping("use ...
- SpringBoot中获取spring.profiles.active的值
一.网上很多采用@Profile("dev")的方式获取,但是这个是类级别的 二.开发中可能需要代码级别 1.刚开始我想通过classpath下的文件读取方式,麻烦死了,于是换了个 ...
- SpringBoot中实现Spring容器中注入类型相同但名不同Bean
@Bean(autowire = Autowire.BY_NAME,value = "kaptchaProducer") public Producer kaptchaProduc ...
- 单点登录实现(spring session+redis完成session共享)
一.前言 项目中用到的SSO,使用开源框架cas做的.简单的了解了一下cas,并学习了一下 单点登录的原理,有兴趣的同学也可以学习一下,写个demo玩一玩. 二.工程结构 我模拟了 sso的客户端和s ...
- 大话 Spring Session 共享
javaweb中我们项目稍微正规点,都会用到单点登录这个技术.实现它的方法各家有各界的看法.这几天由于公司项目需求正在研究.下面整理一下最近整理的心得. 简介 在分布式项目中另我们头疼的是多项目之间的 ...
- Spring Session解决Session共享
1. 分布式Session共享 在分布式集群部署环境下,使用Session存储用户信息,往往出现Session不能共享问题. 例如:服务集群部署后,分为服务A和服务B,当用户登录时负载到服务A ...
随机推荐
- Future Maker | 领跑亚太 进击的阿里云数据库
7月31日,阿里云马来西亚峰会在吉隆坡召开,阿里巴巴集团副总裁.阿里云智能数据库事业部总裁李飞飞在演讲中表示:“作为亚太地区第一的云服务提供商,阿里云数据库已为多家马来西亚知名企业提供技术支持,助力企 ...
- JavaScript--关于实例对象带不带参数和构造函数带不带参数的关系
就是一句话: 构造函数创建对象时,也可以带参数,因为可以对对象进行一些属性的初始化,也就是你创建对象时,就带着这些属性,当然你也可以不带参数,后面实例化对象后再进行添加.而且,js函数的参数在定义函数 ...
- R语言处理Web数据
R语言处理Web数据 许多网站提供的数据,以供其用户的消费.例如,世界卫生组织(WHO)提供的CSV,TXT和XML文件的形式的健康和医疗信息报告.基于R程序,我们可以通过编程提取这些网站的具体数据. ...
- PAT天梯赛L3-011 直捣黄龙
题目链接:点击打开链接 本题是一部战争大片 -- 你需要从己方大本营出发,一路攻城略地杀到敌方大本营.首先时间就是生命,所以你必须选择合适的路径,以最快的速度占领敌方大本营.当这样的路径不唯一时,要求 ...
- 数据库 Mysql-mongodb-redis
目录 1. Mysql 1.1. 介绍 1.1.1 基础 1.1.3 数据库操作 1.2. 查询 1.2.1 条件 1.2.2 聚合 1.2.3 分组 1.2.4 排序 1.2.4 分页 1.3. 高 ...
- Docker for windows pull镜像文件的安装位置改变方法
发生现象: 在windows10下安装docker for windows,随着用docker pull image文件后,C盘的容量越来越小了,你可能也有一种跟我一样的想法,想改变默认的安装路径,本 ...
- compass与css sprite(雪碧图)
什么是css sprite? css sprite,中文叫雪碧图,也有人喊CSS精灵,就是一种背景拼合的技术,然后通过background-position来显示雪碧图中需要显示的图像. MDN相关链 ...
- linux驱动开发满三年,回首一下基本看不到其它选择
刚刚搞完一个处理器BSP项目,准备搞下一个自研处理器.说不上来什么喜悦,仅仅有些许茫然.没有刚毕业时对这个行业的痴迷,慢慢认同这仅仅是个谋生工具的想法. 回忆当初编写第一个驱动,就像上了战场.被长官踢 ...
- 复杂SQL示例 (排行榜需求)
公司项目要求做出排行榜,根据六组数据依次排行,关联多表,SQL记录下来方便日后查看 " ?><!DOCTYPE mapper PUBLIC "-//mybatis.or ...
- Docker 学习笔记 2019-05-27
Docker 学习笔记 2019-05-27 可以很方便的打包应用. 使用 docker-compose 更方便. 每个发行版安装方式不一样,如果 centos 直接安装很可能会安装成旧版本. Lin ...