RedisSession (自定义)

疯狂创客圈 Java 高并发【 亿级流量聊天室实战】实战系列 【博客园总入口

架构师成长+面试必备之 高并发基础书籍 【Netty Zookeeper Redis 高并发实战


前言

Crazy-SpringCloud 微服务脚手架 &视频介绍

Crazy-SpringCloud 微服务脚手架,是为 Java 微服务开发 入门者 准备的 学习和开发脚手架。并配有一系列的使用教程和视频,大致如下:

高并发 环境搭建 图文教程和演示视频,陆续上线:

中间件 链接地址
Linux Redis 安装(带视频) Linux Redis 安装(带视频)
Linux Zookeeper 安装(带视频) Linux Zookeeper 安装, 带视频
Windows Redis 安装(带视频) Windows Redis 安装(带视频)
RabbitMQ 离线安装(带视频) RabbitMQ 离线安装(带视频)
ElasticSearch 安装, 带视频 ElasticSearch 安装, 带视频
Nacos 安装(带视频) Nacos 安装(带视频)

Crazy-SpringCloud 微服务脚手架 图文教程和演示视频,陆续上线:

组件 链接地址
Eureka Eureka 入门,带视频
SpringCloud Config springcloud Config 入门,带视频
spring security spring security 原理+实战
Spring Session SpringSession 独立使用
分布式 session 基础 RedisSession (自定义)
重点: springcloud 开发脚手架 springcloud 开发脚手架
SpingSecurity + SpringSession 死磕 (写作中) SpingSecurity + SpringSession 死磕

小视频以及所需工具的百度网盘链接,请参见 疯狂创客圈 高并发社群 博客

RedisSession 场景和问题

一般,大家获取 Session 的方式: session = request.getSession(), 是通过HttpServletRequest 获取的,因为每次用户请求过来,我们服务端都会获取到请求携带的唯一 SessionId。

如果自定的 HttpSession的,所以我们还要自定义一个 HttpServletRequest 的包装类,使得每次请求获取的都是我们自己的HttpSession。

还有一点 ,如何 使用HttpServletRequest 包装类呢?

还需要自定义一个 Filter,这个Filter不干其它的事情,就负责把HttpServletRquest 换成我们自定义的包装类。

第一步 ,定义一个 RedisHttpSession

RedisHttpSession 实现 HttpSession 接口 ,选择Redis存储属性,达到分布式的目标。

session在 Redis中 选择的 Hash 结构存储,以 sessionId 作为Key,有些方法不需要实现。

//首先我说过,HttpSession是不能注入属性的,所以就需要依赖 上面定义的那个 工具类,获取bean
//如果不加此注解,你的属性就会为空,获取不到
@DependsOn("applicationContextUtil")
@SpringBootConfiguration
public class CustomRedisHttpSession implements HttpSession { private HttpServletRequest httpServletRequest;
private HttpServletResponse httpServletResponse;
private Cookie[] cookies;
//sessionId
private String sessionId;
public CustomRedisHttpSession(){} public CustomRedisHttpSession(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,String sid){ this.httpServletRequest = httpServletRequest;
this.httpServletResponse = httpServletResponse;
this.cookies = cookies;
this.sessionId =sid;
} /**
* 获取指定属性值
* @param key 属性key
* @return key对应的value
*/
@Override
public Object getAttribute(String key) {
if(sessionId != null){
return sessionRedisTemplate.opsForHash().get(sessionId,key);
}
return null;
} /**
* 之前说过了,此类属性不能注入,只能通过手动获取
*/
@SuppressWarnings("unchecked")
private final RedisTemplate<String,Object> sessionRedisTemplate =
=ApplicationContextUtil.getBean("sessionRedisTemplate",RedisTemplate.class); //sessionId 的前缀
private static final String SESSIONID_PRIFIX="yangxiaoguang"; /**
* 设置属性值
* @param key key
* @param value value
*/
@Override
public void setAttribute(String key, Object value) {
if (sessionId != null) {
sessionRedisTemplate.opsForHash().put(sessionId, key, value);
}else{
//如果是第一次登录,那么生成 sessionId,将属性值存入redis,设置过期时间,并设置浏览器cookie
this.sessionId = SESSIONID_PRIFIX + UUID.randomUUID();
setCookieSessionId(sessionId);
sessionRedisTemplate.opsForHash().put(sessionId, key, value);
sessionRedisTemplate.expire(sessionId, sessionTimeout, TimeUnit.SECONDS);
}
}
//session的过期时间,8小时
private final int sessionTimeout=28800; //将sessionId存入浏览器
private void setCookieSessionId(String sessionId){
Cookie cookie = new Cookie(SESSIONID,sessionId);
cookie.setPath("/");
cookie.setMaxAge(sessionTimeout);
this.httpServletResponse.addCookie(cookie);
} /**
* 移除指定的属性
* @param key 属性 key
*/
@Override
public void removeAttribute(String key) {
if(sessionId != null){
sessionRedisTemplate.opsForHash().delete(sessionId,key);
}
} }

第2步 ,定义一个 ServletRequestWrapper

