首页 > 代码库 > 使用cookie管理Servlet的session

使用cookie管理Servlet的session

由于集群下session同步性能较差,可以选择使用cookie保存session。session处理遵照以下几点

1.选择map做session的存储,在更新时写入cookie,可以保证每次请求时能正常获取上次记录的session。


2.添加子类重写HttpSession的方法,将其修改的方法实现为对map的修改,在每次修改后更新response的cookie。

自定义HttpSession

public class CsmSession implements HttpSession {

	private ConcurrentHashMap<String, Object> session;
	private String uuid;
	private Kryo kryo = new Kryo();
	private HttpServletResponse response;
	private HttpServletRequest request;

	@SuppressWarnings("unchecked")
	public CsmSession(HttpServletRequest request, HttpServletResponse response,
			String data, String uuid) {
		this.request = request;
		this.response = response;
		this.uuid = uuid;
		DeflateSerializer deflateSerializer = new DeflateSerializer(
				kryo.getDefaultSerializer(ConcurrentHashMap.class));
		BlowfishSerializer blowfishSerializer = new BlowfishSerializer(
				deflateSerializer, Constants.BLOWFISH_KEY);
		kryo.register(ConcurrentHashMap.class, blowfishSerializer);
		if (data != null) {
			try {
				Input input = new Input(Base64.decodeBase64(data));
				this.session = this.kryo.readObject(input,
						ConcurrentHashMap.class);
				input.close();
			} catch (Exception e) {
			}
		}
		if (this.session == null) {
			this.session = new ConcurrentHashMap<String, Object>();
			this.change();
		}
	}

	@Deprecated
	@Override
	public long getCreationTime() {
		return 0;
	}

	@Override
	public String getId() {
		return this.uuid;
	}

	@Deprecated
	@Override
	public long getLastAccessedTime() {
		return 0;
	}

	@Override
	public ServletContext getServletContext() {
		return this.request.getServletContext();
	}

	@Deprecated
	@Override
	public void setMaxInactiveInterval(int interval) {
	}

	@Deprecated
	@Override
	public int getMaxInactiveInterval() {
		return 0;
	}

	@SuppressWarnings("deprecation")
	@Override
	public HttpSessionContext getSessionContext() {
		return null;
	}

	@Override
	public Object getAttribute(String name) {
		return session.get(name);
	}

	@Override
	public Object getValue(String name) {
		return session.get(name);
	}

	@Override
	public Enumeration<String> getAttributeNames() {
		return session.keys();
	}

	@Override
	public String[] getValueNames() {
		return session.keySet().toArray(new String[0]);
	}

	@Override
	public void setAttribute(String name, Object value) {
		this.put(name, value);
		this.change();
	}

	@Override
	public void putValue(String name, Object value) {
		this.put(name, value);
		this.change();
	}

	@Override
	public void removeAttribute(String name) {
		session.remove(name);
		this.change();
	}

	@Override
	public void removeValue(String name) {
		session.remove(name);
		this.change();
	}

	@Override
	public void invalidate() {
		session.clear();
		this.change();
	}

	@Deprecated
	@Override
	public boolean isNew() {
		return false;
	}

	public String toCookieString() {
		Output output = new Output(1024, Constants.SESSION_MAX);
		this.kryo.writeObject(output, this.session);
		byte[] bytes = output.toBytes();
		output.close();
		return Base64.encodeBase64URLSafeString(bytes);
	}

	public void addToCookie(HttpServletResponse response, String path) {
		String cookieStr = this.toCookieString();
		CookieUtil.setCookie(response, Constants.SESSION_DATA, cookieStr, path);
	}

	private void change() {
		addToCookie(response, "/");
	}

	private void put(String name, Object value) {
		if (name == null)
			return;
		if (value =http://www.mamicode.com/= null)>

更新cookie


public static void setCookie(HttpServletResponse response, final Cookie cookie) {
        if (response.isCommitted()) {
            return;
        }
        final String headername = "Set-Cookie";
        String header = generateCookieString(cookie);
        final String startsWith = cookie.getName() + "=";
        Collection<String> headers = response.getHeaders(headername);
        String replaceItem = null;
        for (String item : headers) {
			if(item.startsWith(startsWith)){
				replaceItem = item;
			}
		}
        if(replaceItem != null){
        	headers.remove(replaceItem);
        	response.setHeader(headername, header);
        	for (String item : headers) {
        		response.addHeader(headername, item);
			}
        }else{
        	response.addHeader(headername, header);
        }
    }


3.使用filter将request包装后再继续执行,在包装的request中重写获取session、sessionid等方法,转为自己实现的session

filter处理:

public void doFilter(ServletRequest request, ServletResponse response,
		FilterChain chain) throws IOException, ServletException {
	String uri = ((HttpServletRequest) request).getRequestURI();
	boolean isStatic = uri.matches(".*\\.(ico|png|gif|jpg|css|js)$"); //静态文件不需要session处理
	if (!isStatic) {
		logger.info("start session filter uri="+uri);

		CsmServletRequest req = new CsmServletRequest(
				(HttpServletRequest) request,
				(HttpServletResponse) response);
		chain.doFilter(req, response);
		logger.info("session filter finished");
	}else{
		chain.doFilter(request, response);
	}
}

request重写

public class CsmServletRequest extends HttpServletRequestWrapper {
	private HttpSession session;
	private HttpServletResponse response;

	public CsmServletRequest(HttpServletRequest request,
			HttpServletResponse response) {
		super(request);
		this.response = response;
	}

	@Override
	public HttpSession getSession() {
		return this.getSession(true);
	}

	@Override
	public HttpSession getSession(boolean create) {
		this.initSession(create);
		return this.session;
	}

	@Override
	public String getRequestedSessionId() {
		return this.getSession().getId();
	}

	private void initSession(boolean create) {
		if (this.session == null && create) {
			this.session = SessionBuilder.get(this, this.response).cookie()
					.build();
		}
	}
}


这样,每次对session的修改就能转为cookie的写入,集群中不再需要额外对session进行共享、复制处理。


使用cookie管理Servlet的session