Session与Cookie不同的是,它是写在服务器端的。当一个浏览器链接到服务器后,服务器会为这个浏览器分配一块特定的内存来存储session的信息。但是当有很多客户端访问服务器时,服务器会为他们分配很多session的内存用于存储每个客服端访问服务器时产生的信息,比如订单等,那么,这些session怎么和每个客户端一一对应呢?这里的解决办法是给每一个客户端一个独一无二的SessionID,而这个SessionID是与session一一对应的。当一个客户端离开当前页面与服务器另一个页面交互时,服务器会根据这个客户端特有的SessionID,找到与他对于的session,从而拿到他之前与服务器其他页面交互时留下的信息,以便进行下一步操作。
那么,新的问题是,这个SessionID存储在什么地方呢?以浏览器访问服务器为例,只要浏览器没有禁用掉Cookie,那么他是通过Cookie存储在浏览器里面的,生命周期和当前的浏览器窗口一样,当浏览器窗口关闭时,Cookie消失。
如果浏览器禁用掉了Cookie,那么必须要自己编程,重写encodeURL()方法,使得重新发起页面请求时,在请求的URL后面带着上一个页面产生的SessionID。
以登陆邮箱为例综合分析Cookie和Session在其中发挥的作用:
当输入用户名和密码的时候点击登陆后,服务器会分配给客户端一个SessionID,这个sessionID要么存储在Cookie中,要么跟在下一次请求的URL后面。这样,进入到读取邮件信息页面时,通过客户端的SessionID找到服务器里对应的Session(里面存在说明用户已经登陆的信息),从而得以判断当前请求的用户确实已经登陆过了,这时才会让你有权限读取邮件。
同时,经常在登陆页旁有一个“一个星期内自动登陆”的选项。实际上,勾选了这个选项后,服务器就会通过向客户端写入cookie的方式,将登陆信息写入本地磁盘文件,并且保存一个星期,这样下次登陆时直接读取cookie里面的信息,从而实现自动登陆。
下面的代码为一段关于用session实现记录页面访问次数的功能。
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class TestSession extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//整个功能用来记录该页面的访问次数
PrintWriter pw = resp.getWriter();//向客户端写数据的流
HttpSession session = req.getSession(true);
Integer accessCount = (Integer)session.getAttribute("access");//拿到session里的值
if(accessCount == null){
accessCount = new Integer(0);
}else{
accessCount = new Integer(accessCount.intValue()+1);
}
session.setAttribute("access", accessCount);//向session里设置值
pw.println(accessCount);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
当在浏览器里访问这个sevlet时,因为这个计数器是通过session存储存储的,也就是说是与每一个客户端一一对应的。当关掉当前页面再启一个页面重新访问这个servlet时,会发现计数又重新从零开始。注意,这点与application的区别。
下面这段代码通过application来实现计数功能。
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TestApplication extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext application = this.getServletContext();//拿到当前webApplication的上下文
PrintWriter pw = resp.getWriter();
Integer accessCount = (Integer) application.getAttribute("access");
if(accessCount == null){
accessCount = new Integer(0);
}else{
accessCount = new Integer(accessCount.intValue()+1);
}
application.setAttribute("access", accessCount);
pw.println(accessCount);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
super.doPost(req, resp);
}
}
当在浏览器中访问这个servlet时,即使关掉当前页面重新再启一个页面,计数也会从上一个页面的数字继续增加。这就是application的特点。
每一个服务器上面可能会有很多个webApplication,而每一个webApplication里面则可能会有很多个servlet对外提供服务。每一个webApplication都有自己的Context,也就是这整个webApplication运行的环境,application的内容就是存储在这个Context里面的,所以所有的客户端都可以访问,而不像session那样每个客户端都有自己特定的一块用来存储session信息,而且只能自己独自访问。