Servlet 3.0 之 分發(fā)請求

當構(gòu)建一個Web應(yīng)用邦蜜,把一個請求的處理轉(zhuǎn)給其它servlet,或者在response中包含其它servlet的輸出通常很有用處署辉。RequestDispatcher接口提供一種機制來完成這個功能押赊。

當在請求上啟動了異步叶堆,AsyncContext允許用戶把請求分發(fā)回servlet容器。

一摘昌、獲取一個RequestDispatcher

實現(xiàn)了RequestDispatcher接口的對象可以通過ServletContext中的下列方法被獲人傺:

  • getRequestDispatcher
  • getNamedDispatcher

getRequestDispatcher方法需要傳入一個字符串參數(shù),這個參數(shù)描述了ServletContext范圍內(nèi)的一個路徑聪黎。這個路勁必須相對ServletContext的根目錄罕容,并且以"/"開頭或者為空。這個方法根據(jù) Mapping Requests to Servlets 章節(jié)里servlet路徑匹配規(guī)則稿饰,使用這個路徑來查找一個servlet锦秒,使用一個RequestDispatcher 對象來包裝它,并且返回一個結(jié)果對象喉镰。如果基于給定的路徑?jīng)]有servlet能夠被解析旅择,提供它的RequestDispatcher返回那個路徑的內(nèi)容。

getNamedDispatcher方法需要傳入一個字符串參數(shù)侣姆,這個參數(shù)用來表示ServletContext已知的一個servlet的名字生真。如果一個servlet被發(fā)現(xiàn)脖咐,它會被用一個RequestDispatcher對象來包裝并且返回這個對象。如果沒有servlet與指定的名字關(guān)聯(lián)汇歹,方法必須返回null屁擅。

為了使RequestDispatcher對象能夠通過使用相對于當前請求(不是相對ServletContext的根路徑)路徑的相對路徑被獲得,ServletRequest 接口中提供了getRequestDispatcher 方法产弹。

這個方法的行為與ServletContext 中有相同名字的方法類似派歌。servlet容器使用請求對象中的信息把給定的相對于當前servlet的路徑轉(zhuǎn)換為一個完整路徑。比如痰哨,在一個"/"根上下文胶果,一個請求/garden/tools.html中,通過ServletRequest.getRequestDispatcher("header.html") 獲得的請求分發(fā)器將像調(diào)用ServletContext.getRequestDispatcher("/garden/header.html") 一樣斤斧。

  1. 請求分發(fā)器路徑中的查詢字符串
    使用路徑信息來創(chuàng)建RequestDispatcher對象的ServletContextServletRequest方法允許請求字符串信息的可選附件給這個路徑早抠。比如,一個開發(fā)者可以通過下列代碼獲得一個RequestDispatcher

     String path = "/raisins.jsp?orderno=5";
     RequestDispatcher rd = context.getRequestDispatcher(path);
     rd.include(request, response);
    

被用來創(chuàng)建RequestDispatcher的請求字符串中指定的參數(shù)相比傳遞給servlet的有相同名字的參數(shù)有更高優(yōu)先級撬讽。與一個RequestDispatcher 關(guān)聯(lián)的參數(shù)僅被應(yīng)用在includeforward 調(diào)用期間蕊连。

二、使用一個請求分發(fā)器

為了使用一個請求分發(fā)器游昼,一個servlet調(diào)用RequestDispatcher 接口的include或者forward方法甘苍。給這些方法的參數(shù)可能是通過javax.servlet接口的service方法傳遞進來的requestresponse參數(shù),或者是request或response包裝對象類的子類實例烘豌。對于后者载庭,包裝器實例必須包裝容器傳遞給service方法的request或者response對象。

容器提供者應(yīng)該確保請求一個目標servlet的分發(fā)出現(xiàn)在相同JVM里的相同線程廊佩。

三囚聚、Include方法

RequestDispatcher接口的include方法可以在任意時間被調(diào)用。include方法的目標servlet可以獲得請求對象的所有方面标锄,它對response對象的使用會更加受限顽铸。

它僅能夠把信息寫到response對象的ServletOutputStream或者Writer,并且通過寫內(nèi)容超出response緩存鸯绿,或者顯示調(diào)用ServletResponse接口的flushBuffer方法來提交response跋破。
除了HttpServletRequest.getSession()HttpServletRequest.getSession(boolean)方法,它不能設(shè)置頭部或者調(diào)用任何影響response頭部的方法瓶蝴。
任何嘗試設(shè)置頭部必須被忽略毒返,并且如果response已經(jīng)被提交,任何對需要添加一個Cookie響應(yīng)頭的HttpServletRequest.getSession()或者HttpServletRequest.getSession(boolean)的調(diào)用必須拋出一個IllegalStateException舷手。

