Download presentation
Presentation is loading. Please wait.
1
张孝祥IT课堂 -深入体验Java Web开发内幕
IT资讯交流网
2
第5讲 HttpServletResponse的应用
准备实验环境 HttpServletResponse简介 产生响应状态 构建响应消息头 响应消息头的实用案例 创建响应正文 请求重定向与请求转发 IT资讯交流网
3
准备实验环境 为支持Servlet 2.4和JSP 2.0 ,使用Tomcat 5.5.12作为运行环境。
在Tomcat 的<tomcat的安装目录>\webapps目录中创建一个名为it315的子目录。 在it315目录中创建一个名为test.html的网页文件,在该文件中写上“<s>中文测试页面</s>”这几个字符。 在<tomcat的安装目录>\webapps\it315目录中创建一个名为WEB-INF的子目录。 在保存Servlet源文件的目录中编写compile.bat编译工具 set PATH=C:\jdk1.5.0_01\bin;%path% set CLASSPATH=C:\tomcat \common\lib\servlet-api.jar;%CLASSPATH% javac -d C:\tomcat \webapps\it315\WEB-INF\classes %1 pause IT资讯交流网
4
HttpServletResponse简介
WEB服务器回送给WEB客户端的HTTP响应消息分为三个部分: 状态行 响应消息头 消息正文(也叫实体内容) Servlet API中定义的ServletResponse接口类用于创建响应消息。 HttpServletResponse是专用于HTTP协议的ServletResponse子接口,它用于封装HTTP响应消息。 HttpServletResponse定义了一系列用于描述各种HTTP状态码的常量。 在service()方法内部调用HttpServletResponse对象的各种方法来创建响应消息。 IT资讯交流网
5
产生响应状态行 HTTP响应消息的响应状态行包括HTTP版本、状态代码和一条相关的提示信息:
HTTP/ OK HttpServletResponse中定义了若干与状态码数值对应的常量,每个常量的名称以前缀SC(Status Code的简写)开头,然后是状态码在HTTP 1.1规范中所表示的状态信息的英文单词的组合,每个单词之间用下划线连接,且所有字母都大写。 状态码404 对应的常量为HttpServletResponse.SC_NOT_FOUND setStatus方法用于设置HTTP响应消息的状态码,并生成响应状态行。 sendError方法用于发送表示错误信息的状态码(一般是404,找不到客户机所请求的资源)到客户端,并清除缓冲区中的内容。 用常量便于记忆,说实在话,英文单词也记不住,但是,用开发工具的提示功能,我们可以挑选出来,这就像指证罪犯时,自己回忆不出罪犯的像貌,但可以从一堆嫌疑人中指出来。 IT资讯交流网
6
构建响应消息头 addHeader与setHeader方法 addIntHeader与setIntHeader方法
addDateHeader与setDateHeader方法 setContentLength方法 setContentType方法 (*) setCharacterEncoding方法 (*) setLocale方法 <locale-encoding-mapping-list> <locale-encoding-mapping> <locale>zh_CN</locale> <encoding>GB2312</encoding> </locale-encoding-mapping> </locale-encoding-mapping-list> containsHeader方法 讲setCharacterEncoding时,说“中国”在内存里是什么码?Unicode!送给浏览器的是什么码?反正不是unicode码,通常是GB2312码,到底是什么码,由Servlet开发人员决定。 有三个方法都能决定输出内容的字符编码,优先级问题。 IT资讯交流网
7
响应消息头的实用案例 Servlet的中文输出问题 让浏览器定时刷新网页 禁止浏览器缓存当前文档内容
使用<meta>标签模拟响应消息头 printWriter用于把unicode字符串转换成某种编码的字节流,jdk1.4中的PrintWriter的设计缺陷,嘿嘿!故意不加charsert=GB2312,显示的结果立马为? setContentType方法有两个作用:一个是把字符以什么码输出,iso里就没有汉字,所以,不能以iso输出汉字;一个告诉浏览器,输出的内容是什么码。 IT资讯交流网
8
Servlet的中文输出问题原理 浏览器接收到的中文字符并不是中文符号本身,而是它的某种字符集编码的数据。
浏览器必须使用正确的字符集编码进行查看,才能将它所接收到的数据显示为正确的中文字符。 当Servlet程序仅仅需要输出纯文本格式的响应正文时,通常应调用ServletResponse对象的getWriter方法返回一个PrintWriter对象,然后使用这个PrintWriter对象将文本内容写入到客户端。 Java程序中的字符文本在内存中是以unicode编码的形式存在的,PrintWriter对象在输出字符文本时,需要先将它们转换成其他某种字符集编码的字节数组后输出。 ServletResponse对象的getWriter方法返回的PrintWriter对象默认使用ISO8859-1字符集编码进行Unicode字符串到字节数组的转换,由于ISO8859-1字符集中根本就没有中文字符,Unicode编码的中文字符将被转换成无效的字符编码后输出给客户端。 IT资讯交流网
9
动手体验:浏览器查看网页文档时怎样选择字符集编码 动手体验:Servlet的中文输出问题及解决之道
ServletResponse接口中定义了setCharacterEncoding、setContentType和setLocale等方法来指定ServletResponse.getWriter方法返回的PrintWriter对象所使用的字符集编码。 调用ServletResponse接口中定义的setContentType方法,在HTTP响应消息的Content-Type头字段中指定响应正文的字符集编码。 动手体验:浏览器查看网页文档时怎样选择字符集编码 动手体验:Servlet的中文输出问题及解决之道 IT资讯交流网
10
脚下留心:注意传递给setContentType方法的参数值的大小写
Servlet的中文输出问题其他发现 脚下留心:注意传递给setContentType方法的参数值的大小写 多学两招 :修改某个Servlet将导致整个WEB应用程序被重新加载 IT资讯交流网
11
动手体验:了解Refresh头字段的作用效果
让浏览器定时刷新网页 HTTP协议中定义了一个Refresh头字段,用于告诉浏览器过多少秒后自动刷新页面。 在Refresh头字段的时间设置值后面还可以用分号(;)分隔后,再指定一个URL地址,这将让浏览器在指定的时间值后自动去访问该URL地址指向的资源。 动手体验:了解Refresh头字段的作用效果 IT资讯交流网
12
动手体验:了解浏览器缓存和禁止缓存的效果
禁止浏览器缓存当前文档内容 response.setDateHeader("Expires",0); response.setHeader("Cache-Control","no-cache"); response.setHeader("Pragma","no-cache"); 动手体验:了解浏览器缓存和禁止缓存的效果 IT资讯交流网
13
使用<meta>标签模拟响应消息头
问题: 利用HTTP消息的响应头字段,可以让浏览器完成各种有用的功能,但是,这需要通过编写WEB服务器端的程序来实现。如果不会服务器端编程的普通HTML页面制作者也想借助HTTP消息的响应头字段来实现一些特殊功能,他们该怎么办呢? 解决方案: HTML语言中专门定义了<meta>标签的http-equiv属性来在HTML文档中模拟HTTP响应消息头,当浏览器读取到HTML文档中具有http-equiv属性的<meta>标签时,它会用与处理WEB服务器发送的响应消息头一样的方式来进行处理。 举例: <meta http-equiv="Expires" content="0"> <meta http-equiv="Cache-Control" content="no-cache"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Refresh" content="0;url= <meta http-equiv="Content-Type" content="text/html; charset=GB2312"> IT资讯交流网
14
使用<meta>标签模拟响应消息头实践
动手体验:使用<meta>标签解决浏览器查看HTML文件时的中文乱码问题 多学两招 :网页文档应尽量采用UTF-8编码 演示Tomcat 版本总是发送字符集编码为“ISO8859-1”的Content-Type头字段的问题。 IT资讯交流网
15
创建响应正文 getOutputStream与getWriter方法 与getWriter方法相关的一些小疑问 输出缓冲区
实现动态文件内容的下载 图像访问计数器 IT资讯交流网
16
getOutputStream与getWriter方法
getOutputStream方法用于返回Servlet引擎创建的字节输出流对象,Servlet程序可以按字节形式输出响应正文。 getWriter方法用于返回Servlet引擎创建的字符输出流对象,Servlet程序可以按字符形式输出响应正文。 getOutputStream和getWriter这两个方法互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。 getOutputStream方法返回的字节输出流对象的类型为ServletOutputStream,它可以直接输出字节数组中的二进制数据。 getWriter方法将Servlet引擎的数据缓冲区包装成PrintWriter类型的字符输出流对象后返回,PrintWriter对象可以直接输出字符文本内容。 Servlet程序向ServletOutputStream或PrintWriter对象中写入的数据将被Servlet引擎获取,Servlet引擎将这些数据当作响应消息的正文,然后再与响应状态行和各响应头组合后输出到客户端。 Serlvet的service方法结束后,Servlet引擎将检查getWriter或getOutputStream方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎将调用close方法关闭该输出流对象。 在实际项目的Servlet中,几乎不用Printwriter对象,原因在于它会把请求转发给专门负责输出内容的JSP。 IT资讯交流网
17
选择getOutputStream 和getWriter方法的要点
PrintWriter对象输出字符文本内容时,它内部还是将字符串转换成了某种字符集编码的字节数组后再进行输出,使用PrintWriter对象的好处就是不用编程人员自己来完成字符串到字节数组的转换。 使用ServletOutputStream对象也能输出内容全为文本字符的网页文档,但是,如果网页文档内容是在Servlet程序内部使用文本字符串动态拼凑和创建出来的,则需要先将字符文本转换成字节数组后输出。 如果一个网页文档内容全部为字符文本,但是这些内容可以直接从一个字节输入流中读取出来,然后再原封不动地输出到客户端,那么就应该使用ServletOutputStream对象直接进行输出,而不要使用PrintWriter对象进行输出。 IT资讯交流网
18
与getWriter方法相关的一些小疑问
在Serlvet程序中可以多次调用HttpServetResponse对象的getWriter方法吗? 每次调用getWriter方法返回的PrintWriter对象的引用变量指向的是同一个PrintWriter对象吗? PrintWriter.println方法与PrintWriter.print方法有什么区别呢? 动手体验:了解与getWriter方法相关的一些问题 IT资讯交流网
19
输出缓冲区 Servlet程序输出的HTTP消息的响应正文首先被写入到Servlet引擎提供的一个输出缓冲区中,直到输出缓冲区被填满或者Servlet程序已经写入了所有的响应内容,缓冲区中的内容才会被Servlet引擎发送到客户端。 使用输出缓冲区后,Servlet引擎就可以将响应状态行、各响应头和响应正文严格按照HTTP消息的位置顺序进行调整后再输出到客户端。 如果在提交响应到客户端时,输出缓冲区中已经装入了所有的响应内容,Servlet引擎将计算响应正文部分的大小并自动设置Content-Length头字段。 如果在提交响应到客户端时,输出缓冲区中装入的内容只是全部响应内容的一部分, Servlet引擎将使用HTTP 1.1的chunked编码方式(通过设置Transfer-Encoding头字段来指定)传输响应内容。 IT资讯交流网
20
动手体验:了解Servlet引擎处理输出缓冲区的细节
输出缓冲区有关方法 setBufferSize方法 getBufferSize方法 flushBuffer方法 reset方法 isCommitted方法 for(int i=0; i<len/*-1*/; i++) { out.print("w"); } Servlet执行完for语句后,缓冲区满,但容器不敢肯定Servlet是否还有内容输出,所以,容器将缓冲区的内容输出给浏览器时,无法确定整个实体内容的长度,只知道当前要输出的这块内容的大小,所以它用chuncked传输方式。 动手体验:了解Servlet引擎处理输出缓冲区的细节 IT资讯交流网
21
什么是动态文件内容的下载 只要让超链接的URL地址指向一个exe或zip等类型的文件,用户单击这个超链接就可以将该资源文件下载到客户端。
如果要下载的文件并不真正存在于WEB服务器的文件系统中,而是需要用一个Servlet程序临时在服务器内存中动态产生后再传送到客户端,那该如何实现呢? 我给你的sina帐户发一封邮件,其中有两个附件,收到的邮件存储在sina的服务器上,请问:sina邮件服务器为这封邮件保存了几个文件?实际上是一个,马上演示这种效果。 IT资讯交流网
22
动手体验:实现动态文件内容的下载 如何实现动态文件内容的下载
需要通过HttpServletResponse.setContentType方法设置Content-Type头字段的值为浏览器无法使用某种方式或激活某个程序来处理的MIME类型,例如,“application/octet-stream”或“application/x-msdownload”等。 需要通过HttpServletResponse.setHeader方法设置Content-Disposition头的值为“attachment; filename =文件名”。 应该调用HttpServletResponse.getOutputStream方法返回的ServletOutputStream对象来向客户端写入附件文件内容,而不应使用HttpServletResponse.getWriter方法返回的PrintWriter对象。 下载文件的名称为中文时,会出现乱码,要将文件名进行utf-8编码再进行URL编码。 在rfc2183中搜索encode,要求查rfc2184 查看urlencoder的帮助,建议用UTF-8编码,和一个连接到w3c的超连接,该超连接指向内容如下: B.2 Special characters in URI attribute values B.2.1 Non-ASCII characters in URI attribute values Although URIs do not contain non-ASCII values (see [URI], section 2.1) authors sometimes specify them in attribute values expecting URIs (i.e., defined with %URI; in the DTD). For instance, the following href value is illegal: <A href=" We recommend that user agents adopt the following convention for handling non-ASCII characters in such cases: Represent each character in UTF-8 (see [RFC2279]) as one or more bytes. Escape these bytes with the URI escaping mechanism (i.e., by converting each byte to %HH, where HH is the hexadecimal notation of the byte value). This procedure results in a syntactically legal URI (as defined in [RFC1738], section 2.2 or [RFC2141], section 2) that is independent of the character encoding to which the HTML document carrying the URI may have been transcoded. Note. Some older user agents trivially process URIs in HTML using the bytes of the character encoding in which the document was received. Some older HTML documents rely on this practice and break when transcoded. User agents that want to handle these older documents should, on receiving a URI containing characters outside the legal set, first use the conversion based on UTF-8. Only if the resulting URI does not resolve should they try constructing a URI based on the bytes of the character encoding in which the document was received. Note. The same conversion based on UTF-8 should be applied to values of the name attribute for the A element. MIME邮件中的附件名的中文,会出乱码吗?用outlook做个实验,结果是这样的: Content-Disposition: attachment; filename="=?gb2312?B?0MK9qCDOxLG+zsS1tS50eHQ=?=" 动手体验:实现动态文件内容的下载 IT资讯交流网
23
图像访问计数器介绍 网页每次被访问时,页面的访问次数都要发生改变,所以这个功能必须通过服务器端的程序来实现。
一些WEB站点只能输出静态页面内容,没有开放运行服务器端程序的功能,无法直接在这些只支持静态内容的WEB站点上编写服务器端程序来实现页面访问次数的统计和显示功能。 一些具有执行服务器端程序功能的WEB站点推出了免费的页面访问计数器,只要在位于任何站点的一个静态HTML页面中增加一条该站点提供的HTML语句,该语句就能显示出该静态页面的访问次数。 一个站点要想能统计另外一个站点上的某个HTML页面的访问次数,必须让任何一个浏览器在每次访问那个HTML页面都通知这个一下站点,这可以通过在静态HTML页面中增加两种特殊的标签来实现:<img>标签和设置src属性的<script>标签。 IT资讯交流网
24
<img>标签的三个重要特性
一个包含有图像的网页文件中并没有包含真正的图像数据内容,而只是使用<img>标签指明了图像的URL地址。 举例:本网页已被浏览了<img src= "count.gif ">次 <img>标签的src属性也可以指向当前页面所在WEB服务器之外的其他WEB服务器上的图像文件。 浏览器并不关心<img>标签所需的图像数据在服务器端是如何产生,它只知道去访问src属性指定的URL资源,并把服务器返回的数据当作一个图像的内容来显示。服务器返回的图像数据可以直接从一个静态图像文件中读取,也可以通过Servlet程序在内存中动态创建。 IT资讯交流网
25
免费页面访问计数器的实现原理 xxxxxxx xxxxx 客户端浏览器 ①访问http://A/count.html获得页面内容
WEB站点A xxxxxxx <img src= " xxxxx ②显示count.html页面 WEB站点B 大家首先要知道一个网站的页面能够引用另一个网站的图像! xxxxxxx xxxxx ③访问 IT资讯交流网
26
页面访问计数器的技术实现细节 Servlet程序输出的图像格式为jpeg,它应告诉浏览器其所输出的实体内容的MIME类型为image/jpeg。 因为图像是二进制数据,所以应该调用HttpServletResponse.getOutputStream方法返回的ServletOutputStream对象来向客户端写入图像数据。 java.awt.image.BufferedImage类用于在内存中创建一幅图像,具体的图像内容则可以通过调用其图形上下文对象(java.awt.Graphics)的各种绘图方法生成。 在内存图像中绘制访问次数时,必须限定显示的位数,如果访问次数超过七位,则用数字 显示,如果访问次数不足七位,则在前面补充相应个数的0。 每个引用该Servlet程序的静态页面的URL都对应一个各自的访问次数,每个URL及其访问次数需要使用数据库系统来进行存储,对于简单的实验,也可以采用一个属性文件来进行存储。当前引用页面的URL可以通过Referer请求头获取。 JDK中提供了一个javax.imageio.ImageIO类,它的write方法可以将BufferedImage对象中的图像编码成jpeg格式的图像数据后写入到一个OutputStream流对象中。 IT资讯交流网
27
动手体验:使用<img>标签实现静态HTML页面的访问次数统计和显示
页面访问计数器实践 使用下面的例子来讲解在程序中使用匿名输入输出流所带来的隐患! import java.io.*; public class Test2 { public static void main(String [] args) throws Exception for(;;) new FileInputStream("d:\\1.txt").close(); } 动手体验:使用<img>标签实现静态HTML页面的访问次数统计和显示 IT资讯交流网
28
图像访问计数器更多思考 如果要自行设置Content-Length头字段,该如何处理?
在实际应用中,往往采用为每个页面分配一个id号的方式来区分和跟踪每个静态HTML页面,请编写一个具体应用案例。 <img src= 借鉴其中的动态图像生成技术,可以根据数据库系统中的数据动态产生出的各类数据分析图(直方图、饼状图、折线图等),甚至是股票走势图。 使用设置src属性的<script>标签也可以实现统计和显示页面访问次数的功能,请编写一个具体应用案例。 借鉴网页访问计数器的设计思想统, IT资讯交流网
29
多学两招:如何动态产生大小可变的图像 涉及到的类: AffineTransformOp类的filter方法用于完成具体的转换操作:
java.awt.image.BufferedImage java.awt.image.ImageIO java.awt.geom.AffineTransform java.awt.image.AffineTransformOp AffineTransformOp类的filter方法用于完成具体的转换操作: public final BufferedImage filter(BufferedImage src,BufferedImage dst) 如果要对一个图像文件进行转换,可以先调用ImageIO.read方法从该文件输入流中读取图像数据并生成一个BufferedImage对象,然后调用AffineTransformOp.filter方法进行转换,最后再调用ImageIO.write方法将转换得到的BufferedImage对象写入到一个文件输出流中。 一个AffineTransform对象定义了一种具体的转换方式,在创建AffineTransformOp对象时,需要为其传递一个AffineTransform对象: public AffineTransformOp(AffineTransform xform,int interpolationType) 如果仅仅是需要改变图像的大小,可以调用AffineTransform.getScaleInstance这个静态方法来创建: public static AffineTransform getScaleInstance(double sx, double sy) IT资讯交流网
30
请求重定向与请求转发 RequestDispatcher接口 用include方法实现资源包含 用forward方法实现请求转发
请求转发的运行流程 用sendRedirect方法实现请求重定向 请求重定向的运行流程 请求重定向与请求转发的比较 缺省Servlet的缓存问题 IT资讯交流网
31
RequestDispatcher接口 RequestDispatcher实例对象是由Servlet引擎创建的,它用于包装一个要被其他资源调用的资源(例如,Servlet、HTML文件、JSP文件等),并可以通过其中的方法将客户端的请求转发给所包装的资源。 RequestDispatcher接口中定义了两个方法:forward方法和include方法。 forward和include方法接收的两个参数必须是传递给当前Servlet的service方法的那两个ServletRequest和ServletResponse对象,或者是对它们进行了包装的ServletRequestWrapper 或ServletResponseWrapper对象。 获取RequestDispatcher对象的方法: ServletContext.getRequestDispatcher (参数只能是以“/”开头的路径) ServletContext.getNamedDispatcher ServletRequest.getRequestDispatcher (参数可以是不以“/”开头的路径) 如果想跳转或引入一个资源,应将该资源包装成RequestDispatcher对象。怎样获得RequestDispatcher对象呢? IT资讯交流网
32
动手体验:了解RequestDispatcher.include方法的应用细节
RequestDispatcher.include方法用于将RequestDispatcher对象封装的资源内容作为当前响应内容的一部分包含进来,从而实现可编程的服务器端包含功能。 被包含的Servlet程序不能改变响应消息的状态码和响应头,如果它里面存在这样的语句,这些语句的执行结果将被忽略。 在调用RequestDispatcher.include方法时,Servlet容器不会去调整HttpServletRequest对象中的信息,HttpServletRequest对象仍然保持其初始的URL路径和参数信息。 动手体验:了解RequestDispatcher.include方法的应用细节 IT资讯交流网
33
缺省Servlet如何创建响应正文 IT资讯交流网 WWW.IT315.ORG
ServletOutputStream ostream = null; PrintWriter writer = null; …… try { /* 如果抛出了异常,说明前面已经调用过getWriter方法, 则在异常处理代码中再次调用getWriter方法对writer变量进行赋值。 */ ostream = response.getOutputStream(); } catch (IllegalStateException e) /*只有那些文本内容才可以用 PrintWriter对象进行转换输出*/ if ( (contentType == null) || (contentType.startsWith("text")) ) writer = response.getWriter(); else throw e; …… //如果已经对writer变量赋值,则执行else从句 if (ostream != null) { //将资源中的内容按字节流原封不动地输出到客户端 copy(cacheEntry, renderResult, ostream); } else /*将资源中的内容转换成字符文本后 再由PrintWriter对象转换输出*/ copy(cacheEntry, renderResult, writer); IT资讯交流网
34
用forward方法实现请求转发 forward方法用于将请求转发到RequestDispatcher对象封装的资源,Servlet程序在调用这个方法进行转发之前可以对请求进行一些前期的预处理。 如果在调用forward方法之前,在Servlet程序中写入的部分内容已经被真正地传送到了客户端,forward方法将抛出IllegalStateException异常。 调用RequestDispatcher.forward方法时,Servlet容器将根据目标资源路径对当前HttpServletRequest对象中的请求路径和参数信息进行调整。 如果在调用forward方法之前向Servlet引擎的缓冲区中写入了内容,只要写入到缓冲区中的内容还没有被真正输出到客户端,forward方法就可以被正常执行,原来写入到输出缓冲区中的内容将被清空,但是,已写入到HttpServletResponse对象中的响应头字段信息保持有效。 如果调用者与被调用者的访问URL不属于同一个目录,当被调用者输出的内容中包含有使用相对URL的访问路径时,原来相对被调用者的URL将变成相对于调用者的URL。 相对路径的问题:第二个人输出的内容是说找他哥哥,可以浏览器记住访问的是第一个人,浏览器自然认为要找第一个人的哥哥。 在讲forward时,要强调将forward的资源放在WEB-INF/JSP之类的目录中,以便外界无法直接访问这个JSP页面,例如,struts中的JSP页面就尽量要这么放。 IT资讯交流网
35
动手体验:了解RequestDispatcher.forward方法的应用细节
IT资讯交流网
36
请求转发的过程示意图 IT资讯交流网
37
用sendRedirect方法实现请求重定向
sendRedirect方法用于生成302响应码和Location响应头,从而通知客户端去重新访问Location响应头中指定的URL,其完整的定义语法如下: public void sendRedirect(java.lang.String location) throws java.io.IOException 使用下面两条语句也能完成response.sendRedirect(url)语句所完成的功能: response.setStatus(response.SC_MOVED_TEMPORARILY ); response.setHeader ("Location", url); sendRedirect 方法不仅可以重定向到当前应用程序中的其他资源,它还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。 如果传递给sendRedirect 方法的相对URL以“/”开头,则是相对于整个WEB站点的根目录,而不是相对于当前WEB应用程序的根目录。 IT资讯交流网
38
动手体验:了解sendRedirect方法的应用
IT资讯交流网
39
请求重定向的过程示意图 IT资讯交流网
40
请求重定向与请求转发的比较 RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect 方法还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。 如果传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头,它是相对于整个WEB站点的根目录;如果创建RequestDispatcher对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录。 调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。 HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求;RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。 RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程。 无论是RequestDispatcher.forward方法,还是HttpServletResponse.sendRedirect方法,在调用它们之前,都不能有内容已经被实际输出到了客户端。如果缓冲区中已经有了一些内容,这些内容将被从缓冲区中清除。 IT资讯交流网
41
缺省Servlet的缓存问题 场景: 问题:
在实际项目中,有些HTML文件是在程序运行时调用一个模版文档来动态生成的,例如,一些站点的统计报表就是在用户访问某个Servlet时,由这个Servlet临时调用报表生成模块(例如,ireport)生成一个HTML文件,然后再将请求转发这个HTML文件。 问题: 如果A部门的一个员工查看了A部门的统计信息后的一个较短时间范围内,B部门的员工来查看B部门的统计信息,结果后者看到的是A部门的统计信息。 Html网页不是用dreamweaver做成的! 你访问我,我调用报表工具生成html文件,然后把请求转发给这个生成的HTML文件。 IT资讯交流网
42
缺省Servlet缓存问题的模拟程序(1)
public class ReportServlet extends HttpServlet { private int count = 0; public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException response.setContentType("text/html;charset=UTF-8"); //禁止浏览器缓存 response.setDateHeader("Expires",0); response.setHeader("Cache-Control","no-cache"); response.setHeader("Pragma","no-cache"); String department = request.getParameter("dept"); synchronized(this) System.out.println(++count + ":" + department); String path = getServletContext().getRealPath("/WEB-INF/report.html"); ReportTool rt = new ReportTool(); rt.setCount(count); rt.setDepartment(department); rt.createReportHTML(path); RequestDispatcher rd = getServletContext().getRequestDispatcher( "/WEB-INF/report.html"); rd.forward(request,response); } IT资讯交流网
43
缺省Servlet缓存问题的模拟程序(2)
public class ReportTool { private int count = 0; private String department = ""; public void setCount(int count) this.count = count; } public void setDepartment(String department) this.department = department; public void createReportHTML(String path) throws IOException FileOutputStream fos = new FileOutputStream(path); OutputStreamWriter ops = new OutputStreamWriter(fos,"UTF-8"); ops.write(String.valueOf(count) + ":" + department + "的统计信息"); ops.close(); IT资讯交流网
44
动手体验:了解缺省Servlet的缓存问题
文件清单:ReportTest.html <a href="servlet/ReportServlet?dept=DEPT_A">查看部门A的统计信息</a> <a href="servlet/ReportServlet?dept=DEPT_B">查看部门B的统计信息</a> 动手体验:了解缺省Servlet的缓存问题 IT资讯交流网
45
缺省Servlet缓存问题解决方案 为每一种统计方案都生成一个名称不同的HTML报表文件,例如,不同部门使用不同名称的报表文件。如果统计方案比较多,生成的HTML报表文件的个数也就会很多,所以,这个方案比较适合只有少数几种固定的统计方案的情况,特别不适合要根据各种组合条件来生成报表的情况。 修改Tomcat的缺省Servlet程序,让它不要进行缓存,这种方案可能会严重影响系统的性能,一般不要采用。 在ReportServlet程序中生成HTML报表文件后,按字节流的形式读取该文件中的内容,然后以字节流的形式直接输出到客户端。这种方案可以生成实时的统计报表,也适合根据各种组合条件来生成报表的情况,所以,推荐采用这种方案。 IT资讯交流网
46
思考与实践(1) 1.描述ServletResponse.setContentType方法的作用,然后参照本书编写实验步骤的方法设计一个详细的实验步骤来解释其作用,请将完成的结果提交给 2.一些网站可能需要这样的功能:列出某个目录下的所有文件和子目录列表,每个文件和子目录都作为一个超链接的文本;如果用户单击指向某个文件的超链接,不管文件类型怎样,都对文件进行下载,而不是直接打开这个文件;如果用户单击指向某个子目录的超链接,则列出该目录下的所有文件和子目录列表。要实现这样的功能,不能让超链接直接指向要下载文件的URL,而是应参照配套书籍5.6.4节的例子程序编写一个Servlet程序,让Servlet程序读取要下载的文件内容,然后再传递给浏览器。请编写一个完成这种功能的程序,然后提交给 提示:首先让Servlet程序显示出某个目录下的所有文件和子目录列表,列表中的所有文件和子目录的超链接又都指向该Servlet程序,要下载文件名或要打开的目录名作为超链接附带的一个参数传递给Servlet程序,关于如何向Servlet程序传递参数以及Servlet程序如何获取参数,请参看配套书籍6.6节的讲解。 IT资讯交流网
47
思考与实践(2) 3.参照5.6.2节讲解的图像访问计数器的例子程序,编写一个使用<script>标签来统计和显示页面访问次数的程序,请将程序提交给 4.在使用RequestDispatcher.include方法时,如果被调用者输出的内容中包含有使用相对URL的访问路径,当调用者与被调用者的访问URL不属于同一个目录时,这个相对URL是相对于调用者的URL,还是相对于被调用者的URL呢?在不允许使用绝对路径的情况下,该如何解决这个问题?请编写一个实验程序和详细的操作步骤,然后提交给 5.有人为了禁止浏览器缓存某个普通的HTML页面,他采用的方式是让浏览器不要直接访问这个HTML页面,而是访问一个前端Servlet,在这个前端Servlet中增加那些禁止浏览器缓存的语句后,再跳转到普通HTML页面。请问,跳转到普通HTML页面时应该采用哪种方式? HttpServletResponse.sendRedirect RequestDispatcher.forward A和B都可以 IT资讯交流网
48
思考与实践(3) 6.请编写一个Servlet程序,并在部署描述符文件(web.xml)中采用通配符(*)的形式将多个URL映射到该Servlet上。如果在这个Servlet程序中使用RequestDispatcher.forward方法跳转到某个URL,而跳转到的URL也匹配该Servlet所映射的URL(即仍由这个Servlet处理),这将会出现怎样的运行效果?请编写一个实验程序和详细的操作步骤,然后提交给 IT资讯交流网
49
结束语 欢迎大家参与多媒体IT课堂其他课程 欢迎加入IT315把宝贵经验分享给大家 相聚的地方,就在……
IT资讯交流网
Similar presentations