创建响应正文:
•getOutputStream与getWriter方法
•与getWriter方法相关的一些小疑问
•输出缓冲区
•实现动态文件内容的下载
•图像访问计数器
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
方法关闭该输出流对象。
选择getOutputStream和getWriter方法的要点:
•
PrintWriter
对象输出字符文本内容时,它内部还是将字符串转
换成了某种字符集编码的字节数组后再进行输出,使用
PrintWriter
对象的好处就是不用编程人员自己来完成字符串到
字节数组的转换。
•
使用
ServletOutputStream
对象也能输出内容全为文本字符的网
页文档,但是,如果网页文档内容是在
Servlet
程序内部使用文
本字符串动态拼凑和创建出来的,则需要先将字符文本转换成
字节数组后输出。
•
如果一个网页文档内容全部为字符文本,但是这些内容可以直
接从一个字节输入流中读取出来,然后再原封不动地输出到客
户端,那么就应该使用
ServletOutputStream
对象直接进行输
出,而不要使用
PrintWriter
对象进行输出。
输出缓冲区:
•
Servlet
程序输出的
HTTP
消息的响应正文首先被写入到
Servlet
引擎提供的一
个输出缓冲区中,直到输出缓冲区被填满或者
Servlet
程序已经写入了所有
的响应内容,缓冲区中的内容才会被
Servlet
引擎发送到客户端。
•
使用输出缓冲区后,
Servlet
引擎就可以将响应状态行、各响应头和响应正
文严格按照
HTTP
消息的位置顺序进行调整后再输出到客户端。
•
如果在提交响应到客户端时,输出缓冲区中已经装入了所有的响应内容,
Servlet
引擎将计算响应正文部分的大小并自动设置
Content-Length
头字段。
•
如果在提交响应到客户端时,输出缓冲区中装入的内容只是全部响应内容的
一部分,
Servlet
引擎将使用
HTTP 1.1
的
chunked
编码方式(通过设置
Transfer-Encoding
头字段来指定)传输响应内容。
输出缓冲区-有关方法:
•
setBufferSize
方法
•
getBufferSize
方法
•
flushBuffer
方法
•
reset
方法
•
isCommitted
方法
什么是动态文件内容的下载:
•
只要让超链接的
URL
地址指向一个
exe
或
zip
等类型的文件,用
户单击这个超链接就可以将该资源文件下载到客户端。
•
如果要下载的文件并不真正存在于
WEB
服务器的文件系统中,
而是需要用一个
Servlet
程序临时在服务器内存中动态产生后再
传送到客户端,那该如何实现呢?
如何实现动态文件内容的下载:
•
需要通过
HttpServletResponse.setContentType
方法设置
Content-Type
头字段的值
为浏览器无法使用某种方式或激活某个程序来处理的
MIME
类型,例如,
“
application/octet-stream
”
或
“
application/x-msdownload
”
等。
•
需要通过
HttpServletResponse.setHeader
方法设置
Content-Disposition
头的值为
“
attachment;
filename
=
文件名
”
。
•
应该调用
HttpServletResponse.getOutputStream
方法返回的
ServletOutputStream
对象来向客户端写入附件文件内容,而不应使用
HttpServletResponse.getWriter
方
法返回的
PrintWriter
对象。
图像访问计数器-介绍:
•
网页每次被访问时,页面的访问次数都要发生改变,所以这个功能必须通过
服务器端的程序来实现。
•
一些
WEB
站点只能输出静态页面内容,没有开放运行服务器端程序的功能,
无法直接在这些只支持静态内容的
WEB
站点上编写服务器端程序来实现页面
访问次数的统计和显示功能。
•
一些具有执行服务器端程序功能的
WEB
站点推出了免费的页面访问计数器,
只要在位于任何站点的一个静态
HTML
页面中增加一条该站点提供的
HTML
语
句,该语句就能显示出该静态页面的访问次数。
•
一个站点要想能统计另外一个站点上的某个
HTML
页面的访问次数,必须让任
何一个浏览器在每次访问那个
HTML
页面都通知这个一下站点,这可以通过在
静态
HTML
页面中增加两种特殊的标签来实现:
标签和设置
src
属性的
标签。
标签的三个重要特性:
•
一个包含有图像的网页文件中并没有包含真正的图像数据内容,而只
是使用
标签指明了图像的
URL
地址。
举例:
本网页已被浏览了
次
•
标签的
src
属性也可以指向当前页面所在
WEB
服务器之外的其他
WEB
服务器上的图像文件。
•
浏览器并不关心
标签所需的图像数据在服务器端是如何产生,
它只知道去访问
src
属性指定的
URL
资源,并把服务器返回的数据当作
一个图像的内容来显示。服务器返回的图像数据可以直接从一个静态
图像文件中读取,也可以通过
Servlet
程序在内存中动态创建。
页面访问计数器的技术实现细节:
•
Servlet
程序输出的图像格式为
jpeg
,它应告诉浏览器其所输出的实体内容的
MIME
类型为
image/jpeg
。
•
因为图像是二进制数据,所以应该调用
HttpServletResponse.getOutputStream
方法返回的
ServletOutputStream
对象来向客户端写入图像数据。
•
java.awt.image.BufferedImage
类用于在内存中创建一幅图像,具体的图像内容则可以通过调
用其图形上下文对象(
java.awt.Graphics
)的各种绘图方法生成。
•
在内存图像中绘制访问次数时,必须限定显示的位数,如果访问次数超过七位,则用数字
9999999
显示,如果访问次数不足七位,则在前面补充相应个数的
0
。
•
每个引用该
Servlet
程序的静态页面的
URL
都对应一个各自的访问次数,每个
URL
及其访问次数
需要使用数据库系统来进行存储,对于简单的实验,也可以采用一个属性文件来进行存储。当
前引用页面的
URL
可以通过
Referer
请求头获取。
•
JDK
中提供了一个
javax.imageio.ImageIO
类,它的
write
方法可以将
BufferedImage
对象中的图
像编码成
jpeg
格式的图像数据后写入到一个
OutputStream
流对象中。
图像访问计数器-更多思考:
•
如果要自行设置
Content-Length
头字段,该如何处理?
•
在实际应用中,往往采用为每个页面分配一个
id
号的方式来区分和跟踪每个
静态
HTML
页面,请编写一个具体应用案例。

