在上一篇《Servlet的学习之Session(2)》我们知道了Session能实现一个会话过程中保存数据或者多个会话中实现同一个Session的关键因素就是Cookie,只是Cookie是否临时的还是保存硬盘中一段时间而已。

  但不是所有的用户的浏览器都会保持着接收Cookie,当有些用户的浏览器禁用Cookie或者第三方安全工具阻止了Cookie之后,那么Session就再也无法保存数据了。

  我们通过IE浏览器的【工具】--->【Internet选项】--->【隐私】--->【高级】,勾选“替代自动cookie处理”,将“第一方Cookie”和“第三方Cookie”都选择为“阻止”。这样就阻止了Cookie。如果我们再去访问会创建的Session的Servlet,那么就会看到如下提示:  

  

  当浏览器禁用Cookie之后,即使是在一个浏览器的一个会话过程中,Session都不起任何作用,因为这时候浏览器连要缓存在IE浏览器中Cookie都不接收。所以每次调用request.getSession()方法都是创建新的Session。其实,getSession()这个方法首先是Session查询从浏览器是否能发来包含JSESSIONID的cookie;如果没有这个cookie,那么浏览器会查询请求URL,这个请看下一段。如果两种方式都没有能找到以前的Session,那么getSession()最终会创建新的Session。

  如果我们想在浏览器禁用Cookie之后能继续使用同一个Session,那么Cookie不能用,我们就要从Session使用Cookie的原理来解决。Session使用Cookie的原理在于能保存JSESSIONID,而我们如果在点击的超链接的URL中加入JSESSIONID的值,那么调用request.getSession()方法的Servlet就可以直接从该URL获取JSESSIONID,再去配对服务器端相同JSESSIONID的值的Session,这样就可以再次获取服务器端Session中保存的数据。这个在超链接中加入JSESSIONID的方法叫做URL重写。URL重写,用来解决客户端浏览器禁用Cookie之后Session的共享问题。

URL重写主要有两个方法:

  Response.encodeURL()方法

  Response.encodeRedirectURL()方法

请认真阅读这两个方法的API文档:

  

  

  如果是在一个页面中的可以点击的超链接要使用encodeURL()方法,而在一个Servlet中如果有要重定向的路径必须使用encodeRedirectURL()方法,而不能使用encodeURL()方法。无论哪种方法,经过URL重写之后都会在URL路径的最后增加JSESSIONID和值。

  我们再将前篇《Servlet的学习之Session(1)》中最后的购物车例子进行改写,使得当用户浏览器禁用cookie之后依然能完成功能。

  当我们禁用cookie之后,再使用这个例子,那么浏览器会抛出空指针异常,原因在于最后购物车Servlet获取我们存放物品的LinkedList上,因为禁用了cookie,使得我们无法获得上一次的Session,因此每次使用getSession()方法都要获取新的Session,而新的Session中并不会有我们设置的“productCart”这个属性,因此每次获得的LinkedList其实都不存在:

     LinkedList<Book> link = (LinkedList<Book>) session.getAttribute("productCart");

     writer.write("您所希望购买的商品如下:<br>");
for(ListIterator<Book> literator = link.listIterator();literator.hasNext();){
Book b = literator.next();
writer.write(b.getName()+"<br>");
}

那么我们就需要在购物车Servlet的前一个Servlet,也就是进行重定向到购物车Servlet的那个Servlet中,将重定向的URL地址进行重写:

     String reUrl = response.encodeRedirectURL("/SessionProject/servlet/SessionDemo3");
response.sendRedirect(reUrl);

只要简单使用encodeRedirectURL或者encodeURL方法就能将地址增加JSESSIONID:

  

记住,鉴于用户浏览器会禁用cookie,因此我们需要在整个web工程中对于会使用到getSession()方法的超链接、重定向或者转发等等的URL地址都要进行URL重写。

  同时!!在所有Servlet的中,最开始的Servlet,也可以称为首页Servlet的代码的最开始加入request.getSession(); 这样一句“废话”,这是因为将URL重写的前提是必须要有Session,或者说已经建立了Session。

  这里将《Servlet的学习之Session(1)》使用URL改写后的例子重新贴出代码,这里略去商品的bean类和使用Map作为数据库的代码,请到《Servlet的学习之Session(1)》博客查阅:

在首页展示商品的Servlet:

     response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter(); request.getSession(); Map<String,Book> map = BookDatabaseFactory.getMap();
for(Map.Entry<String, Book> en : map.entrySet()){ String reUrl = response.encodeURL("/SessionProject/servlet/SessionDemo2?id="+en.getKey());
writer.write(en.getValue().getName() +
"<a href='"+reUrl+"' target='_blank'>购买</a> <br>");
}

处理购买商品的Servlet:

     String bookId = request.getParameter("id");
Map<String,Book> map = BookDatabaseFactory.getMap();
Book book = map.get(bookId); HttpSession session = request.getSession();
LinkedList<Book> link = (LinkedList<Book>) session.getAttribute("productCart"); //禁用cookie之后这里会空指针异常
if(link == null) {
link = new LinkedList<Book>();
session.setAttribute("productCart", link);
}
link.add(book);
//将所点击的商品交给购物车页面显示
String reUrl = response.encodeRedirectURL("/SessionProject/servlet/SessionDemo3");
response.sendRedirect(reUrl);

显示购物车的Servlet:

     response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter(); HttpSession session = request.getSession();
LinkedList<Book> link = (LinkedList<Book>) session.getAttribute("productCart"); //禁用cookie之后这里会空指针异常 writer.write("您所希望购买的商品如下:<br>");
for(ListIterator<Book> literator = link.listIterator();literator.hasNext();){
Book b = literator.next();
writer.write(b.getName()+"<br>");
}
/* 当用户禁用cookie之后再使用覆盖cookie就不能用了
* //当浏览器关闭后重新打开依然有之前想要购买的物品
Cookie cookie = new Cookie("JSESSIONID", session.getId());
cookie.setMaxAge(60*60);
cookie.setPath("/SessionProject");
response.addCookie(cookie);*/

  通过以上两个地方的URL重写(已用红色字体标出),我们就能在用户禁用cookie之后继续能获得之前保存数据的Session,从而对该Session中的数据继续进行操作。我们甚至可以从首页查看源文件看到所有的超链接中可以看到都加入了JSESSIONID:

  

但是,这个方法只能在一个会话过程中有效。也就是说当用户将浏览器关闭之后,重新打开,之前的数据就不复存在了,因为这种方法无法在新的会话中获取之前的Session。因此不能像《Servlet的学习之Session(2)》中使用cookie方法一样无论多少个会话都能获取之前相同的Session。

补充:上面的例子我们以用户禁用cookie为前提,因此在首页显示商品的页面上所有的超链接我们都进行URL重写,这点我们从页面查看源文件也能看出。如果我们上面的例子在用户没有禁用cookie的时候,第一次访问时,我们查看源文件,所有的超链接依然还是有URL重写后将所有的超链接都附上JSESSIONID;但是我们再次刷新时,这些JSESSIONID都会消失:

  

  这是因为服务器很“聪明”,只要你没有禁用cookie,它就不需要进行URL重写,准确的说是进行了URL重写,但是因为没有禁用cookie,因此重写后的URL还是跟原来一样,这点在最开始的encodeRedirectURL和encodeURL的API截图中也可以看出。

