上一节我们总结了cookie技术,这节主要总结一下session技术。

1. session对象

在web开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。
        session和cookie的主要区别在于:cookie是把用户的数据写给用户的浏览器(保存在客户机);session技术把用户的数据写到用户独占的session中(保存在服务器)。
        session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。

2. session实现原理

浏览器A第一次访问Servlet1,服务器会创建一个session,每个session都有一个id号,创建好了后,服务器将id号以cookie的形式回送给客户机(这些是服务器自动完成的)。当浏览器未关闭前再次发请求访问Servlet2时,就会带着这个id号去访问服务器,这时候服务器检索下内存中有没有与之对应的session,有就用这个session为其服务。
        如果想要关掉浏览器再打开还可以使用同一个session,则需要给服务器回送的cookie设置有效时间(服务器自动回送的时候是没有有效期的)。具体做法是通过session对象的getId方法获得该session的id,然后创建一个cookie,该cookie的名字为"JSESSIONID",值就是刚刚获得的id,再将该cookie设置下有效期,(也可以设置下Path),并添加到cookie中即可。但是有效期不得超过30分钟,因为浏览器关掉后,session只保存30分钟。

下面通过一个案例来说明一下session的使用。

3. session的一个案例

通过三个servlet来实现简单的购物功能:

IndexServlet显示首页,并列出所有书(这个servlet和上一节cookie的案例中基本一致)

  1. //首页:列出所有书
  2. public class IndexServlet extends HttpServlet {
  3.  
  4. public void doGet(HttpServletRequest request, HttpServletResponse response)
  5. throws ServletException, IOException {
  6.  
  7. response.setContentType("text/html;charset=UTF-8");
  8. PrintWriter out = response.getWriter();
  9.  
  10. out.write("本网站有如下书:<br/>");
  11.  
  12. Set<Map.Entry<String,Book>> set = DB.getAll().entrySet();
  13. for(Map.Entry<String, Book> me : set) {
  14. Book book = me.getValue();
  15. out.write(book.getName() + "<a href='/test/servlet/BuyServlet?id="+book.getId()+"'>购买</a><br/>");
  16.  
  17. }
  18.  
  19. }
  20.  
  21. public void doPost(HttpServletRequest request, HttpServletResponse response)
  22. throws ServletException, IOException {
  23.  
  24. doGet(request, response);
  25. }
  26.  
  27. }
  28.  
  29. //写一个类来模拟数据库
  30. class DB {
  31.  
  32. private static Map<String,Book> map = new LinkedHashMap();
  33.  
  34. //静态代码块中的内容只执行一次,该类在加载时,往map集合中put一系列书,map也需要设置为静态的
  35. static{
  36.  
  37. map.put("1", new Book("1", "javaweb开发","老张", "一本好书"));
  38. map.put("2", new Book("2", "spring开发","老倪", "一本好书"));
  39. map.put("3", new Book("3", "hibernate开发","老童", "一本好书"));
  40. map.put("4", new Book("4", "struts开发","老毕", "一本好书"));
  41. map.put("5", new Book("5", "ajax开发","老张", "一本好书"));
  42. map.put("6", new Book("6", "java基础","老孙", "一本好书"));
  43.  
  44. }
  45.  
  46. public static Map getAll() {
  47. return map;
  48. }
  49. }
  50.  
  51. class Book {
  52.  
  53. private String id;
  54. private String name;
  55. private String author;
  56. private String description;
  57.  
  58. public Book() {
  59. }
  60.  
  61. public Book(String id, String name, String author, String description) {
  62. super();
  63. this.id = id;
  64. this.name = name;
  65. this.author = author;
  66. this.description = description;
  67. }
  68.  
  69. public String getId() {
  70. return id;
  71. }
  72. public void setId(String id) {
  73. this.id = id;
  74. }
  75. public String getName() {
  76. return name;
  77. }
  78. public void setName(String name) {
  79. this.name = name;
  80. }
  81. public String getAuthor() {
  82. return author;
  83. }
  84. public void setAuthor(String author) {
  85. this.author = author;
  86. }
  87. public String getDescription() {
  88. return description;
  89. }
  90. public void setDescription(String description) {
  91. this.description = description;
  92. }
  93. }

