Servlet各種路徑、URL配置分析

Zollty發表於2013-09-13

 

大家都知道,Servlet有個配置:

<servlet>
  <servlet-name>zolltyMVC</servlet-name>
  <servlet-class>org.zollty.framework.mvc.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>zolltyMVC</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

 

對於<url-pattern>/</url-pattern>這一項,有時候會 帶有 “*” 這種寫法,這和沒有 "*" 號時有什麼差別呢?

 

首先來看一下,通過 HttpServletRequest request 我們能取到哪些重要引數:

System.out.println("getServerName" + request.getServerName());
System.out.println("getLocalName" + request.getLocalName());
System.out.println("------------------------------------");
System.out.println("getPathInfo" + request.getPathInfo());
System.out.println("getPathTranslated" + request.getPathTranslated());
System.out.println("------------------------------------");
System.out.println("getRemoteHost" + request.getRemoteHost());
System.out.println("getRemoteAddr" + request.getRemoteAddr());
System.out.println("getLocalAddr" + request.getLocalAddr());
System.out.println("------------------------------------");
System.out.println("getRequestURI" + request.getRequestURI());
System.out.println("getServletPath" + request.getServletPath());
System.out.println("getContextPath" + request.getContextPath());
System.out.println("------------------------------------");
System.out.println("getScheme" + request.getScheme());
System.out.println("getLocale" + request.getLocale().getLanguage());
System.out.println("------------------------------------");
System.out.println("getServerPort" + request.getServerPort());
System.out.println("getLocalPort" + request.getLocalPort());
System.out.println("getRemotePort" + request.getRemotePort());
System.out.println("------------------------------------");
System.out.println("getMethod" + request.getMethod());
System.out.println("getProtocol" + request.getProtocol());
System.out.println("getRemoteUser" + request.getRemoteUser());
System.out.println("getRequestedSessionId" + request.getRequestedSessionId());
System.out.println("getCharacterEncoding" + request.getCharacterEncoding());
System.out.println("getContentType" + request.getContentType());

 

當配置為 <url-pattern>/</url-pattern>時,列印的結果如下:

getServerNamelocalhost
getLocalName0.0.0.0
------------------------------------
getPathInfonull
getPathTranslatednull
------------------------------------
getRemoteHost0:0:0:0:0:0:0:1
getRemoteAddr0:0:0:0:0:0:0:1
getLocalAddr0.0.0.0
------------------------------------
getRequestURI/sss/sd/ds
getServletPath/sd/ds
getContextPath/sss
------------------------------------
getSchemehttp
getLocalezh
------------------------------------
getServerPort8081
getLocalPort8081
getRemotePort65281
------------------------------------
getMethodGET
getProtocolHTTP/1.1
getRemoteUsernull
getRequestedSessionIdE6CED285C020625E0D6531BBBD25033A
getCharacterEncodingnull
getContentTypenull

 

當配置為 <url-pattern>/*</url-pattern> 時,列印的結果如下:

getServerNamelocalhost
getLocalName0.0.0.0
------------------------------------
getPathInfo/sd/ds
getPathTranslatedD:\C\Java\apache-tomcat-7.0.23\webapps\sss\sd\ds
------------------------------------
getRemoteHost0:0:0:0:0:0:0:1
getRemoteAddr0:0:0:0:0:0:0:1
getLocalAddr0.0.0.0
------------------------------------
getRequestURI/sss/sd/ds
getServletPath
getContextPath/sss
------------------------------------
getSchemehttp
getLocalezh
------------------------------------
getServerPort8081
getLocalPort8081
getRemotePort65388
------------------------------------
getMethodGET
getProtocolHTTP/1.1
getRemoteUsernull
getRequestedSessionIdE6CED285C020625E0D6531BBBD25033A
getCharacterEncodingnull
getContentTypenull

 

區別在如下幾個地方:

// ------------------------------------
// getPathInfo/
// getPathTranslatedD:\C\Java\apache-tomcat-7.0.23\webapps\sss\
// ------------------------------------
// getRequestURI/sss/p/
// getServletPath/p

 

對於"/"形式,得到的getPathInfo和getPathTranslated都為null;

對於"/*"形式,則能得到 "/" 和 專案的所在磁碟上的絕對路徑

而對於ServletPath 和 RequestURI ,分析如下:

// ServletPath = 不含專案名稱的訪問地址 -- 如果是/p/*方式配置,則訪問地址為/p,如果是/*則是""(空); 如果是/方式配置,則訪問地址是全路徑(包括斜槓)
// RequestURI = 包含專案名稱的訪問地址 -- 不管是/或者/*或者/p/*方式配置,訪問地址都為/{專案名}+全路徑(包括斜槓)

也就是說,帶"*"時,ServletPath 獲取的是"/*"前面的內容(沒有斜槓),不帶"*"時,獲取的是全部內容(有沒有斜槓取決於輸入的URL)。

RequestURI 則比較統一,都等於: /{專案名}+全路徑(有沒有斜槓取決於輸入的URL),例如

輸入的是:

http://localhost:8081/zollty/ds,則為/zollty/ds(不帶斜槓)

輸入的是:

http://localhost:8081/zollty/ds/,則為/zollty/ds/(帶斜槓)

 

另外,getContextPath等於 "/" + 專案名稱 ,即: /{專案名},也比較常用,但是每次都去取,比較麻煩,還不如把專案名稱作為一個靜態常量。

 

 另外,servlet url的解析順序如下:

 

準則1、   在servlet-mapping配置中,帶"*"的優先順序,大於不帶"*"的;

準則2、   系統自帶的servlet,比如default Servlet、jsp Servlet,優先順序高於自定義的servelt的(將優先處理),但是這些servlet如果處理不了,會把請求轉發到後續的servelt去處理。

準則3、   同一檔案中的配置,前面的servlet-mapping配置,優先順序高於後面的servlet-mapping配置。

 

另外,說明一點:  

   帶"*"的配置方式,是強行攔截,只要匹配上,請求都會被攔截(比如,/*會攔截所有請求,*.jsp 會攔截所有 以.jsp結尾的請求。

   不帶"*"的配置方式,理論上是“精確攔截”,只會攔截和設定的url精確匹配的那一個請求的url,比如/prog,則只有http://...{專案名}/prog請求才會被攔截,

其他比如http://...{專案名}/prog/、http://...{專案名}/prog/abc等,都不會被攔截。但是設定成 "/" 時,是個例外,它會攔截所有請求(進一步說,"/"的攔截範圍和"/*"的攔截範圍其實是一樣的,只不過"/*"不僅僅是攔截範圍廣,更重要的是它的優先順序高,比沒有設定"/*"的系統自帶的servlet優先順序還高)。

 

以下是本人親自測試多次的結果:

優先順序從高到低,依次為:

<servlet-name>default</servlet-name>

<url-pattern>/*</url-pattern>

 

<servlet-name>jsp</servlet-name>

<url-pattern>/*</url-pattern>

 

<servlet-name>{自定義的servlet}</servlet-name>

<url-pattern>/*</url-pattern>

 

<servlet-name>jsp</servlet-name>

<url-pattern>*.jsp</url-pattern>

 

<servlet-name>default</servlet-name>

<url-pattern>/</url-pattern>

 

<servlet-name>{自定義的servlet}</servlet-name>

<url-pattern>/</url-pattern>

 

 

 

 

相關文章