博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Servlet--关于RequestDispatcher(forward、include)的原理
阅读量:2441 次
发布时间:2019-05-10

本文共 6616 字,大约阅读时间需要 22 分钟。

RequestDispatcher简介

RequestDispatcher 代表请求的派发者。它有2个动作:forward 和 include 。客户端对于任何一个请求,可以根据业务逻辑需要,选择不同的处理办法:

  1. 请求的是谁,谁就自己处理并响应,例如请求的是一个html,则web浏览器显示的就是这个HTML的内容。
  2. 使用RequestDispatcher让其它的资源参与进来,协同完成的响应,这就是RequestDispatcher的主要作用。

RequestDispatcher 有一个特点,就是浏览器上显示的URL是最先请求的目标资源的URL,不会因为使用了forward、include方法而改变。因此forward和include的调用对于用户来说是透明的。

RequestDispatcher 实质是一个接口,有2个方法分别代表这2个动作。下面一 一介绍。

public interface RequestDispatcher{
public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException; public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException;}

RequestDispatcher.forward(request, response)

这个方法将请求从一个 Servlet or JSP目标资源 上 转发到服务器上的另一个资源(servlet、JSP 文件或 HTML 文件,这些资源必须是当前Web上下文中的),让其它的资源去生成响应数据。

例如用户请求的是目标资源A,A接受到请求后,转发到B,真正产生响应数据是被转发的资源B,而A只是起个引导转发作用。浏览器的地址栏不会变,依然是A的URL。
这个方法可以允许被请求的目标资源做一些准备工作后,再让转发的资源去响应请求。例如下面的例子1。

注意事项:

  • 在目标资源中调用forward方法时,必须保证此响应没有提交。也就是不要使用 ServletResponse 对象的输出流对象,因为即便你写入了数据到响应缓冲区,最后也会被清空,如果缓冲区数据被刷新提交(out.flush),还会抛出IllegalStateException异常。
  • 对于forward方法传递的request对象:虽然我们从调用上看,好像是将request对象传递给转动的资源上去了,但是我发现目标资源使用的request对象和转发的资源使用的request对象不是同一个request对象,因为分别从这2个request中获取RequestURL,发现是不一样的。但是在目标资源request提取的Paramter 和 Attribute ,在转发后的资源的request对象中,依然都可以提取到,且是相同的。所以,二者只是在请求路径相关的属性上不同,其它API调用返回的都是一样的。
  • 在forward语句的前后,都不应该有响应输出的语句,应该会被忽略。

示例1:一个简单的 MVC演示。Servlet充当控制器,转发到view层的jsp。

User.java

public class User{
private String name; private int age; public String getName(){
return name ; } public void setName( String name ){
this .name = name ; } public int getAge() {
return age ; } public void setAge( int age ){
this .age = age ; }}

UsersServlet.java

