简单的session共享的封装
目的
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共享的封装的更多相关文章
- nginx+tomcat9+redisson+redis+jdk1.8简单实现session共享
一.环境安装 由于资源限制,在虚拟机中模拟测试,一台虚拟机,所有软件均安装到该虚拟机内 安装系统:CentOS Linux release 7.4.1708 (Core) CentOS安装选择版本:B ...
- 设计模式之装饰模式,session共享的底层原理
前言 还记得当初写spring-session实现分布式集群session的共享的时候,里面有说到利用filter和HttpServletRequestWrapper可以定制自己的getSession ...
- Tomcat通过Memcached实现session共享的完整部署记录
对于web应用集群的技术实现而言,最大的难点就是:如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块.要实现这一点, 大体上有两种方式:一种是把所有Ses ...
- Session共享的简单总结
1.同服务器.同一域名.不同应用(端口.虚拟目录等) 这种很简单,把sessionState保存到SQLServer,aspnet_regsql之后,修改存储过程TempGetAppID,把 SET ...
- Spring Boot 一个依赖搞定 session 共享,没有比这更简单的方案了!
有的人可能会觉得题目有点夸张,其实不夸张,题目没有使用任何修辞手法!认真读完本文,你就知道松哥说的是对的了! 在传统的单服务架构中,一般来说,只有一个服务器,那么不存在 Session 共享问题,但是 ...
- 分布式集群Session共享 简单多tomcat8+redis的session共享实现
; i++) { str = str + session.getAttribute("name" + i) + "<br>"; } response ...
- Tomcat中session共享问题的简单解决办法
tomcat-redis-session-manager 使用redis配置tomcat共享session 结构图: 分析: 分布式web server集群部署后需要实现session共享,针对 to ...
- 分布式中使用Redis实现Session共享(二)
上一篇介绍了一些redis的安装及使用步骤,本篇开始将介绍redis的实际应用场景,先从最常见的session开始,刚好也重新学习一遍session的实现原理.在阅读之前假设你已经会使用nginx+i ...
- 分布式中使用Redis实现Session共享(一)
上一篇介绍了如何使用nginx+iis部署一个简单的分布式系统,文章结尾留下了几个问题,其中一个是"如何解决多站点下Session共享".这篇文章将会介绍如何使用Redis,下一篇 ...
随机推荐
- 实测可用的免费STUN服务器!
实测可用的免费STUN服务器! 以实际ping延迟排序: stun.voipbuster.com 287ms stun.wirlab.net 320ms s1.taraba.net ...
- Python学习笔记(4):自定义时间类
Python的时间我实在无法接受,太难用了.我觉得C#的时间就非常完美,简单.好用.所以,自定义了自己的时间类: 用法: 一个小小的应用,我需要取出每天股市交易的分钟段,开始是这样的: 稍微改进一下, ...
- java微信开发API第一步 服务器接入
I如何接入服务器,下面就为大家进行介绍 一.说明 * 本示例根据微信开发文档:http://mp.weixin.qq.com/wiki/home/index.html最新版(4/3/2016 5:34 ...
- Md5加密方法
package com.atguigu.surveypark.util; import java.security.MessageDigest; /** * 数据 */ public class Da ...
- Android 解压boot.img
其实解压.打包boot.img没什么难度一看就会咯!! 1.先下附件:工具. 点击打开链接 6.0 KB, 下载次数: 60) 解压到bin文件夹里,方便以后使用. 2.解压boot ...
- Hadoop学习-生态体系(ecosystem)概览
0. 大背景 全球No.1搜索引擎公司谷歌(Google)面临每天海量搜索引擎数据的问题,经过长时间的实践积累, 谷歌形成了自己的大数据框架,但是并没有开源,而是发表了一篇论文,阐述了自己的思想,在论 ...
- WPF的Timer控件的使用WPF的Timer控件的使用
通过System.Threaing.Timer控件来实现“初始加载页面时为DataGrid的模版列赋初始值” System.Threaing.Timer的用法: 步骤1: //声明定时器 System ...
- Ecshop文章列表页显示内容摘要
本教程中讲到的“内容摘要”指的是文章内容的前 60个字符(当然也可以是前40个,前50个等等) 下面以 2.7.2版 + 官方默认模板 为例进行讲解: 1).修改 includes/lib_artic ...
- composite
#coding:utf-8 import math # 在确定函数前,我们先来了解下算法 # 有数 n 判断其是否是合数 # 如果 n 除以 range(2,math.sqrt(n)+1) 能够整除, ...
- cmd实用命令
1.netstat 查看电脑端口状况 实际应用举例:查看某软件坚监听的电脑端口. 在任务管理器中选择列...,打开PID的显示.在这里查看某个应用程序的线程ID是多少.例如QQ:4904. 运行,cm ...