您的位置:首页 > 其它

会话管理

2016-05-29 14:53 309 查看


会话管理


Cookie技术

Cookie技术:会话数据保存在浏览器客户端。
Cookie核心技术

Cookie类:用于存储会话数据

构造Cookie对象

Cookie(java.lang.String name, java.lang.String value)

设置cookie

void setPath(java.lang.String uri)

设置cookie的有效访问路径

void setMaxAge(int expiry)

设置cookie的有效时间

void setValue(java.lang.String newValue)

设置cookie的值

发送cookie到浏览器端保存

void response.addCookie(Cookie cookie)

发送cookie

服务器接收cookie

Cookie[] request.getCookies()

接收cookie

Cookie的原理
服务器创建cookie对象,把会话数据存储到cookie对象中。

new Cookie("name","value");

服务器发送cookie信息到浏览器

response.addCookie(cookie);

举例: set-cookie: name=eric (隐藏发送了一个set-cookie名称的响应头)

浏览器得到服务器发送的cookie,然后保存在浏览器端。
浏览器在下次访问服务器时,会带着cookie信息

举例: cookie: name=eric (隐藏带着一个叫cookie名称的请求头)

服务器接收到浏览器带来的cookie信息

request.getCookies();

Cookie的细节
void setPath(java.lang.String uri)

设置cookie的有效访问路径。有效路径指的是cookie的有效路径保存在哪里,那么浏览器在有效路径下访问服务器时就会带着cookie信息,否则不带cookie信息。

void setMaxAge(int expiry)

设置cookie的有效时间。

正整数:表示cookie数据保存浏览器的缓存目录(硬盘中),数值表示保存的时间。

负整数:表示cookie数据保存浏览器的内存中。浏览器关闭cookie就丢失了!!

零:表示删除同名的cookie数据

Cookie数据类型只能保存非中文字符串类型的。可以保存多个cookie,但是浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。


Session技术

引入

ookie的局限:

Cookie只能存字符串类型。不能保存对象
只能存非中文。
1个Cookie的容量不超过4KB。

如果要保存非字符串,超过4kb内容,只能使用session技术!!!

Session特点:

会话数据保存在服务器端。(内存中)

Session核心技术
创建或得到session对象

HttpSession getSession()

HttpSession getSession(boolean create)

设置session对象

void setMaxInactiveInterval(int interval)

设置session的有效时间

void invalidate()

销毁session对象

java.lang.String getId()

得到session编号

保存会话数据到session对象

void setAttribute(java.lang.String name, java.lang.Object value)

保存数据

java.lang.Object getAttribute(java.lang.String name)

获取数据

void removeAttribute(java.lang.String name)

清除数据

Session原理

问题:服务器能够识别不同的浏览器

前提:在哪个session域对象保存数据,就必须从哪个域对象取出!!!!

浏览器1:(给s1分配一个唯一的标记:s001,把s001发送给浏览器)

创建session对象,保存会话数据

HttpSession session = request.getSession(); -->保存会话数据 s1

浏览器1的新窗口(带着s001的标记到服务器查询,s001->s1,返回s1)

得到session对象的会话数据

HttpSession session = request.getSession(); -->可以取出 s1

新的浏览器1:(没有带s001,不能返回s1)

得到session对象的会话数据

HttpSession session = request.getSession(); --不可以取出 s2

浏览器2:(没有带s001,不能返回s1)

得到session对象的会话数据

HttpSession session = request.getSession(); --不可以取出 s3

代码解读:HttpSession session = request.getSession();

第一次访问创建session对象,给session对象分配一个唯一的ID,叫JSESSIONID

new HttpSession();

把JSESSIONID作为Cookie的值发送给浏览器保存

Cookie cookie = new Cookie("JSESSIONID", sessionID); response.addCookie(cookie);

第二次访问的时候,浏览器带着JSESSIONID的cookie访问服务器
服务器得到JSESSIONID,在服务器的内存中搜索是否存放对应编号的session对象。
if(找到){
return map.get(sessionID);
}
Map<String,HttpSession>]

<"s001", s1>
<"s001,"s2>

如果找到对应编号的session对象,直接返回该对象
如果找不到对应编号的session对象,创建新的session对象,继续走1的流程

结论:通过JSESSION的cookie值在服务器找session对象!!!!!

Sesson细节
java.lang.String getId()

得到session编号

两个getSession方法:

getSession(true) / getSession() :

创建或得到session对象。没有匹配的session编号,自动创建新的session对象。