如果自定的 HttpSession的,所以我们还要自定义一个 HttpServletRequest 的包装类,使得每次请求获取的都是我们自己的HttpSession。


public class CustomSessionHttpServletRequestWrapper extends HttpServletRequestWrapper{
private HttpServletRequest httpServletRequest;
private HttpServletResponse httpServletResponse;
//自定义Session
private CustomRedisHttpSession customRedisHttpSession; public CustomSessionHttpServletRequestWrapper(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
super(httpServletRequest);
this.httpServletRequest = httpServletRequest;
this.httpServletResponse = httpServletResponse;
Cookie[] cookies = httpServletRequest.getCookies();
String sid= getCookieSessionId(cookies);
this.customRedisHttpSession = new
CustomRedisHttpSession(httpServletRequest,httpServletResponse,sid);
} //这个方法就是最重要的,通过它获取自定义的 HttpSession
@Override
public HttpSession getSession() {
return this.customRedisHttpSession;
} //浏览器的cookie key
private static final String SESSIONID="xyzlycimanage"; //从浏览器获取SessionId
private String getCookieSessionId(Cookie[] cookies){
if(cookies != null){
for(Cookie cookie : cookies){
if(SESSIONID.equals(cookie.getName())){
return cookie.getValue();
}
}
}
return null;
}
}

如果从header 中获取 sessiondi,也是类似的:

public class CustomSessionHttpServletRequestWrapper extends HttpServletRequestWrapper{
private HttpServletRequest httpServletRequest;
private HttpServletResponse httpServletResponse;
//自定义Session
private CustomRedisHttpSession customRedisHttpSession; public CustomSessionHttpServletRequestWrapper(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
super(httpServletRequest);
this.httpServletRequest = httpServletRequest;
this.httpServletResponse = httpServletResponse;
String sid= request.getHeader("SESSION_ID");
this.customRedisHttpSession = new
CustomRedisHttpSession(httpServletRequest,httpServletResponse,sid);
} //这个方法就是最重要的,通过它获取自定义的 HttpSession
@Override
public HttpSession getSession() {
return this.customRedisHttpSession;
} //浏览器的cookie key
private static final String SESSIONID="xyzlycimanage"; //从浏览器获取SessionId
private String getCookieSessionId(Cookie[] cookies){
if(cookies != null){
for(Cookie cookie : cookies){
if(SESSIONID.equals(cookie.getName())){
return cookie.getValue();
}
}
}
return null;
}
}

第三步: 定义一个 Filter 类

还有一点 ,如何 使用HttpServletRequest 包装类呢?

还需要自定义一个 Filter,这个Filter不干其它的事情,就负责把HttpServletRquest 换成我们自定义的包装类。

	/**
* 此过滤器拦截所有请求,也放行所有请求,但是只要与Session操作的有关的请求都换被
* 替换成:CustomSessionHttpServletRequestWrapper包装请求,
* 这个请求会获取自定义的HttpSession
*/
public class CustomSessionRequestFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain)
throws IOException, ServletException { //将请求替换成自定义的 CustomSessionHttpServletRequestWrapper 包装请求
HttpServletRequest customSessionHttpServletRequestWrapper =
new CustomSessionHttpServletRequestWrapper
((HttpServletRequest)servletRequest,(HttpServletResponse)servletResponse); filterChain.doFilter(customSessionHttpServletRequestWrapper,
httpServletResponse); //替换了 请求哦
filterChain.doFilter(customSessionHttpServletRequestWrapper,servletResponse);
} /**
* init 和 destroy 是管理 Filter的生命周期的,与逻辑无关,所以无需实现
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void destroy() {}
}

四步 装载 Filter 类

可以独立加载,也可以放在springsecurity 的配置类中。

如果放在springsecurity 的配置类,具体如下:

package com.gsafety.pushserver.message.config;

//...

@EnableWebSecurity()
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers(
//...
"/actuator/hystrix",
"/actuator/hystrix.stream",
"/v2/api-docs",
"/swagger-resources/configuration/ui",
"/swagger-resources",
"/swagger-resources/configuration/security",
"/swagger-ui.html")
.permitAll()
// .antMatchers("/image/**").permitAll()
// .antMatchers("/admin/**").hasAnyRole("ADMIN")
.and()
.authorizeRequests().anyRequest().authenticated() .and() .formLogin().disable()
.sessionManagement().disable()
.and()
.logout().disable()
.addFilterBefore(new CustomSessionRequestFilter(), SessionManagementFilter.class)
.sessionManagement().disable(); } @Override
public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers(
//....
"/actuator/hystrix.stream",
"/actuator/hystrix",
"/api/mock/**",
"/v2/api-docs",
"/swagger-resources/configuration/ui",
"/swagger-resources",
"/swagger-resources/configuration/security",
"/api/gemp/duty/info/user/login",
"/swagger-ui.html",
"/css/**",
"/js/**",
"/images/**",
"/webjars/**",
"**/favicon.ico"
);
} }

具体,请关注 Java 高并发研习社群博客园 总入口


最后,介绍一下疯狂创客圈:疯狂创客圈,一个Java 高并发研习社群博客园 总入口

