Servlet会话跟踪

会话跟踪技术
  • 什么是会话?
    会话可简单理解为:打开浏览器 -> 访问一些服务器内容 -> 关闭浏览器,整个过程称之为一个会话。
  • 会话过程中要解决的问题?
    HTTP 是一种“无状态”协议,每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,服务器要想办法为每个用户保存这些数据:
    如:用户登录场景,当不同的用户登录系统后,我们如何在主页面显示不同的用户名?
  • 会话跟踪技术是一种在客户端与服务器间保持HTTP状态的解决方案,管理浏览器客户端和服务器端之间会话过程中产生的会话数据。从开发角度考虑,是使上一次请求所传递的数据能够维持状态到下一次请求,并且辨认出是否相同的客户端所发送出来的。
  • 会话跟踪技术的解决方案主要分为以下几种:
    Cookie技术
    Session技术
    URL重写技术
    隐藏表单域技术
一、Cookie
  • Cookie技术是一种在客户端保持会话跟踪的解决方案,会话数据保存在客户端浏览器。
  • Cookie在用户第一次访问服务器时,由服务器通过响应头的方式发送给客户端浏览器;当用户再次向服务器发送请求时会附带上这些文本信息。
  • 在使用Cookie时,要保证客户端浏览器接受Cookie。


  • 存储Cookie会话数据

1.构造Cookie对象

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

2.设置cookie

  • void setPath(java.lang.String uri):设置cookie的有效访问路径。
    默认cookie只能由创建它的应用获得,设置cookie.setPath(“/”),则可在同一应用服务器内的所有应用共享访问。
  • void setMaxAge(int expiry) : 设置cookie的有效时间
    该Cookie失效时间,单位秒。如果为正数,则该Cookie在expiry秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1
  • void setValue(java.lang.String newValue) :设置cookie的值
    Cookie的值不能设置成非ASSIC字符,如果要使用中文可以通过URLEncoder将其编码,否则会出异常。
    Cookie大小和数量的限制,不同的浏览器有所区别,一般每个域名最多可存储
    50个cookie,Cookie总的的大小限制为4KB。

3.将Cookie对象响应给客户端浏览器,存储在客户端。

  • void response.addCookie(Cookie cookie) : 发送cookie
@WebServlet("/CookieStorageServlet")
public class CookieStorageServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      Cookie ck1 = new Cookie("name",URLEncoder.encode("张三","UTF-8"));
      Cookie ck2 = new Cookie("jSessionId", "10001");
      Cookie ck3 = new Cookie("email","xx@xx.com");
      Cookie ck4 = new Cookie("status","1");
      ck1.setMaxAge(-1);//默认值
      ck2.setMaxAge(0);//删除cookie
      ck3.setMaxAge(24*60*60);//设置1天后失效
      ck3.setPath("/ch03-cookie/shopping");
      ck4.setMaxAge(10);//10秒后失效
      response.addCookie(ck1);
      response.addCookie(ck2);
      response.addCookie(ck3);
      response.addCookie(ck4);
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      doGet(request, response);
  }
}
  • 获取Cookie会话数据

存储在客户端的Cookie,通过HttpServletRequest对象的getCookies()方法获取,该方法返回所访问网站的所有Cookie的对象数组,遍历该数组可以获得各个Cookie对象。

@WebServlet("/CookieGetServlet")
public class CookieGetServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      // TODO Auto-generated method stub
      response.setContentType("text/html;charset=UTF-8");
      request.setCharacterEncoding("utf-8");
      PrintWriter out = response.getWriter();
      
      Cookie[] cookies = request.getCookies();
      for(Cookie c:cookies) {
          if("name".equals(c.getName())) {
              out.println("<p>" + URLDecoder.decode(c.getValue(),"UTF-8") + "<p>");
          }else {
              out.println("<p>" + c.getValue() + "<p>");
          }
          out.println("<p>" + c.getName() + "<p>");
          out.println("==========================");
      }
      out.close();
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      // TODO Auto-generated method stub
      doGet(request, response);
  }
}

  • Cookie的局限性
  • Cookie可能被禁用,当用户非常注重个人隐私保护时,很可能会禁用浏览器的Cookie功能;
  • Cookie可能被删除,因为每个Cookie都是硬盘上的一个文件,因此很有可能被用户删除;
  • Cookie的大小和个数受限,不同浏览器有所区别,Cookie保存的数据不能超过4095个字节,50个/每个域名;
  • Cookie安全性不够高,所有的Cookie都是以纯文本的形式记录于文件中,因此如果要保存用户名密码等信息时,最好事先经过加密处理。
