目的
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代码,实际应用需重构代码。
from:https://www.cnblogs.com/davidwang456/p/5256874.html
