程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> JSP編程 >> 關於JSP >> 請求轉發和請求包含

請求轉發和請求包含

編輯:關於JSP

請求轉發和請求包含


1、Servlet 容器

\

  編程中的容器我們可以理解為程序運行時需要的環境,那麼Tomcat 就是Servlet 的運行環境,就是一個Servlet 容器。Servlet 容器的作用是負責處理客戶請求,當Servlet 容器獲取到用戶請求後,調用某個Servlet,並把Servlet 的執行結果返回給用戶。

  Servlet 容器的工作流程:

  ● 當用戶請求某個資源時,Servlet 容器使用ServletRequest 對象將用戶的請求信息封裝起來,然後調用 java Servlet API 中定義的Servlet 的生命周期方法,完成Servlet 的運行。

  ● Servlet 容器將Servlet 執行後需要返回用戶的結果封裝到 ServletResponse 對象中,最後由Servlet 容器發送給客戶,完成對客戶的一次服務過程。

  ● 每一個Servlet 都會執行 init()、service()、destory() 三個方法,在啟動時調用一次init) 方法對參數進行初始化,在該Servlet 生存期間每當收到對其的請求時都會調用Service() 方法對請求進行處理,當容器銷毀時自動調用 destory() 方法對Servlet 進行銷毀。

2、請求轉發和請求包含

  正是因為因為Servlet 中的service() 方法由Servlet 容器調用,所以一個 Servlet 的對象是無法調用另一個 Servlet 的方法的,但是在實際項目中,對於客戶端請求做出的響應可能會復雜,需要多個Servlet 來協作完成,這就需要請求轉發和請求包含技術了。但是,要注意,無論是請求轉發還是請求包含,都是表示由多個Servlet 共同處理同一個請求。

(1)請求轉發定義:

  Servlet(源組件)先對客戶請求做一些預處理操作(一般是對響應頭進行處理),然後把請求轉發給其他Servlet(目標組件)來完成包括生成響應結果在內的後續操作。

  實現方法:request.getRequestDispatcher(“接收請求的Servlet 路徑”). forward(request,response)

  getRequestDispatcher(String path):該方法的返回值類型是RequestDispatcher,請求發送器,該方法的參數是指明要接收請求的Servlet 的路徑;

  forward(ServletRequest req,ServletResponse res):該方法是RequestDispatcher 接口的方法,將請求從一個 servlet 轉發到服務器上的另一個資源(servlet、JSP 文件或 HTML 文件)。此方法允許一個 servlet 對請求進行初步處理,並使另一個資源生成響應。需要傳遞兩個參數,這兩個參數是當前Servlet 的request 對象和 response 對象傳遞過去的。

  forward() 方法的處理流程:

  ● 清空用於存放響應正文(響應體)數據的緩沖區。

  ● 如果目標組件為Servlet 或JSP,就調用它們的service() 方法,把該方法產生的響應結果發送到客戶端,如果目標組件為文件系統中的靜態 html 文檔,就讀去文檔中的數據並把它發送到客戶端。

  ● 由於 forward() 方法先清空用於存放響應正文數據的緩沖區,因此servlet源組件生成的響應結果不會被發送到客戶端,只有目標組件生成的結果才會被發送到客戶端,所以對源組件叫“留頭不留體”,目標組件為“留體不留頭”。

  ● 如果源組件在進行請求轉發之前,已經提交了響應結果(例如調用了flush 或close() 方法),那麼forward() 方法會拋出IllegalStateException。為了避免該異常,不應該在源組件中提交響應結果,所以叫留體拋異常。

(2)請求包含定義:

  Servlet(源組件)把其他Servlet(目標組件)生成的響應結果包含到自身的響應結果中。

  實現方式:request.getRequestDispatcher(“接收請求的Servlet 路徑”). include(request,response)

  include(ServletRequest request,ServletResponse response):該方法是RequestDispatcher 接口的方法,表示包含。它的參數同forward() 方法的參數一樣都是由當前Servlet傳遞過去的。

  包含與轉發相比,源組件與被包含的目標組件的輸出數據都會被添加到響應結果中,在目標組件中對響應狀態代碼或者響應頭所做的修改都會被忽略,所以對源組件來說是“留頭又留體”,對目標組件為“留體不留頭”。

  注意:當Servlet 源組件調用 RequestDispatcher 的 forward 或 include 方法時,都要把當前的 ServletRequest 對象和ServletResponse 對象作為參數傳給 forward 或 include 方法,這就使得源組件和目標組件共享同一個ServletRequest 對象和ServletResponse 對象,就實現了多個Servlet 協同處理同一個請求。