二、Session
  • Session是指使用HttpSession对象实现会话跟踪的技术,是一种在服务器端保持会话跟踪的解决方案。
  • HttpSession对象会在用户第一次访问服务器时由容器创建(注意只有访问JSP、Servlet等程序时才会创建,只访问HTML、IMAGE等静态资源并不会创建),当用户调用其失效方法(invalidate()方法)或超过其最大不活动时间时会失效。在此期间,用户与服务器之间的多次请求都属于同一个会话。
  • Session和Cookie的主要区别在于:
    Cookie是把用户的数据写给用户的浏览器。
    Session技术把用户的数据写到用户独占的session中。
  • Session工作原理

服务器在创建会话对象时,会为其分配一个唯一的会话标识——SessionId,以“JSESSIONID”的属性名保存在客户端Cookie中,在用户随后的请求中,服务器通过读取Cookie中的JSESSIONID属性值来识别不同的用户,从而实现对每个用户的会话跟踪。


  • 获取HttpSession对象
@WebServlet("/CreateSessionServlet")
public class CreateSessionServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        //获取HttpSession对象标识sessionid
        out.println("<p>" + session.getId() + "</p>");
        //获取HttpSession对象产生的时间,单位是毫秒
        out.println("<p>" + session.getCreationTime() + "</p>");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}
  • Session存取数据
  • 存储会话域属性
    session.setAttribute("username"," neuedu ");
  • 会话域中获取属性值
    String uname = (String)session.getAttribute("username");
  • 会话域中删除属性
    session.removeAttribute("username");
  • 例:当用户当用户登录成功后,将用户信息存储到session中,并重定向到主页面显示用户信息。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <form action="login" method="post">
        <input type="text" name="userName" placeholder="用户名"/><br/>
        <input type="password" name="password" placeholder="密码"/><br/>
        <input type="submit" value="登录"/>
    </form>
</body>
</html>
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取session对象
        HttpSession session = request.getSession();
        //模拟登陆成功
        String userName = request.getParameter("userName");
        //向session中存储用户名
        session.setAttribute("userName",userName);
        response.sendRedirect("index");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}
@WebServlet("/index")
public class IndexServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        //获取session对象
        HttpSession session = request.getSession();
        String userName = (String)session.getAttribute("userName");
        //判断是否登录成功:
        if(userName == null || "".equals(userName)) {
            //没有登录成功,跳转到login.html
            response.sendRedirect("login.html");
            return;
        }
        //设置session的非活动时间
        session.setMaxInactiveInterval(10);
        out.println("<p> 欢迎你:" + userName + "<p>");
        out.println("<a href=\"logout\">退出登录</a>");
        out.close();
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }
}
  • Session生命周期
  • Session失效时间
    session具有一定声生命周期,如果session超过会话的最大不活动时间,会话自动失效,会话的最大不活动时间指会话超过此时间段不进行任何操作;
  • 设置Session的失效时间
    方法1:在工程的web.xml中配置session的生命周期,单位为分钟;
    <session-config> <session-timeout>15</session-timeout> </session-config>
    方法2:在程序硬编码设置
    session.setMaxInactiveInterval(30 * 60);//设置单位为秒,设置为-1永不过期;
    方法3:在Tomcat安装目录下conf/web.xml中配置(Web容器级别)
    <session-config> <session-timeout>15</session-timeout> </session-config>
  • 手动销毁Session
    可以通过调用invalidate()方法立即清除会话对象及其所有会话域属性,同时响应客户端浏览器清除Cookie中的JSESSIONID
  • 在实际应用中,此方法多用来实现系统的“安全退出”功能。
