上一节我们总结了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的案例中基本一致)

//首页:列出所有书
public class IndexServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter(); out.write("本网站有如下书:<br/>"); Set<Map.Entry<String,Book>> set = DB.getAll().entrySet();
for(Map.Entry<String, Book> me : set) {
Book book = me.getValue();
out.write(book.getName() + "<a href='/test/servlet/BuyServlet?id="+book.getId()+"'>购买</a><br/>"); } } public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response);
} } //写一个类来模拟数据库
class DB { private static Map<String,Book> map = new LinkedHashMap(); //静态代码块中的内容只执行一次,该类在加载时,往map集合中put一系列书,map也需要设置为静态的
static{ map.put("1", new Book("1", "javaweb开发","老张", "一本好书"));
map.put("2", new Book("2", "spring开发","老倪", "一本好书"));
map.put("3", new Book("3", "hibernate开发","老童", "一本好书"));
map.put("4", new Book("4", "struts开发","老毕", "一本好书"));
map.put("5", new Book("5", "ajax开发","老张", "一本好书"));
map.put("6", new Book("6", "java基础","老孙", "一本好书")); } public static Map getAll() {
return map;
}
} class Book { private String id;
private String name;
private String author;
private String description; public Book() {
} public Book(String id, String name, String author, String description) {
super();
this.id = id;
this.name = name;
this.author = author;
this.description = description;
} public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

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

public class BuyServlet extends HttpServlet {  

    public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { String id = request.getParameter("id"); //获得url中带过来的参数id
Book book = (Book)DB.getAll().get(id); //在DB中获得该id号的book HttpSession session = request.getSession(); //获得当前session对象
Cookie cookie = new Cookie("JSESSIONID", session.getId()); //设置新的cookie,注意cookie名必须为JSESSIONID,值为该session的id
cookie.setMaxAge(30*60); //设置cookie有效期
cookie.setPath("/test"); //设置cookie的路径
response.addCookie(cookie); //将cookie添加到cookies中带给浏览器,下次浏览器访问,就会将此cookie带过来了 //先把书加到容器里,再把容器加到session中。一般先检查用户的session中有没有保存书的容器,没有就创建,有就加
List list = (List)session.getAttribute("list");
if(list == null) {
list = new ArrayList();
session.setAttribute("list", list);
}
list.add(book); //跳转到显示用户买过哪些商品
// request.getRequestDispatcher("/servlet/ListCartServlet").forward(request, response);
response.sendRedirect("/test/servlet/ListCartServlet"); } public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response);
}
}

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

public class ListCartServlet extends HttpServlet {  

    public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter(); HttpSession session = request.getSession(); //获得当前的session
List<Book> list = (List)session.getAttribute("list"); //从session中拿出list if(list == null || list.size() == 0) {
out.write("对不起,您还没有购买任何商品!");
return;
} out.write("您买过如下商品:<br/>");
for(Book book : list) {
out.write(book.getName() + "<br/>");
} } public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response);
}
}

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

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

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

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

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

改为:

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

在IndexServlet.java中,把

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

改写成:

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

还有最后一步很重要:在

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

之前加上

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分钟失效:

<session-config>
<session-timeout>1</session-timeout>
</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. POCO库中文编程参考指南(4)Poco::Net::IPAddress

    POCO库中文编程参考指南(4)Poco::Net::IPAddress 作者:柳大·Poechant 博客:Blog.CSDN.net/Poechant 邮箱:zhongchao.ustc#gmai ...

  2. 设计模式-python实现

    设计模式是什么? 设计模式是经过总结.优化的,对我们经常会碰到的一些编程问题的可重用解决方案.一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码.反之,设计模式更为高级,它是一种必须在特定情 ...

  3. cpp调用dll

    c++ 显示调用 其他程序dll #pragma comment(lib, "DllTest.lib") int fnDllTest(void); int c = fnDllTes ...

  4. 想转行做web前端工程师,必学这6大技能

    web前端工程师是近几年才发展出来的新兴职业,也是目前火爆且高薪的职业.大需求的市场环境下,出现了越来越多的人群转行做web前端工程师,如设计师.后台程序员.网虫.大学其他专业.策划.编辑等等. 要学 ...

  5. 如何打造属于自己的Javascript武器库(封装方法)

    前言 代码写的久了,就会发现很多时候都是在写一些重复的东西,这个时候就应该要考虑到提高工作效率了,比如对常用方法的封装,例如日期格式化,浏览器类型判断等. 今天这篇文章我们就来看看如何封装常用的Jav ...

  6. #417 Div2 E (树上阶梯博弈)

    #417 Div2 E 题意 给出一颗苹果树,设定所有叶子节点的深度全是奇数或偶数,并且包括根在内的所有节点上都有若干个苹果. 两人进行游戏,每回合每个人可以做下列两种操作中的一种: 每个人可以吃掉某 ...

  7. Lightoj 1348 Aladdin and the Return Journey (树链剖分)(线段树单点修改区间求和)

    Finally the Great Magical Lamp was in Aladdin's hand. Now he wanted to return home. But he didn't wa ...

  8. RandomeAccessFile - read write

    RandomeAccessFile use write replace writeBytes public class RandomAccessFileTest { public static voi ...

  9. 【hdu1150】【Machine Schedule】二分图最小点覆盖+简单感性证明

    (上不了p站我要死了,侵权度娘背锅) 题目大意 有两台机器A和B以及N个需要运行的任务.每台机器有M种不同的模式,而每个任务都恰好在一台机器上运行.如果它在机器A上运行,则机器A需要设置为模式ai,如 ...

  10. 【背包DP】【OpenJudge4978】宠物小精灵之收服

    宠物小精灵之收服 总时间限制: 1000ms 内存限制: 65536kB [描述] 宠物小精灵是一部讲述小智和他的搭档皮卡丘一起冒险的故事. 一天,小智和皮卡丘来到了小精灵狩猎场,里面有很多珍贵的野生 ...