目的

  session存储在缓存服务器上(各种缓存服务器上均可,本文以memcached为例),但对开发者来说,他不用关注,只需要调用request.getSession()方法即可获取到session,然后对session的属性进行操作。

面临的问题

  1. session获取,不是从application的服务器上获取,要从memcached上获取。

  2. session属性的获取及设置,不是设置到application服务器上,而是操作memcached获取或者设置。

解决问题的方法

  1. 使用一个HttpServletRequestWrapper的实现类,重写getSession()方法,然后使用filter,来过滤每个请求,使request变为requestWrapper。

  2. 使用一个HttpSessionAttributeListener的实现类,重写attributeAdded()、attributeRemoved()、attributeReplaced()方法,当属性发生改变时需要通知memcached中的session发生改变

另外:为解决各个异构系统因语言不通可能发生的兼容问题,session以json字符串存储。

具体代码如下:

wrapper类

import java.io.IOException;
import java.util.Map; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpSession; import org.springframework.util.StringUtils; import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.javacodegeeks.util.JacksonMapUtil;
import com.javacodegeeks.util.MemcachedUtil; public class GetSessionWrapper extends HttpServletRequestWrapper{
private String sessionId=null;
public GetSessionWrapper(HttpServletRequest request) {
super(request);
}
public GetSessionWrapper(HttpServletRequest request,String sessionId) {
super(request);
this.setSessionId(sessionId);
} @Override
public HttpSession getSession() {
HttpSession httpSession=super.getSession();
//id-->sessionId;
String id="davidwang456";
String json=MemcachedUtil.getValue(id);
if(StringUtils.isEmpty(json)){
return httpSession;
}
httpSession.setAttribute("JPHPSESSID", id);
// 读取JSON数据
Map<String, Object> userData;
try {
userData = JacksonMapUtil.getMapper().readValue(json, Map.class);
for(Map.Entry<String, Object> entry:userData.entrySet()){
httpSession.setAttribute(entry.getKey(), entry.getValue());
}
} catch (JsonParseException e) {
System.out.println("json字符串不能解析成功!");
} catch (JsonMappingException e) {
System.out.println("json字符串不能映射到Map!");
} catch (IOException e) {
System.out.println("io异常!");
}
return httpSession;
} @Override
public HttpSession getSession(boolean create) {
HttpSession httpSession=super.getSession(create);
return httpSession;
}
public static void main(String[] args) {
String sessionId="davidwang456";
String json=MemcachedUtil.getValue(sessionId);
System.out.println(json);
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
}

filter类

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import org.springframework.web.util.WebUtils; public class FetchSession implements javax.servlet.Filter{
private static final String regex=".*(css|html|ico|html|jpg|jpeg|png|gif|js)";
@Override
public void init(FilterConfig filterConfig) throws ServletException { } private static String getSessionId(ServletRequest request){
HttpServletRequest httpRequest=(HttpServletRequest)request;
String sessionId="";
Cookie cookie =WebUtils.getCookie(httpRequest, "PHPSESSID");
if(cookie!=null){
return cookie.getValue();
}
cookie =WebUtils.getCookie(httpRequest, "JSESSIONID");
if(cookie!=null){
sessionId= cookie.getValue();
}
return sessionId;
} @Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
String sessionId=getSessionId(request);
HttpServletRequest httpRequest=(HttpServletRequest)request;
String requestedUri=httpRequest.getRequestURL().toString();
System.out.println(requestedUri);
if(requestedUri.matches(regex)){
chain.doFilter(request, response);
return;
}
GetSessionWrapper wrapperRequest=new GetSessionWrapper(httpRequest,sessionId);
//HttpSession httpSession=wrapperRequest.getSession();
chain.doFilter(wrapperRequest, response);
} @Override
public void destroy() {
}
}