@WebServlet("/logout")
public class LogoutSerlvet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        //手动销毁sessoin
        request.getSession().invalidate();
        response.sendRedirect("login.html");
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}
三、其它会话技术
  • URL重写技术
  • URL重写技术是实现动态网站会话跟踪的重要保障。在实际应用中,当客户端浏览器禁用Cookie后的session处理,当不能确定客户端浏览器是否支持Cookie的情况下,使用URL重写技术可以对请求的URL地址追加会话标识,从而实现用户的会话跟踪功能。
  • URL重写实现方法
@WebServlet("/UrlRewriterServlet")
public class UrlRewriterServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      // TODO Auto-generated method stub
      response.setContentType("text/html;charset=UTF-8");
      PrintWriter out = response.getWriter();
      HttpSession session = request.getSession();
      // 两个请求地址进行URL重写
      String link1 = response.encodeURL("UrlRewriterResultServlet");
      String link2 = response.encodeURL("UrlRedirectServlet");
      // 使用超链接形式对URL重写地址进行请求
      out.println("<p><a href='" + link1 + "'>对一个普通Servlet的请求</a></p>");
      out.println("<p><a href='" + link2 + "'>对一个含有重定向代码的Servlet的请求</a></p>");
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse >response) throws ServletException, IOException {
      doGet(request, response);
  }
}
@WebServlet("/UrlRewriterResultServlet")
public class UrlRewriterResultServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      java.io.PrintWriter out = response.getWriter();
      // 获取经URL重写传递来的会话标识值
      String sessionId = request.getSession().getId();
      out.println(sessionId);
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      // TODO Auto-generated method stub
      doGet(request, response);
  }
}
@WebServlet("/UrlRedirectServlet")
public class UrlRedirectServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      // TODO Auto-generated method stub
      String url = response.encodeRedirectURL("UrlRewriterResultServlet");
      response.sendRedirect(url);
  }
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      // TODO Auto-generated method stub
      doGet(request, response);
  }
}
  • URL重写技术应用注意事项:
    1.如果应用需要使用URL重写,那么必须对应用的所有请求(包括所有的超链接、表单的action属性值和重定向地址)都进行重写,从而将jsessionid维持下来;
    2.由于浏览器对URL地址长度的限制,特别是在对含有查询参数的GET请求进行URL重写时,需要注意其总长度;
    3.由于静态页面不能进行会话标识的传递,因此所有的URL地址都必须为动态请求地址。
  • 隐藏表单域
  • 利用Form表单的隐藏表单域,在用户无法从页面显示看到隐藏标识的情况下,将标识随请求一起传送给服务器处理,从而实现会话的跟踪。
  • 在Form表单中定义隐藏域
    <input type="hidden" name="userID" value="10010">
  • 在服务器端通过HttpServletRequest对象获取隐藏域的值
    String flag = request.getParameter("userID");
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352

推荐阅读更多精彩内容

  • 本文包括:1、Filter简介2、Filter是如何实现拦截的?3、Filter开发入门4、Filter的生命周期...
    廖少少阅读 7,266评论 3 56
  • 会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Se...
    chinariver阅读 5,613评论 1 49
  • 2.1 软件中的会话 一次会话: 打开浏览器 -> 访问一些服务器内容 -> 关闭浏览器 登录场景: 打开浏览器 ...
    yangliangliang阅读 376评论 0 0
  • 这部分主要是与Java Web和Web Service相关的面试题。 96、阐述Servlet和CGI的区别? 答...
    杂货铺老板阅读 1,402评论 0 10
  • 已经不知过了多少年,这里的宅院早已破烂不堪,只剩下那棵结满桃花的树,在风中摇曳。 当年满脸阳光充满梦想的扎着两个蝴...
    小倩星阅读 657评论 1 63