如果默認servlet是RequestDispatch.include()的目標拧簸,并且請求的資源并不存在,那么這個默認的servlet必須拋出FileNotFoundException男窟。如果這個異常沒有被抓住和處理盆赤,并且response還沒有被提交贾富,這個狀態(tài)碼必須被設(shè)置為500。

  1. Included Request 參數(shù)
    除了用getNameDispatcher方法獲得的servlets牺六,一個被另外servlet使用RequestDispatcher接口的include方法調(diào)用的servlet可以訪問它被調(diào)用的路徑颤枪。
    下列請求屬性必須被設(shè)置:

     javax.servlet.include.request_uri
     javax.servlet.include.context_path
     javax.servlet.include.servlet_path
     javax.servlet.include.path_info
     javax.servlet.include.query_string
    

這些屬性可以通過請求對象上從included servlet通過getAttribute方法訪問到,并且它們的值必須分別等于請求URI淑际,context path畏纲,servlet path,path info和included servlet的查詢字符串春缕。如果這個請求是后續(xù)included盗胀,這些屬性會被這個include代替。
如果這個included servlet通過getNameDispatcher方法被獲得锄贼,這些屬性一定不能被設(shè)置票灰。

四、Forward 方法

僅當輸出還未被提交到客戶端宅荤,RequestDispatcher接口的forward方法可以通過調(diào)用servlet而被調(diào)用屑迂。如果response緩存中的輸出數(shù)據(jù)還未被提交,在目標servlet的service方法被調(diào)用之前膘侮,其中的內(nèi)容必須被清除屈糊。如果response對象已經(jīng)被提交,IllegalStateException必須被拋出琼了。

暴露給目標servlet的請求對象的路徑元素必須反應(yīng)用來獲取RequestDispatcher的路徑。

對此夫晌,唯一的例外就是如果RequestDispatcher通過getNamedDispatcher方法獲得雕薪。這種場景下,請求對象的路徑元素必須反應(yīng)出原始請求的路徑晓淀。

RequestDispatcher接口的forward方法沒有異常并返回之前所袁,response內(nèi)容必須被容器發(fā)送,提交和關(guān)閉凶掰。如果一個錯誤出現(xiàn)在RequestDispatcher.forward()的目標中燥爷,異常會在所有調(diào)用filters和servlets之中傳遞,最終傳遞回容器懦窘。

  1. 查詢字符串
    當forwarding或者including請求時前翎,請求分發(fā)機制負責聚合查詢字符串參數(shù)。

  2. Forwarded請求參數(shù)
    除了通過getNamedDispatcher方法獲得的servlets畅涂,一個被另外servlet通過使用RequestDispatcherforward方法調(diào)用的servlet能夠訪問原始請求的路徑港华。
    下列請求屬性必須被設(shè)置:

     javax.servlet.forward.request_uri
     javax.servlet.forward.context_path
     javax.servlet.forward.servlet_path
     javax.servlet.forward.path_info
     javax.servlet.forward.query_string
    

這些屬性的值必須分別等于HttpServletRequest的這些方法的返回值-getRequestURI,getContextPath午衰,getServletPath立宜,getPathInfo冒萄,getQueryString,這些方法在傳遞給來自客戶端的請求的調(diào)用鏈上第一個servlet對象的請求對象上被調(diào)用橙数。

這些屬性通過請求對象上的getAttribute方法從forwarded servlet訪問到尊流。需要注意的是,這些屬性必須總能反應(yīng)原始請求里面的信息灯帮,即使在多個forwards和后續(xù)請求被調(diào)用的情況下崖技。

如果forwarded servlet通過使用getNamedDispatcher方法獲得,那么這些屬性一定不能被設(shè)置施流。

五响疚、錯誤處理

如果是一個請求分發(fā)器目標的servlet拋出一個運行時異常或者一個ServletException或者IOException類型的已檢查異常瞪醋,它會被傳遞到發(fā)起調(diào)用的servlet忿晕。所有其它異常應(yīng)該被包裝為ServletException,并且把異常的根本原因設(shè)置為原始異常银受,就像它沒有被傳遞一樣践盼。

六宾巍、獲得一個AsyncContext