getSession(false)

得到session对象。没有匹配的session编号,返回null

void setMaxInactiveInterval(int interval)

设置session的有效时间

session对象销毁时间:

默认情况30分服务器自动回收

修改session回收时间

全局修改session有效时间

<!-- 修改session全局有效时间:分钟 --><session-config><session-timeout>1</session-timeout></session-config>


手动销毁session对象

void invalidate()

销毁session对象

如何避免浏览器的JSESSIONID的cookie随着浏览器关闭而丢失的问题
/*** 手动发送一个硬盘保存的cookie给浏览器
*/
Cookie c = new Cookie("JSESSIONID",session.getId());
c.setMaxAge(60*60);
response.addCookie(c);


经常遇到的问题解决方法

IE禁用Cookie之后的Session处理

解决方法:URL重写

response.encodeRedirectURL(java.lang.String url)

用于对sendRedirect方法的URL重写

response.encodeURL(java.lang,String url)

用于对表单action或超链接的url地址重写

利用session防止表单重复提交

具体的做法:

在服务器端生成一个唯一的随机标识号,专业术语称为Token(令牌),同时在当前用户的Session域中保存这个Token。然后将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端,然后在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。

在下列情况下,服务器程序将拒绝处理用户提交的表单请求:

存储Session域中的Token(令牌)与表单提交的Token(令牌)不同。
当前用户的Session中不存在Token(令牌)。
用户提交的表单数据中没有Token(令牌)。

实例

创建FormServlet,用于生成Token(令牌)和跳转到form.jsp页面

protectedvoid doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String token = TokenProccessor.getInstance().makeToken();//创建令牌16
System.out.println("在FormServlet中生成的token:"+token);
request.getSession().setAttribute("token", token);  //在服务器使用session保存token(令牌)18
request.getRequestDispatcher("/form.jsp").forward(request, response);//跳转到form.jsp页面19

}


在form.jsp中使用隐藏域来存储Token(令牌)

<%@ pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>form表单</title></head><body><form action="${pageContext.request.contextPath}/servlet/DoFormServlet"method="post"><%--使用隐藏域存储生成的token--%><%--
<inputtype="hidden"name="token"value="<%=session.getAttribute("token") %>">
--%>
<%--使用EL表达式取出存储在session中的token--%><input type="hidden"name="token"value="${token}"/>
用户名:<input type="text"name="username"><input type="submit"value="提交"></form></body></html>


DoFormServlet处理表单提交

publicvoid doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

boolean b = isRepeatSubmit(request);//判断用户是否是重复提交if(b==true){
System.out.println("请不要重复提交");
return;
}
request.getSession().removeAttribute("token");//移除session中的token
System.out.println("处理用户提交请求!!");
}

/**
* 判断客户端提交上来的令牌和服务器端生成的令牌是否一致
* @param request
* @return
*         true 用户重复提交了表单
*         false 用户没有重复提交表单
*/privateboolean isRepeatSubmit(HttpServletRequest request) {
String client_token = request.getParameter("token");
//1、如果用户提交的表单数据中没有token,则用户是重复提交了表单if(client_token==null){
returntrue;
}
//取出存储在Session中的tokenString server_token = (String) request.getSession().getAttribute("token");
//2、如果当前用户的Session中不存在Token(令牌),则用户是重复提交了表单if(server_token==null){
returntrue;
}
//3、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同,则用户是重复提交了表单if(!client_token.equals(server_token)){
returntrue;
}

returnfalse;
}


生成Token的工具类TokenProccessor

publicclassTokenProccessor {

/*
*单例设计模式(保证类的对象在内存中只有一个)
*1、把类的构造函数私有
*2、自己创建一个类的对象
*3、对外提供一个公共的方法,返回类的对象
*/privateTokenProccessor(){}

privatestaticfinal TokenProccessor instance = new TokenProccessor();

/**
* 返回类的对象
* @return
*/publicstatic TokenProccessor getInstance(){
return instance;
}

/**
* 生成Token
* Token:Nv6RRuGEVvmGjB+jimI/gw==
* @return
*/public String makeToken(){  //checkException//  7346734837483  834u938493493849384  43434384
String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
//数据指纹   128位长   16个字节  md5try {
MessageDigest md = MessageDigest.getInstance("md5");
byte md5[] =  md.digest(token.getBytes());
//base64编码--任意二进制编码明文字符   adfsdfsdfsf
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(md5);
} catch (NoSuchAlgorithmException e) {
thrownew RuntimeException(e);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息