public class UsersServlet extends HttpServlet {
private static final long serialVersionUID = 1L ;protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException , IOException {
/*****************一般实际开发这些用户数据都是从数据库查出来的*********/ List
users = new ArrayList <> (); User u1 = new User () ; u1 .setAge ( 20) ; u1 .setName ( "Bob") ; User u2 = new User () ; u2 .setAge ( 21) ; u2 .setName ( "Tony") ; users .add ( u1) ; users .add ( u2) ; /*********************************************/ request .setAttribute ( "users", users) ; //对request 进制预处理准备工作 request .getRequestDispatcher ( "users.jsp").forward( request , response );//转发到users.jsp,让他去具体响应 } }

users.jsp

<%@ page   contentType= "text/html; charset=UTF-8" pageEncoding ="UTF-8" trimDirectiveWhitespaces= "true"          session ="true" %><%@ taglib prefix= "c" uri = "http://java.sun.com/jsp/jstl/core"   %>< html>
用户列表

-----------------转发到的资源users.jsp产生的响应数据------------------

< c:forEach var ="user" items= " ${users}" >用户姓名:${user.name} 用户年龄:${user.age}

在这里插入图片描述

示例2:不使用Attribute,使用Paramter向转发的资源传递参数。
虽然request对象没有setParameter方法来设置参数,但是我们可以在转发的URL后通过QueryString 的方式添加。JSP中的jsp:foward标签下的jsp:param标签就是使用的这个原理。

在这里插入图片描述

AimServlet.java

public class AimServlet extends HttpServlet {
private static final long serialVersionUID = 1L ; protected void doGet( HttpServletRequest request , HttpServletResponse response) throws ServletException , IOException {
request .getRequestDispatcher ( "foo.jsp?num=1") . forward( request , response ); }}

foo.jsp

<%@ page   contentType= "text/html; charset=UTF-8" pageEncoding ="UTF-8" trimDirectiveWhitespaces= "true"          session ="true" %><%@ taglib prefix= "c" uri = "http://java.sun.com/jsp/jstl/core"   %>
标题通过forward传递过来的参num=${param.num}

在这里插入图片描述

RequestDispatcher.include(request, response)

此方法用于包含响应中某个资源(servlet、JSP 页面和 HTML 文件)的内容。

调用者指定一个被包含的资源,将这个包含的资源(JSP,Servlet,HTML)的响应数据包含到自己的响应体中。被包含的数据是在服务器上经过运行产生的,因此是动态包含,而不同于JSP中的include指令,它是JSP转译期的静态包含,类似于C语言中的宏一样。

这个过程实质是用一个相同的Request再请求一次被包含的资源,将被包含的资源的响应数据包含到原本的资源中去,构成它的响应数据的一部分。

在这里插入图片描述

注意事项:

  • 被包含者不能设置ServletResponse的响应状态和响应头(否则并不会产生效果),因为这些都是包含者做的事,被包含者只需要产生响应数据解可以了。
  • 不同于 forward中的request的传递特性:在被包含的资源中从request中获取请求路径相关的信息,发现依然是原始请求的路径,也就是浏览器地址栏相关的路径,也就是说被包含的资源获得的request对象的路径属性和原始请求资源的路径一样(见下面的例子1)。其它的API调用也是一样的(Attribute 和Parameter)。

示例1:

TargetServlet.java

public class TargetServlet extends HttpServlet {
private static final long serialVersionUID = 1L ; protected void doGet( HttpServletRequest request , HttpServletResponse response) throws ServletException , IOException {
response .setContentType ( "text/html;charset=utf-8" ); PrintWriter out = response .getWriter () ; out .println ( "----------来自TargetServlet的告白----------------
" ) ; out .print ( "我偷懒了,下面的响应数据并不是我自己产生的,而是包含的其它资源产生的
" ) ; request .getRequestDispatcher ( "test.jsp") . include( request , response ); out .flush () ; out .close () ; }}

test.jsp

<%@ page    contentType= "text/html; charset=UTF-8" pageEncoding = "UTF-8" trimDirectiveWhitespaces = "true"          session = "false"%>

------------------------来自test.jsp的告白--------------------------

我输出的响应数据将被其它的资源包含

请的URL是 <%= request.getRequestURL().toString() %> ,可以看出客户端真正请求的不是我,我只是幕后工作者。

但我很开心,因为响应给客户端的数据一部分来自于我

在这里插入图片描述

示例2:通过包含路径后追加QueryString来向被包含资源传递参数,以及通过request.setAttribute传递属性。

同样, JSP中的< jsp:include >标签下的< jsp:param >标签就是通过在含路径后追加QueryString达到的传递参数的效果。

在这里插入图片描述

public class TargetServlet extends HttpServlet {
private static final long serialVersionUID = 1L ; protected void doGet( HttpServletRequest request , HttpServletResponse response) throws ServletException , IOException {
response .setContentType ( "text/html;charset=utf-8" ); PrintWriter out = response .getWriter () ; out .println ( "----------来自TargetServlet的告白----------------
" ) ; out .print ( "我偷懒了,下面的响应数据并不是我自己产生的,而是包含的其它资源产生的
" ) ; request .setAttribute ( "sharedatt", "I`m shared attribute") ; request .getRequestDispatcher ( "test.jsp?sharedparam=Im-shared-parameter" ). include (request , response ) ; out .flush () ; out .close () ; }}
<%@ page    contentType= "text/html; charset=UTF-8" pageEncoding = "UTF-8" trimDirectiveWhitespaces = "true"          session = "false"%>

------------------------来自test.jsp的告白--------------------------

我输出的响应数据将被其它的资源包含

从request中提取共享的属性Attribute : <%= request.getAttribute("s haredatt") %>

从request中提取共享的参数Parameter : <%= request.getParameter("sharedparam" ) %>

在这里插入图片描述

转载地址:http://hnsqb.baihongyu.com/

你可能感兴趣的文章
ubuntu中如何启用仓库_如何在Ubuntu中启用本地菜单
查看>>
outlook密码更改_如何更改您的Outlook.com密码
查看>>
如何在Ubuntu 14.04中管理启动应用程序
查看>>
如何在Ubuntu 14.04中读取MOBI文件
查看>>
计算两张图片是否完全相同_您如何分辨两张DVD是否完全相同?
查看>>
如何在Windows 10中连接到无线网络
查看>>
proxies中的机密信息_新机密模式在Gmail中的工作方式
查看>>
如何检查MacBook的电池状况
查看>>
2k分辨率显示器 浏览器_如何使浏览器使用显示器的完整分辨率?
查看>>
ubuntu lts 版本_最新的Ubuntu LTS版本是什么?
查看>>
苹果收集到月中蜂窝数据满_苹果不会收集有关您的大量数据
查看>>
redis发布订阅数据太大_一切现在都是订阅,而且太多了
查看>>
android alexa_如何将Alexa设置为Android上的默认数字助理
查看>>
2018年4月13日_如何立即获取Windows 10的2018年4月更新
查看>>
电报机器人 gmail_如何在新的Gmail中查找联系人
查看>>
硬盘未分配空间变为可用空间_使用Windows 10的新“可用空间”工具清理硬盘
查看>>
如何下载所有Instagram照片
查看>>
iphone闪存测速软件_如何在iPhone上使用USB闪存盘
查看>>
传智播客客户端密码_适用于Android的最佳播客客户端
查看>>
24/7专业家庭安全监控值得吗?
查看>>