Session概述

当人们去医院就诊时,就诊病人需要办理医院的就诊卡,该卡上只有卡号,而没有其它信息。但病人每次去该医院就诊时,只要出示就诊卡,医务人员便可根据卡号查询到病人的就诊信息。
Session技术就好比医院发放给病人的就医卡和医院为每个病人保留病例档案的过程。
当浏览器访问Web服务器时,Servlet容器就会创建一个Session对象和ID属性,其中,Session对象就相当于兵力档案,ID就相当于就诊卡号。当客户端后续访问服务器时,只要将标识号传递给服务器,服务器就能判断出该请求是哪个客户端发送的,从而选择与之对应的Session对象为其服务。

需要注意的是,由于客户端需要接收、记录和回送Session对象的ID,因此,通常情况下,Session是借助Cookie技术来传递ID属性的。

示例:以购物网站为例,通过下图描述Session保存用户信息的原理:
在这里插入图片描述
在上去中,用户甲和乙都调用buyServlet将商品添加到购物车,调用payServlet进行商品结算。由于甲和乙购买商品的过程类似,在此,以用户甲为例进行详细说明。当用户访问购物网站时,服务器为甲创建了一个Session对象(相当于购物车)。当甲将Nokia手机添加到购物车时,Nokia手机的信息便存放到了Session对象中。同时,服务器将Session对象的ID属性以Cookie(Set-Cookie:JSESSIONID=111)的形式返回给甲的浏览器。当甲完成购物进行结账时,需要向服务器发送结账请求,这时,浏览器自动在请求消息头中将Cookie(Cookie:JSESSIONID=111)信息回送给服务器,服务器根据ID属性找到为用户甲所创建的Session对象,并将Session对象中所存放的Nokia手机信息取出进行结算。

为什么要使用会话
  • 使用Servlet生成验证码时,我们需要在服务器记录一份生成的随机字符,当用户提交填写的数据时,将用户输入的数据和服务器缓存的数据进行对比。
  • 将随机字符串保存在ServletContext中或者request中是否可以?
    • 将数据存放到ServletContext,多个用户共享一个验证码。
      在这里插入图片描述
    • 将数据存放到request作用域,多次请求不能共享数据。
      在这里插入图片描述 - 将数据保存到ServletContext和request中是存在问题的,那么就需要使用会话技术保存用户的私有信息。
为何有了Cookie还需要Session
  • Cookie是有大小和个数的限制的Session存到服务器端的技术,没有大小和个数的限制
  • Cookie相对于Session来讲不安全
使用Session

Session是与每个请求消息紧密相关的,为此i,HttpServletRequest定义了用于获取session对象的getSession()方法,该方法有两种重载形式,具体如下。

public HttpSession getSession(boolean create)
public HttpSession getSession()

上面重载的两个方法都用于返回与当前请求相关的HttpSession对象。不同的是,第一个getSession()方法根据传递的参数来判断是否创建新的HttpSession对象,如果参数为true,则在相关的HttpSession对象不存在时创建并返回新的HtttpSession对象,否则不创建新的HttpSession对象,而是返回null。
第二个getSession()方法则相当于第一个方法参数为true时的情况,在相关的HttpSession对象不存在时总是创建新的HttpSession对象。

要想使用HttpSession对象管理会话数据,不仅需要获取到HttpSession对象,还需要了解HttpSession对象的相关方法。HttpSesseion接口中定义的操作会话数据的常用方法如下表:

Session API
方法声明功能描述
String getId()用于返回与当前HttpSession对象关联的会话标识号
long getCreationTime()返回Session创建的时间,这个时间是创建Session的时间与1970年1月1日00:00:00之间时间差的毫秒形式表示
long getLastAccessedTime()返回客户端最后一次发送与Session相关请求的时间,这个时间是发送请求的时间与1970年1月1日00:00:00之间时间差的毫秒表示形式
void setMaxInactiveInterval(int interval)用于设置当前HttpSession对象可空闲的以秒为单位的最长时间,也就是修改当前会话的默认超时间隔
boolean isNew()判断当前HttpSession对象是否是新创建的
void invalidate()用于强制使Session对象无效
ServletContext getServletContext()用于返回当前HttpSession对象所属于的WEB应用程序对象,即代表当前WEB应用程序的ServletContext对象
void setAttribute(String name, Object value)用于将一个对象与一个名称关联后存储到当前的HttpSession对象中
String getAttribute()用于从当前HttpSession对象中返回指定名称的属性对象
void removeAttribute(String name)用于从当前HttpSession对象中删除指定名称的属性
实例

使用HttpSession对象获取Session会话创建时间和最后访问时间。如果不存在session会话,我们将通过请求创建一个新的session会话。

package pers.zhang.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author zhang
 * @date 2019/9/19 - 11:29
 */
public class SessionServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //如果不存在Session会话,则创建一个session对象
        HttpSession session = request.getSession(true);
        //获取session创建时间
        Date createTime = new Date(session.getCreationTime());
        //获取该网页的最后一次访问时间
        Date lastAccessTime = new Date(session.getLastAccessedTime());

        //设置日期输出的格式
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        String title = "Servlet Session";
        Integer visitCount = new Integer(0);
        String visitCountKey = new String("visitCount");
        String userIDKey = new String("userID");
        String userID = new String("zhang");
        if(session.getAttribute(visitCountKey) == null){
            session.setAttribute(visitCountKey, new Integer(0));
        }

        //检查网页上是否有新的访问者
        if(session.isNew()){
            title = "Servlet Session";
            session.setAttribute(userIDKey, userID);
        }else{
            visitCount = (Integer) session.getAttribute(visitCountKey);
            visitCount = visitCount + 1;
            userID = (String) session.getAttribute(userIDKey);
        }
        session.setAttribute(visitCountKey, visitCount);

        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();

        String docType = "<!DOCTYPE html>\n";
        out.println(docType +
                "<html>\n" +
                "<head><title>" + title + "</title></head>\n" +
                "<body bgcolor=\"#f0f0f0\">\n" +
                "<h1 align=\"center\">" + title + "</h1>\n" +
                "<h2 align=\"center\">Session 信息</h2>\n" +
                "<table border=\"1\" align=\"center\">\n" +
                "<tr bgcolor=\"#949494\">\n" +
                "  <th>Session 信息</th><th>值</th></tr>\n" +
                "<tr>\n" +
                "  <td>id</td>\n" +
                "  <td>" + session.getId() + "</td></tr>\n" +
                "<tr>\n" +
                "  <td>创建时间</td>\n" +
                "  <td>" +  df.format(createTime) +
                "  </td></tr>\n" +
                "<tr>\n" +
                "  <td>最后访问时间</td>\n" +
                "  <td>" + df.format(lastAccessTime) +
                "  </td></tr>\n" +
                "<tr>\n" +
                "  <td>用户 ID</td>\n" +
                "  <td>" + userID +
                "  </td></tr>\n" +
                "<tr>\n" +
                "  <td>访问统计:</td>\n" +
                "  <td>" + visitCount + "</td></tr>\n" +
                "</table>\n" +
                "</body></html>");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}

浏览器第一次访问,页面显示:
在这里插入图片描述
第二次访问:
在这里插入图片描述

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