主机地址
:8080/it315/CountServlet?id=
本页面的
id
号
>
•
借鉴其中的动态图像生成技术,可以根据数据库系统中的数据动态产生出的
各类数据分析图(直方图、饼状图、折线图等),甚至是股票走势图。
•
使用设置
src
属性的
标签也可以实现统计和显示页面访问次数的功
能,请编写一个具体应用案例。
•
借鉴网页访问计数器的设计思想统,
www.it315.org
站点还为其他站点的页
面提供了一个
“
显示来访者的
IP
地址和地区信息
”
的功能,请描述一下其实
现过程?
多学两招:如何动态产生大小可变的图像:
•
涉及到的类:
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)
请求重定向与请求转发:
•
RequestDispatcher
接口
•
用
include
方法实现资源包含
•
用
forward
方法实现请求转发
•
请求转发的运行流程
•
用
sendRedirect
方法实现请求重定向
•
请求重定向的运行流程
•
请求重定向与请求转发的比较
•
缺省
Servlet
的缓存问题
RequestDispatcher接口:
•
RequestDispatcher
实例对象是由
Servlet
引擎创建的,它用于包装一个要被
其他资源调用的资源(例如,
Servlet
、
HTML
文件、
JSP
文件等),并可以通
过其中的方法将客户端的请求转发给所包装的资源。
•
RequestDispatcher
接口中定义了两个方法:
forward
方法和
include
方法。
•
forward
和
include
方法接收的两个参数必须是传递给当前
Servlet
的
service
方法的那两个
ServletRequest
和
ServletResponse
对象,或者是对
它们进行了包装的
ServletRequestWrapper
或
ServletResponseWrapper
对
象。
•
获取
RequestDispatcher
对象的方法:
ü
ServletContext.getRequestDispatcher
(参数只能是以
“
/
”
开头的路径)
ü
ServletContext.getNamedDispatcher
ü
ServletRequest.getRequestDispatcher
(参数可以是不以
“
/
”
开头的路径)
用include方法实现资源包含:
•
RequestDispatcher.include
方法用于将
RequestDispatcher
对象封装的资源内容作
为当前响应内容的一部分包含进来,从而实现可编程的服务器端包含功能。
•
被包含的
Servlet
程序不能改变响应消息的状态码和响应头,如果它里面存在这样的
语句,这些语句的执行结果将被忽略。
•
在调用
RequestDispatcher.include
方法时,
Servlet
容器不会去调整
HttpServletRequest
对象中的信息,
HttpServletRequest
对象仍然保持其初始的
URL
路径和参数信息。
缺省Servlet如何创建响应正文:
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);
}
用forward方法实现请求转发:
lforward方法用于将请求转发到RequestDispatcher对象封装的资源,Servlet程序在调用这个方法进行转发之前可以对请求进行一些前期的预处理。
l如果在调用forward方法之前,在Servlet程序中写入的部分内容已经被真正地传送到了客户端,forward方法将抛出IllegalStateException异常。
l调用RequestDispatcher.forward方法时,Servlet容器将根据目标资源路径对当前HttpServletRequest对象中的请求路径和参数信息进行调整。
l如果在调用forward方法之前向Servlet引擎的缓冲区中写入了内容,只要写入到缓冲区中的内容还没有被真正输出到客户端,forward方法就可以被正常执行,原来写入到输出缓冲区中的内容将被清空,但是,已写入到HttpServletResponse对象中的响应头字段信息保持有效。
l如果调用者与被调用者的访问URL不属于同一个目录,当被调用者输出的内容中包含有使用相对URL的访问路径时,原来相对被调用者的URL将变成相对于调用者的URL。
用sendRedirect方法实现请求重定向:
l
sendRedirect方法用于生成302响应码和Location响应头,从而通知客户端去重新访问Location响应头中指定的URL,其完整的定义语法如下:
public void sendRedirect(java.lang.String location)
throws java.io.IOException
l
使用下面两条语句也能完成response.sendRedirect(url)语句所完成的功能:
response.setStatus(response.SC_MOVED_TEMPORARILY );
response.setHeader ("Location", url);
l
sendRedirect 方法不仅可以重定向到当前应用程序中的其他资源,它还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。
l
如果传递给sendRedirect 方法的相对URL以“/”开头,则是相对于整个WEB站点的根目录,而不是相对于当前WEB应用程序的根目录。
请求重定向与请求转发的比较:
•
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
方法,在调用它们之
前,都不能有内容已经被实际输出到了客户端。如果缓冲区中已经有了一些内容,这些内容将被从缓冲区中
清除。
创建响应正文:
•getOutputStream与getWriter方法
•与getWriter方法相关的一些小疑问
•输出缓冲区
•实现动态文件内容的下载
•图像访问计数器
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
方法关闭该输出流对象。
选择getOutputStream和getWriter方法的要点:
•
PrintWriter
对象输出字符文本内容时,它内部还是将字符串转
换成了某种字符集编码的字节数组后再进行输出,使用
PrintWriter
对象的好处就是不用编程人员自己来完成字符串到
字节数组的转换。
•
使用
ServletOutputStream
对象也能输出内容全为文本字符的网
页文档,但是,如果网页文档内容是在
Servlet
程序内部使用文
本字符串动态拼凑和创建出来的,则需要先将字符文本转换成
字节数组后输出。
•
如果一个网页文档内容全部为字符文本,但是这些内容可以直
接从一个字节输入流中读取出来,然后再原封不动地输出到客
户端,那么就应该使用
ServletOutputStream
对象直接进行输
出,而不要使用
PrintWriter
对象进行输出。
输出缓冲区:
•
Servlet
程序输出的
HTTP
消息的响应正文首先被写入到
Servlet
引擎提供的一
个输出缓冲区中,直到输出缓冲区被填满或者
Servlet
程序已经写入了所有
的响应内容,缓冲区中的内容才会被
Servlet
引擎发送到客户端。
•
使用输出缓冲区后,
Servlet
引擎就可以将响应状态行、各响应头和响应正
文严格按照
HTTP
消息的位置顺序进行调整后再输出到客户端。
•
如果在提交响应到客户端时,输出缓冲区中已经装入了所有的响应内容,
Servlet
引擎将计算响应正文部分的大小并自动设置
Content-Length
头字段。
•
如果在提交响应到客户端时,输出缓冲区中装入的内容只是全部响应内容的
一部分,
Servlet
引擎将使用
HTTP 1.1
的
chunked
编码方式(通过设置
Transfer-Encoding
头字段来指定)传输响应内容。
输出缓冲区-有关方法:
•
setBufferSize
方法
•
getBufferSize
方法
•
flushBuffer
方法
•
reset
方法
•
isCommitted
方法
什么是动态文件内容的下载:
•
只要让超链接的
URL
地址指向一个
exe
或
zip
等类型的文件,用
户单击这个超链接就可以将该资源文件下载到客户端。
•
如果要下载的文件并不真正存在于
WEB
服务器的文件系统中,
而是需要用一个
Servlet
程序临时在服务器内存中动态产生后再
传送到客户端,那该如何实现呢?
如何实现动态文件内容的下载:
•
需要通过
HttpServletResponse.setContentType
方法设置
Content-Type
头字段的值
为浏览器无法使用某种方式或激活某个程序来处理的
MIME
类型,例如,
“
application/octet-stream
”
或
“
application/x-msdownload
”
等。
•
需要通过
HttpServletResponse.setHeader
方法设置
Content-Disposition
头的值为
“
attachment;
filename
=
文件名
”
。
•
应该调用
HttpServletResponse.getOutputStream
方法返回的
ServletOutputStream
对象来向客户端写入附件文件内容,而不应使用
HttpServletResponse.getWriter
方
法返回的
PrintWriter
对象。
图像访问计数器-介绍:
•
网页每次被访问时,页面的访问次数都要发生改变,所以这个功能必须通过
服务器端的程序来实现。
•
一些
WEB
站点只能输出静态页面内容,没有开放运行服务器端程序的功能,
无法直接在这些只支持静态内容的
WEB
站点上编写服务器端程序来实现页面
访问次数的统计和显示功能。
•
一些具有执行服务器端程序功能的
WEB
站点推出了免费的页面访问计数器,
只要在位于任何站点的一个静态
HTML
页面中增加一条该站点提供的
HTML
语
句,该语句就能显示出该静态页面的访问次数。
•
一个站点要想能统计另外一个站点上的某个
HTML
页面的访问次数,必须让任
何一个浏览器在每次访问那个
HTML
页面都通知这个一下站点,这可以通过在
静态
HTML
页面中增加两种特殊的标签来实现:
标签和设置
src
属性的
标签。
标签的三个重要特性:
•
一个包含有图像的网页文件中并没有包含真正的图像数据内容,而只
是使用
标签指明了图像的
URL
地址。
举例:
本网页已被浏览了
次
•
标签的
src
属性也可以指向当前页面所在
WEB
服务器之外的其他
WEB
服务器上的图像文件。
•
浏览器并不关心
标签所需的图像数据在服务器端是如何产生,
它只知道去访问
src
属性指定的
URL
资源,并把服务器返回的数据当作
一个图像的内容来显示。服务器返回的图像数据可以直接从一个静态
图像文件中读取,也可以通过
Servlet
程序在内存中动态创建。
页面访问计数器的技术实现细节:
•
Servlet
程序输出的图像格式为
jpeg
,它应告诉浏览器其所输出的实体内容的
MIME
类型为
image/jpeg
。
•
因为图像是二进制数据,所以应该调用
HttpServletResponse.getOutputStream
方法返回的
ServletOutputStream
对象来向客户端写入图像数据。
•
java.awt.image.BufferedImage
类用于在内存中创建一幅图像,具体的图像内容则可以通过调
用其图形上下文对象(
java.awt.Graphics
)的各种绘图方法生成。
•
在内存图像中绘制访问次数时,必须限定显示的位数,如果访问次数超过七位,则用数字
9999999
显示,如果访问次数不足七位,则在前面补充相应个数的
0
。
•
每个引用该
Servlet
程序的静态页面的
URL
都对应一个各自的访问次数,每个
URL
及其访问次数
需要使用数据库系统来进行存储,对于简单的实验,也可以采用一个属性文件来进行存储。当
前引用页面的
URL
可以通过
Referer
请求头获取。
•
JDK
中提供了一个
javax.imageio.ImageIO
类,它的
write
方法可以将
BufferedImage
对象中的图
像编码成
jpeg
格式的图像数据后写入到一个
OutputStream
流对象中。
图像访问计数器-更多思考:
•
如果要自行设置
Content-Length
头字段,该如何处理?
•
在实际应用中,往往采用为每个页面分配一个
id
号的方式来区分和跟踪每个
静态
HTML
页面,请编写一个具体应用案例。