疯狂创客圈,倾力推出:面试必备 + 面试必备 + 面试必备 的基础原理+实战 书籍 《Netty Zookeeper Redis 高并发实战


疯狂创客圈 Java 死磕系列

  • Java (Netty) 聊天程序【 亿级流量】实战 开源项目实战

RedisSession (自定义)的更多相关文章

  1. tornado--之cookie自定义(还有session)

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAhAAAAHzCAIAAAD+WrNvAAAgAElEQVR4nOy993cTV7/vf/6qu865ob

  2. 自定义Web组件

    一.Session 1.面向对象基础 面向对象中通过索引的方式访问对象,需要内部实现 __getitem__ .__delitem__.__setitem__方法 +? 1 2 3 4 5 6 7 8 ...

  3. Tornado 自定义Form,session实现方法

    一. 自定义Tornado 验证模块 我们知道,平时在登陆某个网站或软件时,网站对于你输入的内容是有要求的,并且会对你输入的错误内容有提示,对于Django这种大而全的web框架,是提供了form表单 ...

  4. Python web框架 Tornado(三)自定义session组件

    我们在学习Django框架的过程中,内部封装了session组件,以方便于我们使用进行验证.但是Tornado框架是没有session的,所以如果想使用session的话,就需要我们自己定制相对应的组 ...

  5. Tornado之自定义session

      面向对象基础 面向对象中通过索引的方式访问对象,需要内部实现 __getitem__ .__delitem__.__setitem__方法 #!/usr/bin/env python # -*- ...

  6. spring-redis-session 自定义 key 和过期时间

    对于分布式应用来说,最开始遇到的问题就是 session 的存储了,解决方案大致有如下几种 使用 spring-session 它可以把 session 存储到你想存储的位置,如 redis,mysq ...

  7. 关于Unity3D自定义编辑器的学习

    被人物编辑器折腾了一个月,最终还是交了点成品上去(还要很多优化都还么做).  刚接手这项工作时觉得没概念,没想法,不知道.后来就去看<<Unity5.X从入门到精通>>中有关于 ...

  8. 一起学微软Power BI系列-使用技巧(5)自定义PowerBI时间日期表

    1.日期函数表作用 经常使用Excel或者PowerBI,Power Pivot做报表,时间日期是一个重要的纬度,加上做一些钻取,时间日期函数表不可避免.所以今天就给大家分享一个自定义的做日期表的方法 ...

  9. JavaScript自定义浏览器滚动条兼容IE、 火狐和chrome

    今天为大家分享一下我自己制作的浏览器滚动条,我们知道用css来自定义滚动条也是挺好的方式,css虽然能够改变chrome浏览器的滚动条样式可以自定义,css也能够改变IE浏览器滚动条的颜色.但是css ...

随机推荐

  1. .net基础概念

    .net基础概念 1.       .NET Framework 是支持生成和运行下一代应用程序和 XML Web services 的内部 Windows 组件..NET Framework 具有两 ...

  2. javascript基础修炼(13)——记一道有趣的JS脑洞练习题【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  3. 【我的物联网成长记8】超速入门AT指令集【华为云技术分享】

    [摘要] 在物联网中,AT命令集可用于控制&调测设备.通信模块入网等.本文为您介绍NB-IoT常用的AT命令集及其调测工具. 什么是AT指令集 AT命令,用来控制TE(Terminal Equ ...

  4. 关于软件定义IT基础设施的未来,深信服是这么思考的

    在今年的深信服创新大会上,软件定义IT基础设施成为非常重要的议题之一,深信服与2,000余位客户的CIO和合作伙伴一起围绕IT基础设施在数字化时代中的作用与价值进行了深入的探讨. 此外,深信服还联合I ...

  5. webpack入门指南(基于webpack v4.41.2)

    2019年12月5日初稿,目前webpack已经更新到v4.41.2,本文正是基于该版本,在windows8.1操作系统下进行的demo编译,适用于想入门webpack的前端开发人员. webpack ...

  6. 【django后端分离】rbac组件(文件源代码+使用)

    1:用户,角色,权限,菜单表设计 from django.db import models # 用户菜单 class UserMenu(models.Model): title = models.Ch ...

  7. Java修炼——暂停线程的四个方法

    线程的获取方法:Thread.currentThread() 后面可以加上获取线程的名字 .getName() 这样就成功获取到了线程的名字.             Sleep会导致当前线程休眠一定 ...

  8. MVC方法的返回值类型

    MVC方法返回值类型 ModelAndView返回值类型: 1.当返回为null时,页面不跳转. 2.当返回值没有指定视图名时,默认使用请求名作为视图名进行跳转. 3.当返回值指定了视图名,程序会按照 ...

  9. 10分钟搞定nginx实现负载均衡

    10.1 负载均衡的概念 对用户请求的数据进行调度的作用 对用户访问的请求网站可以进行压力的分担 10.2 常见的代理方式 10.2.1 正向代理 10.2.2 反向代理 10.3 负载均衡的部署环节 ...

  10. ARTS-S docker ceontos镜像中使用crontab

    centos镜像中默认没有crontab,需要在dockerflle中通过yum的安装 yum -y install vixie-cron crontabs && yum clean ...