目的

  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. 493萬Gmail用戶的賬號密碼遭洩露,Google否認自己存在安全漏洞

    最近,大公司在互聯網信息安全問題上狀況頻出.上週,蘋果因iCloud被黑客攻擊而導致大量明星私照外洩,著實是熱鬧了一陣.而Google也來湊熱鬧了.據俄羅斯媒體CNews消息,近493萬Gmail用戶 ...

  2. IntelliJ IDEA 2016.2.4 最新版激活方法

    新版激活方法: 1.在线激活 2016年7月14日 更新: 该域名已无法激活,参见2016.2 的搭建授权服务器激活, 菜单help >>>> Register 选择Licen ...

  3. 分布式Hadoop安装(一)

    本文旨在介绍通过两台物理节点,实现完全分布式hadoop程序的部署 writen by Bob Pan@20140609 环境介绍: 主机名 机器IP 用途 描述 Hadoop0 192.168.80 ...

  4. 简单好用的sshfs -- 通过ssh映射远程路径(转)

    最近习惯性访问N个Linux机器,在不同机器间跳来跳去,很是麻烦,最终,找到了sshfs,可以把远程目录直接映射到本地,无需修改远程机器的设置,仅要求有ssh连接的权限(ssh都没有的话,还能干啥?! ...

  5. ThinkCMF 解决xss攻击问题

    最近使用ThinkCMF给某政府开发的一个平台,因为他们需要通过国家二级信息安全等级测试 所以自己先使用Appscan测试了一下,结果扫描出一个xss安全问题 测试的网址:http://www.xxx ...

  6. MVC使用基架添加控制器出现的错误:无法检索XXX的元数据

    环境 vs2012 框架 mvc3 数据库  sqlservercompact4.0 出现的错误如下: “ ---------------------------Microsoft Visual St ...

  7. 用飞信监控GoldenGate进程

    监控GoldenGate进程 1)         在goldengate安装目录下建立文件ogginfo $vim ogginfo  info all 2)         配置飞信报警       ...

  8. leveldb - log格式

    log文件在LevelDb中的主要作用是系统故障恢复时,能够保证不会丢失数据.因为在将记录写入内存的Memtable之前,会先写入Log文件,这样即使系统发生故障,Memtable中的数据没有来得及D ...

  9. word2007无法执行语言识别

    步驟1:取消“啟用自動語言檢測”在“審閱”選項卡上的“校對”組中,單擊“設置語言”(一個圖標,看起來類似於前麵帶有複選標記的地球).取消“自動檢測語言”複選框.步驟2:取消“鍵入入時檢查拚寫”到Wor ...

  10. 同时大量连接导致的DDOS攻击,导致收发器宕机,用户大面积超时掉线

    前段时间一个客户改成电信网通自动路由后(当然和这个没有关系,但是客户一般没有分析能力,会多想),用户经常大面积掉线,用户才180多个,在线最多也才120多,十分苦恼,原先帮其维护的技术人员,只是远程诊 ...