属性监听器

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger; import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent; import org.springframework.util.StringUtils; import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.javacodegeeks.util.JacksonMapUtil;
import com.javacodegeeks.util.MemcachedUtil; public class MySessionAttributeListener
implements HttpSessionAttributeListener {
private static AtomicInteger count=new AtomicInteger(0);
private static AtomicInteger countU=new AtomicInteger(0); @Override
public void attributeAdded(HttpSessionBindingEvent event) {
int ss=count.incrementAndGet();
HttpSession session=event.getSession();
//String sessionId=(String) session.getAttribute("JPHPSESSID");
String sessionId="davidwang456";
String attributeName = event.getName();
Object attributeValue = event.getValue();
System.out.println("Attribute add " + attributeName + " : " + attributeValue+",ss="+ss);
String json=MemcachedUtil.getValue(sessionId);
if(StringUtils.isEmpty(json)){
return ;
}
String json_new;
try {
json_new = attributeAddOrUpdate(json,attributeName,attributeValue);
MemcachedUtil.setValue(sessionId, json_new);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} private String attributeAddOrUpdate(String json,String key,Object value)
throws JsonParseException, JsonMappingException, IOException{
ObjectMapper mapper=JacksonMapUtil.getMapper();
@SuppressWarnings("unchecked")
Map<String,Object> userData = mapper.readValue(json, Map.class);
Boolean flag=String.class.isAssignableFrom(value.getClass());
if(!flag){
Map<String, Object> map = mapper.convertValue(value, Map.class);
userData.putAll(map);
}else{
userData.put(key, value);
}
return mapper.writeValueAsString(userData);
} private String attributeDel(String json, String key)
throws JsonParseException, JsonMappingException, IOException {
ObjectMapper mapper = JacksonMapUtil.getMapper();
@SuppressWarnings("unchecked")
Map<String, Object> userData = mapper.readValue(json, Map.class);
userData.remove(key);
return mapper.writeValueAsString(userData);
} @Override
public void attributeRemoved(HttpSessionBindingEvent event) {
HttpSession session=event.getSession();
//String sessionId=(String) session.getAttribute("JPHPSESSID");
String sessionId="davidwang456";
String attributeName = event.getName();
System.out.println("Attribute del : " + attributeName);
String json=MemcachedUtil.getValue(sessionId);
if(StringUtils.isEmpty(json)){
return ;
}
String json_new;
try {
json_new = attributeDel(json,attributeName);
MemcachedUtil.setValue(sessionId, json_new);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} @Override
public void attributeReplaced(HttpSessionBindingEvent event) { int ssu=countU.incrementAndGet();
HttpSession session=event.getSession();
//String sessionId=(String) session.getAttribute("JPHPSESSID");
String sessionId="davidwang456";
String attributeName = event.getName();
Object attributeValue = event.getValue();
System.out.println("Attribute update " + attributeName + " : " + attributeValue+",ss="+ssu);
String json=MemcachedUtil.getValue(sessionId);
if(StringUtils.isEmpty(json)){
return ;
}
String json_new;
try {
json_new = attributeAddOrUpdate(json,attributeName,attributeValue);
MemcachedUtil.setValue(sessionId, json_new);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } }

pom.xml依赖:

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-guava</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>net.spy</groupId>
<artifactId>spymemcached</artifactId>
<version>2.12.0</version>
</dependency>

注意:上面代码仅为demo代码,实际应用需重构代码。

简单的session共享的封装的更多相关文章

  1. nginx+tomcat9+redisson+redis+jdk1.8简单实现session共享

    一.环境安装 由于资源限制,在虚拟机中模拟测试,一台虚拟机,所有软件均安装到该虚拟机内 安装系统:CentOS Linux release 7.4.1708 (Core) CentOS安装选择版本:B ...

  2. 设计模式之装饰模式,session共享的底层原理

    前言 还记得当初写spring-session实现分布式集群session的共享的时候,里面有说到利用filter和HttpServletRequestWrapper可以定制自己的getSession ...

  3. Tomcat通过Memcached实现session共享的完整部署记录

    对于web应用集群的技术实现而言,最大的难点就是:如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块.要实现这一点, 大体上有两种方式:一种是把所有Ses ...

  4. Session共享的简单总结

    1.同服务器.同一域名.不同应用(端口.虚拟目录等) 这种很简单,把sessionState保存到SQLServer,aspnet_regsql之后,修改存储过程TempGetAppID,把 SET ...

  5. Spring Boot 一个依赖搞定 session 共享,没有比这更简单的方案了!

    有的人可能会觉得题目有点夸张,其实不夸张,题目没有使用任何修辞手法!认真读完本文,你就知道松哥说的是对的了! 在传统的单服务架构中,一般来说,只有一个服务器,那么不存在 Session 共享问题,但是 ...

  6. 分布式集群Session共享 简单多tomcat8+redis的session共享实现

    ; i++) { str = str + session.getAttribute("name" + i) + "<br>"; } response ...

  7. Tomcat中session共享问题的简单解决办法

    tomcat-redis-session-manager 使用redis配置tomcat共享session 结构图: 分析: 分布式web server集群部署后需要实现session共享,针对 to ...

  8. 分布式中使用Redis实现Session共享(二)

    上一篇介绍了一些redis的安装及使用步骤,本篇开始将介绍redis的实际应用场景,先从最常见的session开始,刚好也重新学习一遍session的实现原理.在阅读之前假设你已经会使用nginx+i ...

  9. 分布式中使用Redis实现Session共享(一)

    上一篇介绍了如何使用nginx+iis部署一个简单的分布式系统,文章结尾留下了几个问题,其中一个是"如何解决多站点下Session共享".这篇文章将会介绍如何使用Redis,下一篇 ...

随机推荐

  1. c++builder调用VC的dll以及VC调用c++builder的dll

    解析__cdecl,__fastcall, __stdcall 的不同:在函数调用过程中,会使用堆栈,这三个表示不同的堆栈调用方式和释放方式. 比如说__cdecl,它是标准的c方法的堆栈调用方式,就 ...

  2. LPC43xx SGPIO DMA and Interrupts

    The SGPIO output pins SGPIO14 and SGPIO15 can trigger a GPDMA request SGPIO pins SGPIO14 and SGPIO15 ...

  3. Oracle的sqlnet.ora与password文件试验

    先看有没有sqlnet.ora [oracle@localhost ~]$ cd $ORACLE_HOME[oracle@localhost dbhome_1]$ cd network[oracle@ ...

  4. jquery实现返回基部案例效果

    <!doctype html> <html> <head> <meta charset="gb2312"> <title> ...

  5. samba权限之easy举例说明--原创

    实验环境RHEL5.0,samba3.023rc-2 一.何为browsealbe=no? 如图lingdao目录的权限为777 如图ling目录的共享设置和用户的ID和组 当用户lingdao_01 ...

  6. apache的hadoop升级到CDH hadoop2.0时遇到的问题及解决

    1:引入的jar包 1.X版本有hadoop-core包:而2.x没有 如果你需要hdfs就引入\share\hadoop\common\lib + hadoop-common-2.0.0-cdh4. ...

  7. VMware Workstation安装RedHat Linux 9

    RedHatLinux是目前世界上使用最多的Linux操作系统.因为它具备最好的图形界面无论是安装.配置还是使用都十分方便.下面我将介绍使用VMware Workstation安装RedHat Lin ...

  8. ReactiveCocoa与Functional Reactive Programming

    转自 http://blog.leezhong.com/ios/2013/06/19/frp-reactivecocoa.html Functional Reactive Programming(以下 ...

  9. 【LeetCode】257. Binary Tree Paths

    Binary Tree Paths Given a binary tree, return all root-to-leaf paths. For example, given the followi ...

  10. MySQL – 导出数据成csv

    方案有很多种,我这里简单说一下: 1.  into outfile SELECT * FROM mytable INTO OUTFILE '/tmp/mytable.csv' FIELDS TERMI ...