實現(xiàn)AsyncContext接口的一個對象可以通過一個startAsync方法從ServletRequest獲取。一旦你有一個AsyncContext顶霞,你能用它通過complete()方法或者一個dispatch方法的使用來完成請求的處理。

七选浑、Dispatch Method

下列來自AsyncContext的方法能夠用來分發(fā)請求:

  • dispatch(path)
    dispatch方法需要一個字符串參數(shù)蓝厌,用來描述ServletContext范圍里面的路徑。這個路徑必須相對于ServletContext的根路徑拓提,并且以'/'開頭。
  • dispatch(servletContext, path)
    dispatch方法需要一個字符串參數(shù)代态,用來描述指定ServletContext范圍里面的路徑。這個路徑必須相對于指定ServletContext的根路徑疹吃,并且以'/'開頭蹦疑。
  • dispatch()
    dispatch方法不需要參數(shù)。它使用原始URI作為路徑互墓。如果AsyncContext通過startAsync(ServletRequest,ServletResponse)初始化,并且傳遞進來的請求是HttpServletRequest的實例判莉,那么這個分發(fā)就是HttpServletRequest.getRequestURI()返回的URI豆挽。否則券盅,當它是容器的最后一個分發(fā),這次分發(fā)就是請求的URI娘侍。

一個AsyncContext接口的dispatch方法可以被等待異步事件發(fā)生的應(yīng)用調(diào)用。如果complete()已經(jīng)在AsyncContext上被調(diào)用憾筏,必須拋出一個IllegalStateException異常痒芝。所有dispatch方法立即返回并且并不提交response荆虱。

暴露給目標servlet的請求對象的路徑元素必須要反應(yīng)出AsyncContext.dispatch里面指定的路徑。

  1. 查詢字符串
    當分發(fā)請求時拖叙,請求分發(fā)機制負責聚合查詢字符串钱骂。

  2. Dispatched 請求參數(shù)
    一個通過使用AsyncContext接口的dispatch方法調(diào)用的servlet可以訪問到原始請求的路徑黄痪。
    下列請求屬性必須被設(shè)置:

     javax.servlet.async.request_uri
     javax.setvlet.async.context_path
     javax.servlet.async.servlet_path
     javax.servlet.async.path_info
     javax.servlet.async.query_string
    

這些屬性的值必須分別等于HttpServletRequest接口的這些方法返回的值-getRequestURI, getContextPath, getServletPath, getPathInfo, getQueryString盔然,這些方法在傳遞給來自客戶端的請求的調(diào)用鏈上第一個servlet對象的請求對象上被調(diào)用。

這些屬性通過請求對象上的getAttribute方法從forwarded servlet訪問到油额。需要注意的是刻帚,這些屬性必須總能反應(yīng)原始請求里面的信息,即使在多個dispatches被調(diào)用的情況下崇众。

翻譯自 Java Servlet Specification
Version 3.0 Rev a
Author:Rajiv Mordani
Date: December 2010

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末航厚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子幔睬,更是在濱河造成了極大的恐慌,老刑警劉巖赦抖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異队萤,居然都是意外死亡,警方通過查閱死者的電腦和手機舍杜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門赵辕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人还惠,你說我怎么就攤上這事』ナ埃” “怎么了嚎幸?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嫉晶。 經(jīng)常有香客問我,道長箍铭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任诈火,我火速辦了婚禮状答,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拍摇。我一直安慰自己,他們只是感情好充活,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著混卵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪男公。 梳的紋絲不亂的頭發(fā)上合陵,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天,我揣著相機與錄音拥知,去河邊找鬼。 笑死速梗,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的姻锁。 我是一名探鬼主播猜欺,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼开皿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起笋妥,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤窄潭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后嫉你,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年油挥,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片深寥。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖则酝,靈堂內(nèi)的尸體忽然破棺而出闰集,到底是詐尸還是另有隱情沽讹,我是刑警寧澤武鲁,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布沐鼠,位于F島的核電站挚瘟,受9級特大地震影響饲梭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜憔涉,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一监氢、第九天 我趴在偏房一處隱蔽的房頂上張望布蔗。 院中可真熱鬧浪腐,春花似錦、人聲如沸议街。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涂身。三九已至,卻和暖如春蛤售,著一層夾襖步出監(jiān)牢的瞬間妒潭,已是汗流浹背揣钦。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留冯凹,地道東北人。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓匈庭,卻偏偏與公主長得像空凸,于是被迫代替她去往敵國和親嚎花。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容