从上面程序中可以看出,当用户点击购买时,将书的id号带上,并跳转到BuyServlet去处理:

  1. public class BuyServlet extends HttpServlet {
  2.  
  3. public void doGet(HttpServletRequest request, HttpServletResponse response)
  4. throws ServletException, IOException {
  5.  
  6. String id = request.getParameter("id"); //获得url中带过来的参数id
  7. Book book = (Book)DB.getAll().get(id); //在DB中获得该id号的book
  8.  
  9. HttpSession session = request.getSession(); //获得当前session对象
  10. Cookie cookie = new Cookie("JSESSIONID", session.getId()); //设置新的cookie,注意cookie名必须为JSESSIONID,值为该session的id
  11. cookie.setMaxAge(30*60); //设置cookie有效期
  12. cookie.setPath("/test"); //设置cookie的路径
  13. response.addCookie(cookie); //将cookie添加到cookies中带给浏览器,下次浏览器访问,就会将此cookie带过来了
  14.  
  15. //先把书加到容器里,再把容器加到session中。一般先检查用户的session中有没有保存书的容器,没有就创建,有就加
  16. List list = (List)session.getAttribute("list");
  17. if(list == null) {
  18. list = new ArrayList();
  19. session.setAttribute("list", list);
  20. }
  21. list.add(book);
  22.  
  23. //跳转到显示用户买过哪些商品
  24. // request.getRequestDispatcher("/servlet/ListCartServlet").forward(request, response);
  25. response.sendRedirect("/test/servlet/ListCartServlet");
  26.  
  27. }
  28.  
  29. public void doPost(HttpServletRequest request, HttpServletResponse response)
  30. throws ServletException, IOException {
  31.  
  32. doGet(request, response);
  33. }
  34. }

从上面的程序可以看出,当用户点击购买后,会将书的id号带过来,我们拿到id号后就可以找到相应的书,同时我们将当前session的id保存到cookie中,再带给浏览器,这样下次浏览器访问的时候就会将当前session的id带过来了。拿到相应的书后,放到list中,再把list放到session中,这样下次跳转的时候,浏览器带来的cookie中有当前session的id,我们可以通过getSession()获得当前的session,再把session中保存的list拿出来,就知道用户买了哪些书了。这就是购物车的原理,请看下面的ListCartServlet:

  1. public class ListCartServlet extends HttpServlet {
  2.  
  3. public void doGet(HttpServletRequest request, HttpServletResponse response)
  4. throws ServletException, IOException {
  5.  
  6. response.setContentType("text/html;charset=UTF-8");
  7. PrintWriter out = response.getWriter();
  8.  
  9. HttpSession session = request.getSession(); //获得当前的session
  10. List<Book> list = (List)session.getAttribute("list"); //从session中拿出list
  11.  
  12. if(list == null || list.size() == 0) {
  13. out.write("对不起,您还没有购买任何商品!");
  14. return;
  15. }
  16.  
  17. out.write("您买过如下商品:<br/>");
  18. for(Book book : list) {
  19. out.write(book.getName() + "<br/>");
  20. }
  21.  
  22. }
  23.  
  24. public void doPost(HttpServletRequest request, HttpServletResponse response)
  25. throws ServletException, IOException {
  26.  
  27. doGet(request, response);
  28. }
  29. }

4. 浏览器禁用cookie后的session处理

由上文可知,session通过向浏览器回送cookie,如果用户将浏览器的cookie禁用了该如何解决?
        解决方案:url重写,让session的id不以cookie的形式带过来,以url中带过来。有两个url重写的方法:

  1. response.encodeRedirectURL(java.lang.String url); //用于对sendRedirect方法后的url地址进行重写。
  2. response.encodeURL(java.lang.String url); //用于对表单action和超链接的url地址进行重写。

在BuyServlet.java中,把session的id号写入cookie的几行代码去掉,将

  1. response.sendRedirect("/test/servlet/ListCartServlet");

改为:

  1. response.sendRedirect(response.encodeRedirectURL("/test/servlet/ListCartServlet"));

在IndexServlet.java中,把

  1. out.write(book.getName() + "<a href='/test/servlet/BuyServlet?id="+book.getId()+"'>购买</a><br/>");

改写成:

  1. String url= "/test/servlet/BuyServlet?id=" + book.getId();
  2. url= response.encodeURL(url);
  3. out.write(book.getName() + "<a href='" + url + "'>购买</a><br/>");

还有最后一步很重要:在

  1. out.write("本网站有如下书:<br/>");

之前加上

  1. request.getSession();

因为要实现共享一个session,必须首先获得session。

这样就算浏览器禁用了cookie,我们依然可以共享一个session了。

5. 总结

1. 服务器是如何做到一个session为一个浏览器的多次请求而服务的?
        服务器创建session出来后,会把session的id号以cookie的形式回写给客户机,这样,只要客户机的浏览器不关,再去访问服务器时,都会带着session的id号去,服务器发现客户机带session的id过来了,就会使用内存中与之对应的session为之服务。
        2. 如何做到一个session为多个浏览器服务?
        服务器第一次创建session,程序员把session的id号手动以cookie的形式回送给浏览器,并设置cookie的有效期,这样即使用户的浏览器关了,开新的浏览器时,还会带着session的id号找服务器,服务器从而就可以用内存中与之对应的session为第二个浏览器窗口服务。
        3. 如何做到用户禁用cookie后,session还能为多次请求而服务?
       把用户可能点击的每一个超链接后面,都跟上用户的session id号。
        4. session对象的创建和销毁时机
        用户第一次request.getSession时创建。session对象默认在30分钟没有使用,则服务器会自动销毁session。但是用户可以在web.xml文件中手动配置session的失效时间:  下面表示1分钟失效:

  1. <session-config>
  2. <session-timeout>1</session-timeout>
  3. </session-config>

