好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Servlet关于RequestDispatcher的原理详解

requestdispatcher简介

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

1、请求的是谁,谁就自己处理并响应,例如请求的是一个html,则web浏览器显示的就是这个html的内容。

2、使用requestdispatcher让其它的资源参与进来,协同完成的响应,这就是requestdispatcher的主要作用。

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

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

?

1

2

3

4

5

6

7

8

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。

注意事项:  

1、在目标资源中调用forward方法时,必须保证此响应没有提交。也就是不要使用 servletresponse 对象的输出流对象,因为即便你写入了数据到响应缓冲区,最后也会被清空,如果缓冲区数据被刷新提交(out.flush),还会抛出illegalstateexception异常。

2、对于forward方法传递的request对象:虽然我们从调用上看,好像是将request对象传递给转动的资源上去了,但是我发现目标资源使用的request对象和转发的资源使用的request对象不是同一个request对象,因为分别从这2个request中获取requesturl,发现是不一样的。但是在目标资源request提取的paramter 和 attribute   ,在转发后的资源的request对象中,依然都可以提取到,且是相同的。所以,二者只是在请求路径相关的属性上不同,其它api调用返回的都是一样的。

3、在forward语句的前后,都不应该有响应输出的语句,应该会被忽略。

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

user.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

public class usersservlet extends httpservlet {

    private static final long serialversionuid = 1l ;

 

protected void doget (httpservletrequest request, httpservletresponse response) throws servletexception , ioexception {

       /*****************一般实际开发这些用户数据都是从数据库查出来的*********/

       list <user > 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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

<%@ 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"   %>

 

<!doctype html>

< html>

<head>

<meta http-equiv = "content-type" content = "text/html; charset=utf-8" >

<title> 用户列表</title>

</head>

<body>

 

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

 

< c:foreach var = "user" items= " ${users}" >

用户姓名:${user.name} 用户年龄:${user.age} <br />

</ c:foreach>

</body>

</html>

例子2: 不使用attribute,使用paramter向转发的资源传递参数。

虽然request对象没有setparameter方法来设置参数,但是我们可以在转发的url后通过querystring 的方式添加。jsp中的<jsp:foward>标签下的<jsp:param>标签就是使用的这个原理。

aimservlet.java

?

1

2

3

4

5

6

7

8

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

<%@ 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"   %>

 

<! doctype html>

<html>

<head>

<meta http-equiv = "content-type" content = "text/html; charset=utf-8" >

<title> 标题</title>

</head>

<body>

 

通过forward传递过来的参num=${param.num}

 

</body>

</html>

requestdispatcher.include(request, response)

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

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

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

 

注意事项:

1、被包含者不能设置servletresponse的响应状态和响应头(否则并不会产生效果),因为这些都是包含者做的事,被包含者只需要产生响应数据解可以了。

2、不同于 forward中的request的传递特性:在被包含的资源中从request中获取请求路径相关的信息,发现依然是原始请求的路径,也就是浏览器地址栏相关的路径,也就是说被包含的资源获得的request对象的路径属性和原始请求资源的路径一样(见下面的例子1)。其它的api调用也是一样的(attribute 和parameter)。

例子1

targetservlet.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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的告白----------------<br />" ) ;

       out .print ( "我偷懒了,下面的响应数据并不是我自己产生的,而是包含的其它资源产生的<br/>" ) ;

       request .getrequestdispatcher ( "test.jsp" ) . include( request , response );

 

       out .flush () ;

       out .close () ;

    }

}

test.jsp 

?

1

2

3

4

5

6

7

8

<%@ page  contenttype= "text/html; charset=utf-8" pageencoding = "utf-8" trimdirectivewhitespaces = "true"

      session = "false"

%>

 

<p> ------------------------来自test.jsp的告白-------------------------- </p>

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

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

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

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

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

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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的告白----------------<br />" ) ;

       out .print ( "我偷懒了,下面的响应数据并不是我自己产生的,而是包含的其它资源产生的<br/>" ) ;

 

       request .setattribute ( "sharedatt" , "i`m shared attribute" ) ;

 

       request .getrequestdispatcher ( "test.jsp?sharedparam=im-shared-parameter" ). include (request , response ) ;

 

       out .flush () ;

       out .close () ;

    }

}

?

1

2

3

4

5

6

7

8

<%@ page  contenttype= "text/html; charset=utf-8" pageencoding = "utf-8" trimdirectivewhitespaces = "true"

      session = "false"

%>

 

<p> ------------------------来自test.jsp的告白-------------------------- </p>

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

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

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

原文链接:https://www.cnblogs.com/lulipro/p/7471987.html

查看更多关于Servlet关于RequestDispatcher的原理详解的详细内容...

  阅读:10次