主机地址
:8080/it315/CountServlet?id=
本页面的
id
号
>
•
借鉴其中的动态图像生成技术,可以根据数据库系统中的数据动态产生出的
各类数据分析图(直方图、饼状图、折线图等),甚至是股票走势图。
•
使用设置
src
属性的
标签也可以实现统计和显示页面访问次数的功
能,请编写一个具体应用案例。
•
借鉴网页访问计数器的设计思想统,
www.it315.org
站点还为其他站点的页
面提供了一个
“
显示来访者的
IP
地址和地区信息
”
的功能,请描述一下其实
现过程?
多学两招:如何动态产生大小可变的图像:
•
涉及到的类:
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)
请求重定向与请求转发:
•
RequestDispatcher
接口
•
用
include
方法实现资源包含
•
用
forward
方法实现请求转发
•
请求转发的运行流程
•
用
sendRedirect
方法实现请求重定向
•
请求重定向的运行流程
•
请求重定向与请求转发的比较
•
缺省
Servlet
的缓存问题
RequestDispatcher接口:
•
RequestDispatcher
实例对象是由
Servlet
引擎创建的,它用于包装一个要被
其他资源调用的资源(例如,
Servlet
、
HTML
文件、
JSP
文件等),并可以通
过其中的方法将客户端的请求转发给所包装的资源。
•
RequestDispatcher
接口中定义了两个方法:
forward
方法和
include
方法。
•
forward
和
include
方法接收的两个参数必须是传递给当前
Servlet
的
service
方法的那两个
ServletRequest
和
ServletResponse
对象,或者是对
它们进行了包装的
ServletRequestWrapper
或
ServletResponseWrapper
对
象。
•
获取
RequestDispatcher
对象的方法:
ü
ServletContext.getRequestDispatcher
(参数只能是以
“
/
”
开头的路径)
ü
ServletContext.getNamedDispatcher
ü
ServletRequest.getRequestDispatcher
(参数可以是不以
“
/
”
开头的路径)
用include方法实现资源包含:
•
RequestDispatcher.include
方法用于将
RequestDispatcher
对象封装的资源内容作
为当前响应内容的一部分包含进来,从而实现可编程的服务器端包含功能。
•
被包含的
Servlet
程序不能改变响应消息的状态码和响应头,如果它里面存在这样的
语句,这些语句的执行结果将被忽略。
•
在调用
RequestDispatcher.include
方法时,
Servlet
容器不会去调整
HttpServletRequest
对象中的信息,
HttpServletRequest
对象仍然保持其初始的
URL
路径和参数信息。
缺省Servlet如何创建响应正文:
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);
}
用forward方法实现请求转发:
lforward方法用于将请求转发到RequestDispatcher对象封装的资源,Servlet程序在调用这个方法进行转发之前可以对请求进行一些前期的预处理。
l如果在调用forward方法之前,在Servlet程序中写入的部分内容已经被真正地传送到了客户端,forward方法将抛出IllegalStateException异常。
l调用RequestDispatcher.forward方法时,Servlet容器将根据目标资源路径对当前HttpServletRequest对象中的请求路径和参数信息进行调整。
l如果在调用forward方法之前向Servlet引擎的缓冲区中写入了内容,只要写入到缓冲区中的内容还没有被真正输出到客户端,forward方法就可以被正常执行,原来写入到输出缓冲区中的内容将被清空,但是,已写入到HttpServletResponse对象中的响应头字段信息保持有效。
l如果调用者与被调用者的访问URL不属于同一个目录,当被调用者输出的内容中包含有使用相对URL的访问路径时,原来相对被调用者的URL将变成相对于调用者的URL。
用sendRedirect方法实现请求重定向:
l
sendRedirect方法用于生成302响应码和Location响应头,从而通知客户端去重新访问Location响应头中指定的URL,其完整的定义语法如下:
public void sendRedirect(java.lang.String location)
throws java.io.IOException
l
使用下面两条语句也能完成response.sendRedirect(url)语句所完成的功能:
response.setStatus(response.SC_MOVED_TEMPORARILY );
response.setHeader ("Location", url);
l
sendRedirect 方法不仅可以重定向到当前应用程序中的其他资源,它还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。
l
如果传递给sendRedirect 方法的相对URL以“/”开头,则是相对于整个WEB站点的根目录,而不是相对于当前WEB应用程序的根目录。
请求重定向与请求转发的比较:
•
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
方法,在调用它们之
前,都不能有内容已经被实际输出到了客户端。如果缓冲区中已经有了一些内容,这些内容将被从缓冲区中
清除。