重写request的getSession方法实现集群session共享

我们在用redis实现session共享的时候,会遇到这样的问题:当一个用户登陆后,可能集群环境下给你分配到另一台服务器,这时候你用request.getSession()获取的session是现在服务器上的session,里面没有你想要的用户信息,然后你又要重新登录,这样是你会同意吗,肯定不行的,所以我们不需要系统自动创建session了,我们来自己写一个实现共享;

首先实现重写的第一步就是使用过滤器,那么我们来配置一个过滤器:他能在目标方法之前对请求进行处理,这样我们就可以用过滤器代替原有的创建session的方法;

   
  
    sessionFilter  
    util.SessionFilter  
  
  
    sessionFilter  
    /*  
 

然后我们去创建这个过滤器:

public class SessionFilter implements Filter {
	public FilterConfig config;
	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		// TODO Auto-generated method stub
		 HttpServletRequest req = (HttpServletRequest) request;
		 HttpServletResponse res=(HttpServletResponse)response;
         req = new SecurityServletRequestWrapper(req, res);
         chain.doFilter(req, res);
	}
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		this.config=null;
	}
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		this.config=filterConfig;
	}
}

上面的SecurityServletRequestWrapper类就是我们要去重写的类,这里我们要重写HttpServletRequestWrapper中的getSession方法:

public class SecurityServletRequestWrapper extends HttpServletRequestWrapper{
	private HttpSession session;
	private HttpServletRequest request;
	private HttpServletResponse response;
	public SecurityServletRequestWrapper(HttpServletRequest request,HttpServletResponse response) {
		super(request);
		this.request=request;
		this.response=response;
	}
	//重写获取session的方法
	public HttpSession getSession() {
		return this.getSession(true);
	} 
	public HttpSession getSession(boolean create) {
		if(create){
			String id = CookieUtil.getCookieValue(request, "pcxSessionId");
			if(StringUtils.isEmpty(id)){
				id=UUID.randomUUID().toString();
				CookieUtil.setCookie(request, response, "pcxSessionId", id, 60*60);
			}
			this.session=new DispacherSessionImmpl(this.request,this.response,id);
			return this.session;
		}else{
			return null;
		}
    }
}

我们从cookie里面获取session的ID,如果获取不到,那就创建一个id然后保存到session中,这个ID就是新的session的ID;这里有个CookieUtil类它里面两个方法就是从cookie中获取数据和保存数据到cookie;当然其他方法没有实现;

public class CookieUtil {
    public static void setCookie(HttpServletRequest request,
            HttpServletResponse response, String name, String value, int seconds) {
        if (StringUtils.isEmpty(name) || StringUtils.isEmpty(value))
            return;
        Cookie cookie = new Cookie(name, value);
        //cookie.setDomain(domain);
        cookie.setMaxAge(seconds); 
        cookie.setPath("/");
        response.setHeader("P3P",
                "CP='IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT'");
        response.addCookie(cookie);
    }
    public static String getCookieValue(HttpServletRequest request,String name){
        Cookie cookies[] = request.getCookies();
        if (cookies != null) {
            for (int i = 0; i < cookies.length; i++) {
                if (name.equalsIgnoreCase(cookies[i].getName())) {
                    return cookies[i].getValue();
                }
            }
        }
        return "";
    }
}

然后我们重点看的就是DispacherSessionImmpl类;它实现了HttpSession接口,方法有些多,只说一下修改了的方法,没有说的都是实现原方法就可以;

public class DispacherSessionImmpl implements HttpSession{
	
	private HttpSession session;
	private HttpServletRequest request;
	private HttpServletResponse response;
	private Map sessionMap=null;
	private SessionStore sessionStore=new SessionStore();
	private String sid;
	public DispacherSessionImmpl(){
	}
	public DispacherSessionImmpl(HttpSession session){
		this.session=session;
	}
	public DispacherSessionImmpl(HttpServletRequest request,HttpServletResponse response,String id){
		this.sid=id;
		this.request=request;
		this.response=response;
	}

sessionMap存储放进session中的数据的;

SessionStore是将session数据与redis进行关联实现共享;

	@Override
	public Object getAttribute(String name) {
		// TODO Auto-generated method stub
		if(sessionMap==null){
			sessionMap=sessionStore.getSession(this.getId());
		}
		return sessionMap.get(name);
	}

这个是获取你存储的信息的;

@Override
	public void setAttribute(String name, Object value) {
		// TODO Auto-generated method stub
		if(sessionMap==null){
			sessionMap=sessionStore.getSession(this.getId());
		}
		this.sessionMap.put(name, value);
		sessionStore.saveSession(this.getId(), sessionMap);
	}

往session中存储数据的;这里就是redis中存储了;

@Override
	public void removeAttribute(String name) {
		// TODO Auto-generated method stub
		if(sessionMap==null){
			sessionMap=sessionStore.getSession(this.getId());
		}
		sessionMap.remove(name);
		sessionStore.removeSession(this.getId());
	}

移除数据的方法;

@Override
	public void invalidate() {
		// TODO Auto-generated method stub
		this.sessionMap.clear();
		sessionStore.removeSession(this.getId());
		
	}

删除用的;

接下来我们就看一下存储那个类,这里要用到序列化,我们先写一个序列化得到类出来,直接调用就行

public class Hessian2Serialization {
	public byte[] serialize(Object obj) throws IOException{  
	    if(obj==null) throw new NullPointerException();  
	    ByteArrayOutputStream os = new ByteArrayOutputStream();  
	    HessianOutput ho = new HessianOutput(os);  
	    ho.writeObject(obj);  
	    return os.toByteArray();  
	}  
	public Object deserialize(byte[] by) throws IOException{  
	    if(by==null) throw new NullPointerException();  
	    ByteArrayInputStream is = new ByteArrayInputStream(by);  
	    HessianInput hi = new HessianInput(is);  
	    return hi.readObject();  
	}  
}

在这里,我们需要hession的jar包,

我们看一下存储:

public class SessionStore {
	private Hessian2Serialization h2Serialization=new Hessian2Serialization();
	//private RedisUtil redisUtil;
	private Jedis jedis=new Jedis("127.0.0.1", 6379);
	public Map getSession(String sid){
		 Map session=new HashMap();
		 try {
			 byte[] bs = jedis.get(sid.getBytes());
			 if(bs!=null){
				 Object deserialize = h2Serialization.deserialize(bs);
				 session=(Map) deserialize;
			 }
		} catch (Exception e) {
			// TODO: handle exception
		}
		return session;
	}
	public void saveSession(String sid,Map session){
		try {
			byte[] bs = h2Serialization.serialize(session);
			jedis.set(sid.getBytes(), bs);
			jedis.expire(sid.getBytes(), 3600);//设置过期时间
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
	public void removeSession(String sid){
		try {
			jedis.del(sid.getBytes());
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
}
到这里,我们就可以去测试了。
















你可能感兴趣的:(重写request的getSession方法实现集群session共享)