Servlet關(guān)于RequestDispatcher的原理詳解
RequestDispatcher簡(jiǎn)介
RequestDispatcher 代表請(qǐng)求的派發(fā)者。它有2個(gè)動(dòng)作:forward 和 include ??蛻舳藢?duì)于任何一個(gè)請(qǐng)求,可以根據(jù)業(yè)務(wù)邏輯需要,選擇不同的處理辦法:
1、請(qǐng)求的是誰,誰就自己處理并響應(yīng),例如請(qǐng)求的是一個(gè)html,則web瀏覽器顯示的就是這個(gè)HTML的內(nèi)容。
2、使用RequestDispatcher讓其它的資源參與進(jìn)來,協(xié)同完成的響應(yīng),這就是RequestDispatcher的主要作用。
RequestDispatcher 有一個(gè)特點(diǎn),就是瀏覽器上顯示的URL是最先請(qǐng)求的目標(biāo)資源的URL,不會(huì)因?yàn)槭褂昧薴orward、include方法而改變。因此forward和include的調(diào)用對(duì)于用戶來說是透明的。
RequestDispatcher 實(shí)質(zhì)是一個(gè)接口,有2個(gè)方法分別代表這2個(gè)動(dòng)作。下面一 一介紹。
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)
這個(gè)方法將請(qǐng)求從一個(gè) Servlet or JSP目標(biāo)資源 上 轉(zhuǎn)發(fā)到服務(wù)器上的另一個(gè)資源(servlet、JSP 文件或 HTML 文件,這些資源必須是當(dāng)前Web上下文中的),讓其它的資源去生成響應(yīng)數(shù)據(jù)。
例如用戶請(qǐng)求的是目標(biāo)資源A,A接受到請(qǐng)求后,轉(zhuǎn)發(fā)到B,真正產(chǎn)生響應(yīng)數(shù)據(jù)是被轉(zhuǎn)發(fā)的資源B,而A只是起個(gè)引導(dǎo)轉(zhuǎn)發(fā)作用。瀏覽器的地址欄不會(huì)變,依然是A的URL。
這個(gè)方法可以允許被請(qǐng)求的目標(biāo)資源做一些準(zhǔn)備工作后,再讓轉(zhuǎn)發(fā)的資源去響應(yīng)請(qǐng)求。例如下面的例子1。
注意事項(xiàng):
1、在目標(biāo)資源中調(diào)用forward方法時(shí),必須保證此響應(yīng)沒有提交。也就是不要使用 ServletResponse 對(duì)象的輸出流對(duì)象,因?yàn)榧幢隳銓懭肓藬?shù)據(jù)到響應(yīng)緩沖區(qū),最后也會(huì)被清空,如果緩沖區(qū)數(shù)據(jù)被刷新提交(out.flush),還會(huì)拋出IllegalStateException異常。
2、對(duì)于forward方法傳遞的request對(duì)象:雖然我們從調(diào)用上看,好像是將request對(duì)象傳遞給轉(zhuǎn)動(dòng)的資源上去了,但是我發(fā)現(xiàn)目標(biāo)資源使用的request對(duì)象和轉(zhuǎn)發(fā)的資源使用的request對(duì)象不是同一個(gè)request對(duì)象,因?yàn)榉謩e從這2個(gè)request中獲取RequestURL,發(fā)現(xiàn)是不一樣的。但是在目標(biāo)資源request提取的Paramter 和 Attribute ,在轉(zhuǎn)發(fā)后的資源的request對(duì)象中,依然都可以提取到,且是相同的。所以,二者只是在請(qǐng)求路徑相關(guān)的屬性上不同,其它API調(diào)用返回的都是一樣的。
3、在forward語句的前后,都不應(yīng)該有響應(yīng)輸出的語句,應(yīng)該會(huì)被忽略。
例子1:一個(gè)簡(jiǎn)單的 MVC演示。Servlet充當(dāng)控制器,轉(zhuǎn)發(fā)到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 { /*****************一般實(shí)際開發(fā)這些用戶數(shù)據(jù)都是從數(shù)據(jù)庫(kù)查出來的*********/ 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) ; //對(duì)request 進(jìn)制預(yù)處理準(zhǔn)備工作 request .getRequestDispatcher ( "users.jsp").forward( request , response );//轉(zhuǎn)發(fā)到users.jsp,讓他去具體響應(yīng) } }
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> -----------------轉(zhuǎn)發(fā)到的資源users.jsp產(chǎn)生的響應(yīng)數(shù)據(jù)------------------ </p> < c:forEach var ="user" items= " ${users}" > 用戶姓名:${user.name} 用戶年齡:${user.age} <br /> </ c:forEach> </body> </html>
例子2:不使用Attribute,使用Paramter向轉(zhuǎn)發(fā)的資源傳遞參數(shù)。
雖然request對(duì)象沒有setParameter方法來設(shè)置參數(shù),但是我們可以在轉(zhuǎn)發(fā)的URL后通過QueryString 的方式添加。JSP中的<jsp:foward>標(biāo)簽下的<jsp:param>標(biāo)簽就是使用的這個(gè)原理。
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> 標(biāo)題</title> </head> <body> 通過forward傳遞過來的參num=${param.num} </body> </html>
RequestDispatcher.include(request, response)
此方法用于包含響應(yīng)中某個(gè)資源(servlet、JSP 頁(yè)面和 HTML 文件)的內(nèi)容。
調(diào)用者指定一個(gè)被包含的資源,將這個(gè)包含的資源(JSP,Servlet,HTML)的響應(yīng)數(shù)據(jù)包含到自己的響應(yīng)體中。被包含的數(shù)據(jù)是在服務(wù)器上經(jīng)過運(yùn)行產(chǎn)生的,因此是動(dòng)態(tài)包含,而不同于JSP中的include指令,它是JSP轉(zhuǎn)譯期的靜態(tài)包含,類似于C語言中的宏一樣。
這個(gè)過程實(shí)質(zhì)是用一個(gè)相同的Request再請(qǐng)求一次被包含的資源,將被包含的資源的響應(yīng)數(shù)據(jù)包含到原本的資源中去,構(gòu)成它的響應(yīng)數(shù)據(jù)的一部分。
注意事項(xiàng):
1、被包含者不能設(shè)置ServletResponse的響應(yīng)狀態(tài)和響應(yīng)頭(否則并不會(huì)產(chǎn)生效果),因?yàn)檫@些都是包含者做的事,被包含者只需要產(chǎn)生響應(yīng)數(shù)據(jù)解可以了。
2、不同于 forward中的request的傳遞特性:在被包含的資源中從request中獲取請(qǐng)求路徑相關(guān)的信息,發(fā)現(xiàn)依然是原始請(qǐng)求的路徑,也就是瀏覽器地址欄相關(guān)的路徑,也就是說被包含的資源獲得的request對(duì)象的路徑屬性和原始請(qǐng)求資源的路徑一樣(見下面的例子1)。其它的API調(diào)用也是一樣的(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的告白----------------<br />" ) ; out .print ( "我偷懶了,下面的響應(yīng)數(shù)據(jù)并不是我自己產(chǎn)生的,而是包含的其它資源產(chǎn)生的<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> 我輸出的響應(yīng)數(shù)據(jù)將被其它的資源包含 </p> 請(qǐng)的URL是 <%= request.getRequestURL().toString() %> ,可以看出客戶端真正請(qǐng)求的不是我,我只是幕后工作者。 <p> 但我很開心,因?yàn)轫憫?yīng)給客戶端的數(shù)據(jù)一部分來自于我 </p>
例子2:通過包含路徑后追加QueryString來向被包含資源傳遞參數(shù),以及通過request.setAttribute傳遞屬性。
同樣, JSP中的<jsp:include>標(biāo)簽下的<jsp:param>標(biāo)簽就是通過在含路徑后追加QueryString達(dá)到的傳遞參數(shù)的效果。
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 ( "我偷懶了,下面的響應(yīng)數(shù)據(jù)并不是我自己產(chǎn)生的,而是包含的其它資源產(chǎn)生的<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> 我輸出的響應(yīng)數(shù)據(jù)將被其它的資源包含 </p> <p> 從request中提取共享的屬性Attribute : <%= request.getAttribute("s haredatt") %> <p> 從request中提取共享的參數(shù)Parameter : <%= request.getParameter("sharedparam" ) %>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringMVC?HttpMessageConverter報(bào)文信息轉(zhuǎn)換器
這篇文章主要為大家介紹了SpringMVC?HttpMessageConverter報(bào)文信息轉(zhuǎn)換器,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05Java實(shí)現(xiàn)異步延遲隊(duì)列的方法詳解
目前系統(tǒng)中有很多需要用到延時(shí)處理的功能,本文就為大家介紹了Java實(shí)現(xiàn)異步延遲隊(duì)列的方法,文中的示例代碼講解詳細(xì),需要的可以參考一下2023-03-03詳解關(guān)于springboot-actuator監(jiān)控的401無權(quán)限訪問
本篇文章主要介紹了詳解關(guān)于springboot-actuator監(jiān)控的401無權(quán)限訪問,非常具有實(shí)用價(jià)值,有興趣的可以了解一下2017-09-09Java之String、StringBuffer、StringBuilder的區(qū)別分析
今天搞安卓在看書的時(shí)候遇到了StringBuilder這個(gè)類型的東東,有點(diǎn)小迷,不知道它跟string、stringbuffer的關(guān)系式怎么樣的,趕快查閱相關(guān)資料,了解了個(gè)大概,拿出來分享一下2012-11-11springboot使用GuavaCache做簡(jiǎn)單緩存處理的方法
這篇文章主要介紹了springboot使用GuavaCache做簡(jiǎn)單緩存處理的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01JAVA中l(wèi)ist,set,數(shù)組之間的轉(zhuǎn)換詳解
以下是對(duì)JAVA中l(wèi)ist,set,數(shù)組之間的轉(zhuǎn)換進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下2013-09-09SpringBoot 集成 ShedLock 分布式鎖的示例詳解
ShedLock是一個(gè)在分布式環(huán)境中使用的定時(shí)任務(wù)框架,用于解決在分布式環(huán)境中的多個(gè)實(shí)例的相同定時(shí)任務(wù)在同一時(shí)間點(diǎn)重復(fù)執(zhí)行的問題,本文重點(diǎn)給大家介紹SpringBoot 分布式鎖ShedLock的相關(guān)知識(shí),感興趣的朋友一起看看吧2021-08-08javaweb實(shí)現(xiàn)百度GPS定位接口(經(jīng)緯度)
這篇文章主要介紹了javaweb實(shí)現(xiàn)百度GPS定位接口(經(jīng)緯度),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02