在上一篇《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. 2080夹角有多大II

    寻人启事:2014级新生看过来! 夹角有多大II Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot ...

  2. iOS 常用开源代码整理

    本文章不定期整理. 1.AFNetworking AFNetworking 采用 NSURLConnection + NSOperation, 主要方便与服务端 API 进行数据交换, 操作简单, 功 ...

  3. java排序方法中的选择排序方法

    每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完. package array; //选择排序方法 public class arra ...

  4. WCF Publisher/Subscriber 订阅-发布模式

    本博后续将陆续整理这些年做的一些预研demo,及一些前沿技术的研究,与大家共研技术,共同进步. 关于发布订阅有很多种实现方式,下面主要介绍WCF中的发布订阅,主要参考书籍<Programming ...

  5. hdu 4063 Aircraft(计算几何+最短路)

    不说了...说多了都是泪...从昨天下午一直wa到现在,直到刚刚才让人帮我找到所谓的“bug”,其实也算不上bug... 这个题的思路就是:找出平面上的所有点:所有圆的交点以及所有圆的圆心.然后依次判 ...

  6. session临时文件存储路径

    今天把本地的项目部署到外网时,遇到个问题,使用session_start()时,提示****目录下的这个文件不存在,网上查了查,说我的根目录不存在,然后在php.ini文件里看了下session.sa ...

  7. Python 绝对简明手册

    Python 绝对简明手册 help(函数名)来获取相关信息 另外,自带的文档和google也是不可少的 2. 基本语法2.1. if / elif / else x=int(raw_input(&q ...

  8. Oracle多实例的配置方法

    SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (SID_NAME = PLSExtProc) (ORACLE_HOME /dbhome_2) (PROGRAM ...

  9. PS 滤镜算法原理 ——马赛克

    % method : 利用邻域的随意一点取代当前邻域全部像素点 %%%% mosaic clc; clear all; addpath('E:\PhotoShop Algortihm\Image Pr ...

  10. NoSQL简要数据库

    前言 NoSQL:not only SQL(不No SQL啊),它的意思是:在关系数据库中使用关系数据库时适用,但在关系数据库中不适合本地使用其它数据库.NoSQL了弥补关系型数据库的不足,能够算是关 ...