Servlet的学习之Session(3)的更多相关文章

  1. Servlet的学习之Session(2)

    在上一篇中我们学习了Session对象默认在一个会话过程中,由服务器创建,能保存在这个会话过程中用户访问多个web资源时产生的需要保存的数据,并在访问服务器中其他web资源时可以将这些数据从Sessi ...

  2. Servlet的学习之Session(1)

    在学习完了Servlet中的Cookie技术后,我们再来学习另一个能保存会话数据的技术——Session. Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其 ...

  3. Servlet的学习之Session(4)

    在本篇中,我们来使用Session完成一个用户登录的案例,前提声明:这个案例主要用于学习Session技术,是属于比较简单的类型,以后会采用MVC模式来开发登录,那就会比较复杂. 现在大多数网站都提供 ...

  4. Servlet的学习之Session(5)

    在上一篇中我们介绍了如果使用Session来做一个简单的用户登录案例,在本篇中我们继续使用Session技术来做一个防止表单重复提交的案例. 这是一个很重要的知识点,在很多框架中都有防止表单重复提交的 ...

  5. JavaWeb之Servlet:Cookie 和 Session

    会话 现实生活中我们会用手机跟对方对话,拿起手机,拨号,然后对面接听,跟着互相通话,最后会话结束. 这个过程也可以用我们的B/S模式来描述: 打开浏览器—>输入地址->发出请求->服 ...

  6. Servlet的学习之Cookie

    从本篇开始学习Servlet技术中的Cookie专题. 首先来了解什么是“会话”.会话是web技术中的一个术语,可以简单的理解为:用户打开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭 ...

  7. Servlet的学习之Filter过滤器技术(1)

    本篇将讲诉Servlet中一项非常重要的技术,Filter过滤器技术.通过过滤器,可以对来自客户端的请求进行拦截,进行预处理或者对最终响应给客户端的数据进行处理后再输出. 要想使用Filter过滤器, ...

  8. Servlet的学习(四)

    在本篇的Servlet的学习中,主要来学习由使用MyEclipse来开发Servlet的一些小细节. 细节一:在web.xml中可以对同一个Servlet配置多个对外访问路径,并如果在web.xml中 ...

  9. Servlet的学习之Request请求对象(3)

    本篇接上一篇,将Servlet中的HttpServletRequest对象获取RequestDispatcher对象后能进行的[转发]forward功能和[包含]include功能介绍完. 首先来看R ...

随机推荐

  1. (Problem 21)Amicable numbers

    Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into ...

  2. 关于QuartusII对ram块的综合

    之前在看Altera的官方教程上就有说明,如果我们定义一个reg [`word_w]user_ram[`word_d]  ; QuartusII会自动综合成为一个ram—— 当然有一些前提:(后续补充 ...

  3. JQuery中两个ul标签的li互相移动实现方法

    这篇文章主要介绍了JQuery中两个ul标签的li互相移动实现方法,可实现ul标签中li标签内容相互替换的技巧,涉及jQuery操作页面元素的相关技巧,需要的朋友可以参考下 本文实例讲述了JQuery ...

  4. UIScrollView方法 属性详解

    --前言:UIScrollView使用非常广,本文研究UIScrollView各属性和方法,明白它们的意义.作用.在后面的一篇文章有整理UIScrollView一些常见用法以及一些效果的实现思路. - ...

  5. 在 Windows 下远程桌面连接 Linux - VNC 篇

    VNC是由AT&T试验室开发,是一款优秀的远程控制工具软件,后来以GPL授权的形式开源.经过几年的发展,现在的VNC已经不单指某个软件,而是一类软件的通称.下面介绍Linux下常用的两个VNC ...

  6. 更新整理本人全部博文中提供的代码与工具(Java,2014.09)

    为了更方便地管理博文中涉及的各种代码与工具资源,如今把这些资源迁移到 GitHub 中,有兴趣者可前往下载. Java 1.<高效 Java Web 应用开发框架 JessMA v3.4.1 正 ...

  7. MySQL分组数据

    分组 理解分组能够看例如以下一个样例,首先我们打印出products表例如以下 从上面的表中能够看出.每一个vendor都有若干个产品,那么怎么一次统计每一个vendor有多少个产品呢? 这里就能够使 ...

  8. android4.4组件分析--service组件

    6       Service 6.1            service介绍 6.1.1.            基本介绍 Service是Android四大组件之中的一个(其余的是activit ...

  9. Vim 使用设置

    转自:http://www.cnblogs.com/end/archive/2012/06/01/2531147.html Vim 作为最好用的文本编辑器之一,使用vim来编文档,写代码实在是很惬意的 ...

  10. ArrayList集合-[习题]--C#

    :向集合中添加10个元素,计算平均值,求最大.最小值. ; list.AddRange(, , , , , , , , }); int Max, Min; Max = Min = (]; ; i &l ...