附:RequestDispatcher 接口

  RequestDispatcher 接口中定義了兩個方法::forward() 方法和 include() 方法,它們分別用於將請求轉發到 RequestDispatcher 對象封裝的資源和將 RequestDispatcher 對象封裝的資源作為當前響應內容的一部分包含進來.

3、請求轉發(留頭不留體,留體拋異常)

  AServlet(發送請求方):

package web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class AServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		
		response.setContentType("text/html;charset=utf-8"); 
		response.getWriter().print("您好!");
		//response.getWriter().flush();//刷新會導致response的狀態為已提交!
		
		// 轉發不能在response提交之後,否則就會拋異常
		request.getRequestDispatcher("/BServlet").forward(request, response);
	}
}
  BServlet(接收請求方):
package web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class BServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {		
		response.getWriter().print("我很棒!");
	}
}

  運行結果為:“我很棒!”(不會輸出“你好!”)。

  我對留頭不留體的分析:

    對於發出請求的Aservlet是:留頭不留體(設置的響應頭可以留下,響應體被接收請求的 Bservlet 響應體覆蓋); 留體拋異常,就是說只要請求轉發了,就要將請求完全由 Bservlet 處理,Aservlet就不能插手了,如果Aservlet 也提交了對請求的處理,那麼Bservlet 就不能處理請求了(因為請求已經被Aservlet 處理了,還處理啥) ,你安排人家處理請求,最終卻由你處理了,當forward() 轉發請求時,發現請求已經被處理,就會拋出異常。

    不過要注意,只有當AServlet 提交了處理(如例中手動flush將緩沖區內數據提交)才會拋出異常,如果沒有提交,說明之前A對請求的處理還在緩沖區中,B就會直接將A的緩沖區清空,然後覆蓋掉,就形成了之前的留頭不留體。

4、請求包含(留頭又留體)

  CServlet(發送請求方):

package web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 請求包含:留頭又留體
 */
public class CServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		response.setContentType("text/html;charset=utf-8"); //設置內容類型
		response.getWriter().print("你好!");
		request.getRequestDispatcher("/DServlet").include(request, response);
	}
}

  DServlet(接收請求方):

package web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {		
		response.getWriter().print("我很棒!");
	}
}

  運行結果為:你好!我很棒!

  結果說明請求包含是多個Servlet 共同處理一個請求的,並且發送方和接收方都能夠留下響應體。

5、請求轉發和請求包含的比較

  (1)相同點:

    請求轉發和請求包含都是在處理一個相同的請求,多個Servlet之間使用同一個 request 對象和 response 對象。

  (2)不同點:

    ● 如果在AServlet中請求轉發到BServlet,那麼在AServlet中不允許再輸出響應體,即不能使用response.getWriter() 和response.getOutputStream() 向客戶端輸出,這一工作交由BServlet來完成;如果是由AServlet請求包含BServlet,則沒有這個限制。

    ● 請求轉發不能設置響應體,但是可以設置響應頭,簡單來說就是“留頭不留體”,例如:response.setContentType("text/html;charset=utf-8”) 是可以留下來的;請求包含不僅可以設置響應頭,還可以設置響應體,簡單來說就是“留頭又留體“。

    ● 請求轉發大多應用在Servlet中,轉發目標大多是jsp頁面;請求包含大多應用在jsp頁面中,完成多頁面的合並。一般情況下經常使用的是請求轉發。

6、請求轉發的應用:

  ● 在Servlet中向數據庫獲取數據,保存到request域中;

  ● 轉發到jsp頁面,jsp從request域中獲取數據,顯示在頁面上。

7、請求轉發和重定向的區別

  ● 對於客戶端浏覽器來說,轉發是一個請求,重定向是兩個請求;

  ● 轉發浏覽器地址欄不變化,重定向會變成轉發後的URL ;

  ● 轉發只能在一個項目內,而重定向沒有限制,可以重定向到任意網址,如京東、淘寶等 ;

  ● 轉發可以使用request 域傳遞數據,而重定向不能。因為轉發是一個請求,重定向是兩個請求;

  ● 轉發只有一個請求,原來是什麼請求方式就是什麼方式;而重定向兩個請求,第一個可能為post 可能為get ,但是第二個請求一定是get 。

  小結:在浏覽器地址欄中輸入某個URL地址或單擊網頁上的一個超鏈接時,浏覽器發出的HTTP請求消息的請求方式為GET。如果網頁中的


\

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved