RedisSession (自定义)

文章很长,而且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 :

免费赠送 :《尼恩Java面试宝典》 持续更新+ 史上最全 + 面试必备 2000页+ 面试必备 + 大厂必备 +涨薪必备
免费赠送 经典图书:《Java高并发核心编程(卷1)加强版》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
免费赠送 经典图书:《Java高并发核心编程(卷2)加强版》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
免费赠送 经典图书:《Java高并发核心编程(卷3)加强版》 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
免费赠送 经典图书:尼恩Java面试宝典 最新版 面试必备 + 大厂必备 +涨薪必备 加尼恩免费领
免费赠送 资源宝库: Java 必备 百度网盘资源大合集 价值>10000元 加尼恩领取


RedisSession 场景和问题

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

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

还有一点 ,如何 使用HttpServletRequest 包装类呢?
还需要自定义一个 Filter,这个Filter不干其它的事情,就负责把HttpServletRquest 换成我们自定义的包装类。

说明:本文会以pdf格式持续更新,更多最新尼恩3高pdf笔记,请从下面的链接获取:语雀 或者 码云

第一步 ,定义一个 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);
        }
    }


}


说明:本文会以pdf格式持续更新,更多最新尼恩3高pdf笔记,请从下面的链接获取:语雀 或者 码云

第二步 ,定义一个 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;
    }
}

说明:本文会以pdf格式持续更新,更多最新尼恩3高pdf笔记,请从下面的链接获取:语雀 或者 码云

第三步: 定义一个 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"
        );
    }
}

说明:本文会以pdf格式持续更新,更多最新尼恩3高pdf笔记,请从下面的链接获取:语雀 或者 码云

posted @ 2019-12-14 09:46  疯狂创客圈  阅读(3873)  评论(0编辑  收藏  举报