用户也可以手动调用session.invalidate方法,摧毁session。

session就总结这么多,如有错误之处,欢迎留言指正~

会话管理之session技术的更多相关文章

  1. [ASP.NET][Session] 使用 SQLServer 会话管理解决 Session 丢失问题

    使用 SQLServer 会话管理解决 Session 丢失问题 步骤 1.通过命令行执行 aspnet_regsql.exe 程序(不要双击安装),先在 CMD 中输入命令 cd C:\Window ...

  2. java基础79 会话管理(Cookie技术、Session技术)

    1.概念     会话管理:管理浏览器和服务器之间会话过程中产生的会话数据.    Cookie技术:会话数据保存到浏览器客户端.[存 编号/标记(id)]    Session技术:会话技术会保存到 ...

  3. 会话管理之Cookie技术

    会话管理是web开发中比较重要的环节,这一节主要总结下会话管理中的cookie技术. 1. 何为会话 会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个 ...

  4. JavaWeb基础—会话管理之Session

    一.什么是session session类似于客户端在服务器端的账户.使用Map存放 一个会话锁定一个用户(一般情况下是一个客户端,即一个浏览器独占一个session对象),即使使用浏览器访问其他程序 ...

  5. 测开之路一百三十八:会话管理之session

    session管理和使用,需要用到flask的session模块和设置安全码:app.secret_key 比如列表页和编辑功能只能给admin用 列表页 编辑页 添加session 登录成功时,把u ...

  6. Java中的会话管理——HttpServlet,Cookies,URL Rewriting(译)

    参考谷歌翻译,关键字直接使用英文,原文地址:http://www.journaldev.com/1907/java-session-management-servlet-httpsession-url ...

  7. shiro会话管理

    Shiro提供了完整的企业级会话管理功能,不依赖于底层容器(如web容器tomcat),不管JavaSE还是JavaEE环境都可以使用,提供了会话管理.会话事件监听.会话存储/持久化.容器无关的集群. ...

  8. Java 中的会话管理—— HttpServlet,Cookies,URL Rewriting(转)

    索引 1.什么是 Session? 2.Java 中的会话管理—— Cookie 3.Java Servlet 中的 Session —— HttpSession 理解 JSESSIONID Cook ...

  9. OWASP 关于会话管理 - 译文 [原创]

    英文原文:https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Session_Management_Cheat_Shee ...

随机推荐

  1. PO-BO-VO-DTO-POJO-DAO

    POJO,BO,VO的关系: 简单理解:http://www.blogjava.net/vip01/archive/2007/01/08/92430.html 全面:https://www.cnblo ...

  2. validate插件实现表单效验(一)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. c++和G++的区别

    今天被g++坑死了.. 网上找了一段铭记:引自 http://www.cnblogs.com/dongsheng/archive/2012/10/22/2734670.html 1.输出double类 ...

  4. spring JPA写法一种

    第一次用,搞了半天,终于知道了大概. 基于ORM的JPA还是蛮好用的, 这次是实现一个MANGODB的日志存储和检索. PRISM用的. repository的写法: package paic.sto ...

  5. 牛客网 暑期ACM多校训练营(第二场)D.money-贪心 or 动态规划

    D.money 贪心,直接贴官方的题解吧. 题目大意 你要按照顺序依次经过n个商店,每到达一个商店你可以购买一件商品,也可以出售你手中的商品. 同一时刻你手上最多拿一件商品.在第i个商店购买和出售的代 ...

  6. Python的程序结构[2] -> 类/Class[5] -> 内建类 bytes 和 bytearray

    内建类 bytes 和 bytearray / Built-in Type bytes and bytearray 关于内建类 Python的内建类 bytes 主要有以下几点: class byte ...

  7. cdq分治浅谈

    $cdq$分治浅谈 1.分治思想 分治实际上是一种思想,这种思想就是将一个大问题划分成为一些小问题,并且这些小问题与这个大问题在某中意义上是等价的. 2.普通分治与$cdq$分治的区别 普通分治与$c ...

  8. c++ —— .bat 对拍

    #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #i ...

  9. elasticsearch 分布式部署

    修改配置文件 /config/elasticsearch.yml 我用两台机器,内网地址分别为230 和 231 处理启动报错一: [2017-01-12T15:55:55,433][INFO ][o ...

  10. Ubuntu 16.04下用Wine运行的软件出现方块的解决思路(应该是兼容现在所有平台的Wine碰到这个的问题)

    说明: 1.我使用的是深度的deepin-wine,版本为1.9.0,参考:http://www.cnblogs.com/EasonJim/p/8016674.html 2.这种问题没有一定的解决的方 ...