【Jsp精品源码栏目提醒】:文章导读:在新的一年中,各位网友都进入紧张的学习或是工作阶段。
网学会员整理了Jsp精品源码-【精品】JSP和Servlet中的Cookie - 大学课件的相关内容供大家参考,祝大家在新的一年里工作和学习顺利!
一、
JSP 和 Servlet 中的 Cookie 由于 HTTP 协议是无状态协议(虽然 Socket 连接是有状态的,但每次用 HTTP协议进行数据传输后就关闭的 Socket 连接,因此,HTTP 协议并不会保存上一次的状态),因此,如果要保存某些 HTTP 请求过程中所产生的数据,就必须要有一种类似全局变量的机制保证数据在不同的 HTTP 请求之间共享。
这就是下面要讲的 Session 和 Cookie。
Cookie 是通过将数据保存在客户端的硬盘(永久 Cookie)或内存(临时Cookie)中来实现数据共享的一种机制。
在 Windows 下,保存在这些 Cookie 数据的目录一般是 C:Documents and SettingsAdministratorCookies。
每一个Cookie 有一个超时时间,如果超过了这个时间,Cookie 将自动失效。
可按如下方法来设置 Cookie 的超时时间: Cookie cookie new Cookiekeyvaluecookie.setMaxAge3600 // Cookie 的超时间为 3600 秒,也就是 1 小时 response.addCookiecookie 如果不使用 setMaxAge 方法,Cookie 的超时时间为-1,在这种情况下,Cookie就是临时 Cookie,也就是说这种 Cookie 实际上并不保存在客户端硬盘上,而是保存在客户端内存中的。
读者可以在
JSP 中运行如下代码,看看是否会在上面提到的保存 cookie 的目录中生成 cookie 文件: Cookie cookie new Cookiekeyvalueresponse.addCookiecookie实际上使用 setMaxAge 将超时时间设为任意的负数都会被客户端浏览器认为是临时 Cookie,如下面的代码将在客户端内存中保存一个临时 Cookie:Cookie cookie new Cookiekeyvaluecookie.setMaxAge-100 // 将 cookie 设为临时 Cookie response.addCookiecookie 如果第一次将 Cookie 写入客户端(不管是硬盘还是内存),在同一台机器上第二次访问 该网站的
jsp 页面时,会自动将客户端的 cookie 作为 HTTP 请求头的 Cookie字段值传给服务端,如果有多个 Cookie,中间用隔开。
如下面的 HTTP 请求头所示: GET /test/First.
jsp HTTP/1.1 HOST:localhost ... Cookie:key1value1key2value2 ... ... 我们可以在
JSP 中使用如下的 Java 代码来输出 Cookie 字段的值: out.printlnrequest.getHeaderCookie 如果在 Servlet 中输出,必须得使用如下语句得到 out,才能向客户端浏览器输出数据: PrintWriter out response.getWriter 虽然永久 Cookie 和临时 Cookie 在第二次向服务端发出 HTTP 请求时生成Cookie 字段,但它们还是有一定的区别的。
永久 Cookie 在任意新开启的 IE 窗口都可以生成 Cookie。
而临时 Cookie 由于只保存在当前 IE 窗口,因此,在新开启的 IE 窗口,是不能生成 Cookie 字段的,也就是说,新窗口和旧窗口是不能共享临时 Cookie 的。
使用重定向机制弹出的新窗口也无法和旧窗口共享临时Cookie。
但在同一个窗口可以。
如在一个 IE 窗口输入http://localhost:8080/test/first.
jsp,向内存写入一个临时 Cookie 后,在同一个 IE 窗口输入 http://localhost:8080/test/second.
jsp,浏览器在向服务端发送 HTTP 请求时,自动将当前浏览器的临时 Cookie也就是 first.
jsp 所创建的 Cookie和永久 Cookie 作为 HTTP 请求头的 Cookie 字段值发送给服务端。
但是如果新启一个 IE 窗口,由于新 IE 窗口没有这个临时 Cookie,因此,second.
jsp 只发送了保存在硬盘上的永久 Cookie。
二、Tomcat 中的 Servlet 和 Session 由于 Cookie 数存在保存在客户端,这样对于一些敏感数据会带来一些风险。
而且 Cookie 一般只能保存字符串等简单数据。
并且大小限制在 4KB。
如果要保存比较复杂的数据,Cookie 可能显得有些不合适。
基于这些原因,我们自然会想到在服务端采用这种类似 Cookie 的机制来存储数据。
这就是我们这节要讲的会话Session。
而在一个客户端和服务端的会话中所有的页面可以共享为这个会话所建立的 Session。
那么什么是会话呢?有很多人认为会话就是在一台机器上客户端浏览器访问某个域名所指向的服务端程序,就建立了一个客户端到服务端的会话。
然后关闭客户端浏览器,会话就结束。
其实这并不准确。
首先让我们先来看看 Session 的原理。
Session 和 Cookie 类似。
所不同的是它是建立在服务端的对象。
每一个 Session 对象一个会话。
也许很多读者看到这会有一个疑问。
Session 是如何同客户端联系在一起的呢?很多人在使用Session 时并没有感觉到这一点。
其实这一切都是 Web 服务器,如 Tomcat 一手包办的。
那么 Web 服务器又是如何识别通过 HTTP 协议进行连接的客户端的呢?这就要用到第一节中所讲的 Cookie。
在一般情况下,Session 使用了临时 Cookie来识别某一个 Session 是否属于某一个会话。
在本文中以 Tomcat 为例来说明Session 是如何工作的。
让我们先假设某一个客户端第一次访问一个 Servlet,在这个 Servlet 中使用了 getSession 来得到一个 Session 对象,也就是建立了一个会话,这个Servlet 的代码如下:import java.io.import javax.servlet.ServletExceptionimport javax.servlet.http.public class First extends HttpServletpublic void doGetHttpServletRequest request HttpServletResponseresponsethrows ServletException IOExceptionresponse.setContentTypetext/htmlHttpSession session request.getSessionsession.setAttributekey mySessionValuePrintWriter out response.getWriterout.printlnThe session has been generatedout.flushout.close对于服务端的 First 来说,getSession 方法主要做了两件事: 1. 从客户端的 HTTP 请求头的 Cookie 字段中获得一个寻找一个 JSESSIONID的 key,这个 key 的值是一个唯一字符串,类似于D5A5C79F3C8E8653BC8B4F0860BFDBCD 。
将 在2. 如果 Cookie 中包含这个 JSESSIONID, key 的值取出, Tomcat 的 SessionMap(用于保存 Tomcat 自启动以来的所有创建的 Session)中查找,如果找到,将这个 Session 取出,如果未找到,创建一个 HttpSession 对象,并保存在Session Map 中,以便下一次使用这个 Key 来获得这个 Session。
在服务器向客户端发送响应信息时,如果是新创建的 HttpSession 对象,在响应HTTP头中加了一个 Set-Cookie 字段,并将 JSESSIONID 和相应的值反回给客户端。
如下面的 HTTP 响应头:HTTP/1.1 200 OK...Set-Cookie: JSESSIONIDD5A5C79F3C8E8653BC8B4F0860BFDBCD... 对于客户端浏览器来说,并不认识哪个 Cookie 是用于 Session 的,它只是将相应的临时 Cookie 和永久 Cookie 原封不动地放到请求 HTTP 头的 Cookie 字段中,发送给服务器。
如果在 IE 中首次访问服务端的 First,这时在当前 IE 窗口并没有临时 Cookie,因此,在请求 HTTP 头中就没有 Cookie 字段,所以 First在调用 getSession 方法时就未找到 JSESSIONID,因此,就会新建一个HttpSession 对象。
并在 Set-Cookie 中将这个 JSESSIONID 返回。
接下来我们使用另外一个 Servlet:Second 来获得在 First 中所设置的 Session 数据。
Second的代码如下:import java.io.import javax.servlet.ServletExceptionimport javax.servlet.http.public class Second extends HttpServletpublic void doGetHttpServletRequest request HttpServletResponseresponsethrows ServletException IOExceptionresponse.setContentTypetext/htmlHttpSession session request.getSessionPrintWriter out response.getWriterout.printlnsession.getAttributekeyout.flushout.close 如果在同一个窗口来调用 Second。
这时客户端已经有了一个临时 Cookie,就是 JSESSIONID,因此,会将这个 Cookie 放到 HTTP 头的 Cookie 字段中发送给服务端。
服务端在收到这个 HTTP 请求时就可以从 Cookie 中得到 JSESSIONID 的值,并从 Session Map 中找到这个 Session 对象,也就是 getSession 方法的返回值。
因此,从技术层面上来说,所有拥有同一个 Session ID 的页面都应该属于同一个会话。
如果我们在一个新的 IE 窗口调用 Second,并不会得到 mySessionValue。
因为这时 Second 和 First 拥有了不同的 Session ID,因此,它们并不属于同一个会话。
讲到这,也许很多读者眼前一亮。
既然拥有同一个 Session ID,就可以共享 Session 对象,那么我们可不可以使用永久 Cookie 将这个 Session ID 保存在 Cookie 文件中,这样就算在新的 IE 窗口,也可以共享 Session 对象了。
答案是肯定的。
下面是新的 First 代码:import java.io.import javax.servlet.ServletExceptionimport javax.servlet.http.public class First extends HttpServletpublic void doGetHttpServletRequest request HttpServletResponseresponsethrows ServletException IOExceptionresponse.setContentTypetext/htmlHttpSession session request.getSessionsession.setMaxInactiveInterval3600Cookie cookie new CookieJSESSIONID session.getIdcookie.setMaxAge3600response.addCookiecookiesession.setAttributekey mySessionValuePrintWriter out response.getWriterout.printlnThe session has been generatedout.flushout.close 在上面的代码中使用了 Cookie 对象将 JSESSIONID 写入了 Cookie 文件,并使用 setMaxAge 方法将 Cookie 超时时间设为 3600 秒(1 小时)。
这样只要访问过First,从访问时间算起,在 1 小时之内,在本机的任何 IE 窗口调用 Second 都会得到mySessionValue字符串。
三三、Tomcat 中的
JSP 和 Session 从本质上讲,
JSP 在运行时已经被编译成相应的 Servlet 了,因此,在
JSP和 Servlet 中 Session 的使用方法应该差不多。
但还是有一些细小的差别。
在 如 如果我们使用过
JSP 就会发现,
JSP 中很多对象是不需要创建的, out、session 等。
它们可以直接使用。
如下面的
JSP 代码所示: 在上面的
JSP 代码中直接使用了 out 和 session。
而并不象 Servlet 里一样用 get 方法来获得相应的对象实例。
那么这是为什么呢? 由于
JSP 在第一次运行时是被编译成 Servlet 的, 我们自然就会想到有可能是在编译
JSP 时自动创建了 session 和 out 对象。
下面我们就来验证这一点。
首先需要查看一下
JSP 被编译成 Servlet 后的源代码。
这非常简单,如果我们使用的是 Tomcat,只需要在 Tomcat 的安装目录中的 work 中找相应的源程序即可。
如一个名为 MyJSP.
jsp 的文件首先被编译成 MyJSP_
jsp.java(这就是由
JSP 生成的 Servlet 源程序文件),然后再由 java 将 MyJSP_
jsp.java 编译成MyJSP_
jsp.class,最后 Tomcat 运行的就是 MyJSP_
jsp.class。
如上面的
JSP 程序被编译成 Servlet 的部分源代码如下:package org.apache.jspimport javax.servlet.import javax.servlet.http.import javax.servlet.
jsp.public final class MyJSP_
jsp extendsorg.apache.jasper.runtime.HttpJspBase... ...... ...public void _jspServiceHttpServletRequest requestHttpServletResponse responsethrows java.io.IOException ServletException PageContext pageContext nullHttpSession session nullServletContext application nullServletConfig config nullJspWriter out nullObject page thisJspWriter _jspx_out nullPageContext _jspx_page_context nulltry response.setContentTypetext/html charsetGB18030pageContext _jspxFactory.getPageContextthis request responsenull true 8192 true_jspx_page_context pageContextapplication pageContext.getServletContextconfig pageContext.getServletConfigsession pageContext.getSessionout pageContext.getOut_jspx_out outout.writernout.writernout.writernout.writet rnout.writetrnout.writettout.printlnsession.getIdout.writernout.writernout.writetrnout.write catch Throwable t if t instanceof SkipPageExceptionout _jspx_outif out null out.getBufferSize 0try out.clearBuffer catch java.io.IOException e if _jspx_page_context null_jspx_page_context.handlePageExceptiont finally _jspxFactory.releasePageContext_jspx_page_context 我们可以看到上面的代码中的_jspService 方法类似于 HttpServlet 中的service 方法,在方法的开始部分首先建立了 session、application、out 等对象实例。
然后将 MyJSP.
jsp 中的 HTML 通过 out 输出到客户端。
我们要注意上面的黑体字的语句:out.printlnsession.getId,
JSP 编译器自动将
JSP 中的中包含的 Java 代码原封不动地插入到_jspService 中。
由于是在创建对象实例后插入,因此,就可以直接使用 session、out 等对象了。
如果我们想做进一步的实验,可以直接使用 javac 来编译 MyJSP_
jsp.java,为了方便其间,首先建立一个 c.cmd 文件,它的内容如下:javac -classpathD:toolsapache-tomcat-6.0.13libservlet-api.jarD:toolsapache-tomcat-6.0.13libjsp-api.jarD:toolsapache-tomcat-6.0.13libannotations-api.jarD:toolsapache-tomcat-6.0.13libcatalina.jarD:toolsapache-tomcat-6.0.13libjasper.jarD:toolsapache-tomcat-6.0.13libel-api.jar 1 其中 D:toolsapache-tomcat-6.0.13 是 tomcat 的安装目录,读者可以将其设为自己的机器上的 tomcat 安装目录 在编译时可直接使用 c MyJSP_
jsp.java 进行编译,这时 tomcat 就直接运行我们编译生成的 MyJSP_
jsp.class 了。
从上面的代码我们还可以了解一点,在
JSP 无论使用还是不使用 session,都会使用 getSession 方法创建一个 Session 对象,而 Servlet 必须显式地调用才会建立 Session 对象。
注:通过直接编译 java 文件运行
jsp,需要清除一下 tomcat 的缓存,一般需要重启一下 tomcat。
四、随心所欲使用 Session1 使用 url 传递 session id 在上面讲过,在默认情况下 session 是依靠客户端的 cookie 来实现的。
但如果客户端浏览器不支持 cookie 或将 cookie 功能关闭,那就就意味着无法通过cookie 来实现 session 了。
在这种情况下,我们还可以有另一种选择,就是通过 url 来传递 session id。
对于 Tomcat 来说,需要使用 jsessionid 作为 key 来传递 session id。
但具体如何传呢?可能有很多人认为会是如下的格式:http://localhost:8080/test/MyJSP.jspjsessionidD5A5C79F3C8E8653BC8B4F0860BFDBCD 但实验上面的 url 并不好使。
其实最直接的方法我们可以看一下 Tomcat 的源程序是如何写的,首先下载 tomcat 的源程序,然后找到 CoyoteAdapter.java文件,并打开。
在其中找到 parseSessionId 方法,这个方法是用来从 url 中提取 Session id 的。
我们可以不必了解这个方法的全部代码,只看一下开头就可以。
代码片段如下: ByteChunk uriBC req.requestURI.getByteChunk int semicolon uriBC.indexOfmatch 0 match.length 0 if semicolon 0 ... 上面代码中的 uriBC 就是请求的 url,第二行在这个 url 中查找 match 字符串,再在 CoyoteAdapter.java 中查找一个 match 字符串,match 变量的初值如下: private static final String match Globals. SESSION_PARAMETER_NAME 从上面代码可以看出,match 开头是一个字符,而SESSION_PARAMETER_NAME 是一个常量,值就是jsessionid,因此可以断定,MyJSP.
jsp 后跟的是,并不是,因此,正确的 url 如下:http://localhost:8080/test/MyJSP.jspjsessionidD5A5C79F3C8E8653BC8B4F0860BFDBCD 通过使用上述方法甚至可以在不同的机器上获得同一个 session 对象。
在 CoyoteAdapter.java 文件中还有一个 parseSessionCookiesId 方法,这个方法将从 HTTP 请求头中提取 session id。
我们中 postParseRequest 方法中可以看到将调用的 parseSessionId 方法,在最后调用了 parseSessionCookiesId方法,因此,我们可以断定,tomcat 将考虑 url 中的 session id,然后再读取Cookie 字段中的 session id。
还有就是在 postParseRequest 方法的最后部分有一个 response.sendRedirectredirectPath, 在调完它后,就直接 return 了。
而没有执行到 parseSessionCookiesId,因此,使用重定向并不能通过 HTTP 头的 cookie 字段共享 session。
只能通过 url 来传递 session id。
2 将 tomcat 的 cookie 支持关闭如果我们只想使用 url 来支持 session,可以直接将 tomcat 的 cookie 功能关闭。
我们可以修改 conf 中的 context.xml 文件,加入一个 cookiesfalse即可,内容如下:... ...... ... 重启 tomcat 后,就算客户端支持 cookie,tomcat 也不会考虑 HTT