轉自:http://foxty.iteye.com/blog/39332
Servlet和Filter的url匹配以及url-pattern詳解
Servlet 和 filter 是 J2EE 開發中常用的技術,使用方便,配置簡單,老少皆宜。估計大多數朋友都是直接配置用,也沒有關心過具體的細節,今天遇到一個問題,上網查了 servlet 的規範才發現, servlet 和 filter 中的 url-pattern 還是有一些文章在裏面的,總結了一些東西,放出來供大家參考,以免遇到問題又要浪費時間。 <o:p></o:p>
一, servlet 容器對 url 的匹配過程: <o:p></o:p>
<o:p></o:p>
當一個請求發送到 servlet 容器的時候,容器先會將請求的 url 減去當前應用上下文的 路徑 作爲 servlet 的映射 url ,比如我訪問的是 http://localhost/test/aaa.html ,我的應用上下文是 test ,容器會將 http://localhost/test 去掉,剩下的 /aaa.html 部分拿來做 servlet 的映射匹配。這個映射匹配過程是有順序的,而且當有一個 servlet 匹配成功以後,就不會去理會剩下的 servlet 了( filter 不同,後文會提到)。其匹配規則和順序如下: <o:p></o:p> 1. 精確路徑匹配。例子:比如 servletA 的 url-pattern 爲 /test , servletB 的 url-pattern 爲 /* ,這個時候,如果我訪問的 url 爲 http://localhost/test ,這個時候容器就會先 進行精確路徑匹配,發現 /test 正好被 servletA 精確匹配,那麼就去調用 servletA ,也不會去理會其他的 servlet 了。 <o:p></o:p> 2. 最長路徑匹配。例子: servletA 的 url-pattern 爲 /test/* ,而 servletB 的 url-pattern 爲 /test/a/* ,此時訪問 http://localhost/test/a 時,容器會選擇路徑最長的 servlet 來匹配,也就是這裏的 servletB 。 <o:p></o:p> 3. 擴展匹配,如果 url 最後一段包含擴展,容器將會根據擴展選擇合適的 servlet 。例子: servletA 的 url-pattern : *.action<o:p></o:p> 4. 如果前面三條規則都沒有找到一個 servlet ,容器會根據 url 選擇對應的請求資源。如果應用定義了一個 default servlet ,則容器會將請求丟給 default servlet (什麼是 default servlet ?後面會講) 。 <o:p></o:p> |
根據這個規則表,就能很清楚的知道 servlet 的匹配過程,所以定義 servlet 的時候也要考慮 url-pattern 的寫法,以免出錯。 <o:p></o:p>
對於 filter ,不會像 servlet 那樣只匹配一個 servlet ,因爲 filter 的集合是一個鏈,所以只會有處理的順序不同,而不會出現只選擇一個 filter 。 Filter 的處理順序和 filter-mapping 在 web.xml 中定義的順序相同。 <o:p></o:p>
二,url-pattern 詳解 <o:p></o:p>
在 web.xml 文件中,以下語法用於定義映射:
l 以 ”/’ 開頭和以 ”/*” 結尾的是用來做路徑映射的。
l 以前綴 ”*.” 開頭的是用來做擴展映射的。
l “/” 是用來定義 default servlet 映射的。
l 剩下的都是用來定義詳細映射的。比如: /aa/bb/cc.action
所以,爲什麼定義 ”/*.action” 這樣一個看起來很正常的匹配會錯?因爲這個匹配即屬於路徑映射,也屬於擴展映射,導致容器無法判斷。