【Servlet】關於RequestDispatcher的原理

RequestDispatcher簡介

RequestDispatcher 表明請求的派發者。它有2個動做:forward 和 include 。客戶端對於任何一個請求,能夠根據業務邏輯須要,選擇不一樣的處理辦法:
一、請求的是誰,誰就本身處理並響應,例如請求的是一個html,則web瀏覽器顯示的就是這個HTML的內容。
二、使用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.javahtml

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
<%@ 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向轉發的資源傳遞參數。java

雖然request對象沒有setParameter方法來設置參數,可是咱們能夠在轉發的URL後經過QueryString 的方式添加。JSP中的<jsp:foward>標籤下的<jsp:param>標籤就是使用的這個原理。web

 

 

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

<! 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再請求一次被包含的資源,將被包含的資源的響應數據包含到本來的資源中去,構成它的響應數據的一部分。

 

注意事項:服務器

一、被包含者不能設置ServletResponse的響應狀態和響應頭(不然並不會產生效果),由於這些都是包含者作的事,被包含者只須要產生響應數據解能夠了。session

二、不一樣於 forward中的request的傳遞特性:在被包含的資源中從request中獲取請求路徑相關的信息,發現依然是原始請求的路徑,也就是瀏覽器地址欄相關的路徑,也就是說被包含的資源得到的request對象的路徑屬性和原始請求資源的路徑同樣(見下面的例子1)。其它的API調用也是同樣的(Attribute 和Parameter)。jsp

 

 

例子1ui

TargetServlet.javathis

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

<%@ 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達到的傳遞參數的效果。

 

 

 

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 () ;
      }
}

 

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

 

 

 

 

 

 歡迎轉載,請註明出處:www.cnblogs.com/lulipro

 爲了得到更好的閱讀體驗,請訪問原博客地址。

限於本人水平,若是文章和代碼有表述不當之處,還請不吝賜教。

 

代碼鋼琴家

相關文章
相關標籤/搜索