Web应用创建于HTTP之上,这会有一个严重的问题,即HTTP是一个无状态的协议,每个请求和相应都是独立的。如果没有会话管理,每次客服端向服务器端发起一个请求,服务器端都不会记录有关客户的任何信息。从服务器度端的角度看,一个新的请求就是一个新的用户,这个请求和其它请求也没有任何关系。为了解决这个问题,在web中引入了会话(session)的概念。
一个会话(session)是指从客户端发起第一个请求开始,即一个会话的开始时刻,到这个会话终止时刻的客户端与服务端的整个交互过程。
那么怎样保存客户端与服务端的会话状态信息呢,下面介绍两种方法。
1.利用cookies跟踪会话
当应用服务器第一次接收到一个请求时(如自定义的url参数action为none),先为该用户分配一个唯一的sessionid;或者也可以自己写一个函数),将该sessionid添加到用户的cookies中;此后每次接收到请求时,就从该请求用户的cookies中读取sessionid,这时如果没有成功读取,这就说明该用户不是通过默认的url来访问的,此时的处理方法就要根据网站的具体应用来决定了,如你可以跳转到自定义的错误页面,提示他通过默认的url登录,也可以把这个请求看成第一个请求来处理。
servlet的代码框架如下:
import
java.io.IOException;
import
java.util.Hashtable;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
import
javax.servlet.
*
;
import
javax.servlet.http.
*
;
public
class
CController
extends
HttpServlet
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
//在这里声明所用到的模型对象
//private Hashtable<String,SessionData> sessionDataTable=new Hashtable<String,SessionData>();
//...
public void init() throws ServletException
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
//在这里添加其他资源的初始化代码(如数据库连接)
//...
}
public void destroy()
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
//在这里添加收回其他资源的代码(如关闭数据库连接)
//...
}
//Process the HTTP Get request
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
String action=request.getParameter("action");
String jspPage="/index.jsp";
if(action==null||action.length()<1)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
action="none";
}
if(action.equals("none"))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
//第一次请求,分配一个唯一分配的sessionid,或者也可以自定义函数(推荐)
HttpSession session = request.getSession();
String sessionId=request.getRequestedSessionId();
//将会话数据对象添加到自定义的Hashtable中
//sessionDataTable.put(sessionId,new SessionData());
//将sessionid添加到用户cookies中(这里可设置path和cookies有效时间)
response.addCookie(new Cookie("JSESSIONID",sessionId));
request.setAttribute("sessionid", sessionId);
}
else if(action.equals("home"))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
//从用户cookies中读取sessionid
Cookie[] c=request.getCookies();
String sessionId="";
for(int i=0;i<c.length;i++)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
if(c[i].getName().equals("JSESSIONID"))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
sessionId=c[i].getValue();
}
}
if(!sessionId.equals(""))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
//读取session数据对象
//SessionData data=sessionDataTable.get(sessionId);
//其他处理...
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
jspPage="error.html";
}
}
else if(action.equals("xxx"))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
Cookie[] c=request.getCookies();
String sessionId="";
for(int i=0;i<c.length;i++)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
if(c[i].getName().equals("JSESSIONID"))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
sessionId=c[i].getValue();
}
}
if(!sessionId.equals(""))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
//读取session数据对象
//SessionData data=sessionDataTable.get(sessionId);
//其他处理...
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
jspPage="error.html";
}
}
//在这里添加处理action="xxx"请求的代码
//...
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
jspPage="error.html";
}
dispatch(jspPage,request,response);
}
protected void dispatch(String jsp, HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
if(jsp!=null)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
RequestDispatcher rd=request.getRequestDispatcher(jsp);
rd.forward(request,response);
}
}
protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
doPost(request, response);
}
}
注:SessionData为自定义的会话数据对象类
2.利用url改写跟踪会话
在一个公共的web应用上,我们可能遇到一些用户拒绝接收服务器端发送来的cookies,那么此时我们可以用url改写跟踪会话,下面给出它的servlet代码框架
import
java.io.IOException;
import
java.util.ArrayList;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
import
javax.servlet.
*
;
import
javax.servlet.http.
*
;
public
class
Controller
extends
HttpServlet
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
//在这里声明所用到的模型对象
//...
public void init() throws ServletException
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
//在这里添加其他资源的初始化代码(如数据库连接)
//...
}
public void destroy()
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
//在这里添加收回其他资源的代码(如关闭数据库连接)
//...
}
//Process the HTTP Get request
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
String action=request.getParameter("action");
String jspPage="/index.jsp";
if(action==null||action.length()<1)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
action="none";
}
if(action.equals("none"))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
//创建一个session对象
HttpSession session = request.getSession(true);
//将会话数据对象添加到session的属性中
//session.setAttribute("xxx", new SessionData());
//重写url
String url=response.encodeURL("controller");
request.setAttribute("url_data", url);
}
else if(action.equals("home"))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
HttpSession session = request.getSession(false);
if(session!=null)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
//获取会话数据对象
//SessionData data=(SessionData)session.getAttribute("xxx");
//在这里添加处理action="home"请求的代码
//...
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
jspPage="error.html";
}
}
else if(action.equals("xxx"))
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
HttpSession session = request.getSession(false);
if(session!=null)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
SessionData data=(SessionData)session.getAttribute("xxx");
//在这里添加处理action="xxx"请求的代码
//...
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
jspPage="error.html";
}
}
//在这里添加处理action="其他"请求的代码
//...
else
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
jspPage="error.html";
}
dispatch(jspPage,request,response);
}
protected void dispatch(String jsp, HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
if(jsp!=null)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
RequestDispatcher rd=request.getRequestDispatcher(jsp);
rd.forward(request,response);
}
}
protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
doPost(request, response);
}
在上面的代码中,当第一次请求时(自定义url参数action为none),则为该用户定义一个新的session,此后每次都通过HttpSession session = request.getSession(false)获得该session,如果为null,则此时的处理方法就如同上面没有成功读取cookies中的sessionid一样了。而且,在接收第一次请求时我们还通过代码String url=response.encodeURL("controller");request.setAttribute("url_data", url);改写了url。这样,我们只要在在jsp页面中定义一个作用域为session的变量url,
<c:if test="${empty url}">
<c:set var="url" value="${requestScope.url_data}" scope="session"/>
</c:if>
此后jsp页面中的每个链接只需写成这样的形式即可${url}?action=xxx&...
下面总结一下这两种方法各自的优点和缺点
cookies跟踪会话
优点:地址栏中的url简洁明了
缺点:会话数据对象所在的hashtable学要自己编写代码来处理回收工作,如一个sesssion结束后相应的会话数据也就无效了,但是我们不知道何时一个session结束,因此只有监视表中的每个对象,当超过一个指定的时间间隔就回收。而且,当用户拒绝使用cookies是该方法就无效了。
url改写跟踪会话
优点:不用自定义hash表结构,可以直接通过session.setAttribute("xxx", new SessionData())来保存会话数据对象,回收也是自动的(事实上它也正式采用了面的机制,因此我们可以设置有效时间间隔,默认为30分钟)
缺点:除默认链接外,地址栏中的url冗长,一般形式为www.xxx.com/controller;jsessionid=3490E0D8F7F0D0SDS7DFDFF?action=xxx&...