1. 程式人生 > 程式設計 >Servlet虛擬路徑對映配置詳解

Servlet虛擬路徑對映配置詳解

​在上一篇中我們初識了Servlet,相信大家對Servlet也都有了些瞭解,知道了如何建立一個Servlet,並且為其新增虛擬對映,最終釋出專案,並在瀏覽器上請求對應的Servlet。

​我們知道,只有給Servlet配置好虛擬路徑,客戶端才可以進行訪問,但是對於Servlet的路徑對映,真的只有現在所知的這麼簡單麼?

​答案當時是No了,不然怎麼會有這篇文章😝,下面讓我們一起來探究其中的祕密吧!

Servlet虛擬路徑對映

在web.xml檔案中,一個<servlet-mapping>元素用於對映一個Servlet的對外訪問路徑,該路徑也稱為虛擬路徑。例如<url-pattern>/TestServlet</url-pattern>,其中“/TestServlet”就是一個虛擬路徑。

1.配置多個對映路徑

​在上一文中,我們說到@WebServlet中的urlPatterns屬性,其可以是一組匹配規則,也就是說一個Servlet是可以配置多個虛擬路徑的,也就是Servlet和虛擬路徑可以是一對多的一個關係(並不是多對多,一個虛擬路徑只能對映一個Servlet),其具體實現如下,並修改doPost處的程式碼:

@WebServlet(
		description = "My First Servlet",urlPatterns = { "/HelloServlet","/StillMe" },initParams = { 
				@WebInitParam(name = "name",value = "lizishu")
		})
public class HelloServlet extends HttpServlet {
 //具體邏輯參看上篇文章
 //...
 
 protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException {
		//設定返回客戶端的contentType
		//text/plain :純文字格式 設定為text/html println的換行會失效
		response.setContentType("text/plain;charset=utf-8");
		//response.setCharacterEncoding("utf-8"); 
		PrintWriter out = response.getWriter();
		out.println("Served at: " + request.getContextPath());
		String name = this.getInitParameter("name");
		out.println("name: " + name);
		out.println("訪問的Servle名為:" + HelloServlet.class);
	}
}

​可以看到,增加一個虛擬路徑對映非常方便,只需在urlPatterns中新增一項即可(注意'/'不可省略),啟動專案,在瀏覽器上輸入url,可以看到,無論是輸入http://localhost:8080/FirstProject/HelloServlet、還是http://localhost:8080/FirstProject/StillMe頁面上得到的輸出內容均一致。

​urlPatterns在Servlet 3.0版本之前,都是配置在web.xml中的,每個Servlet會有一個對應的<servlet-mapping>標籤,其中可以配置多個<url-pattern>

2.urlPatterns匹配規則

​說到Servlet虛擬路勁的匹配規則,還需要說到urlPatterns的幾種匹配規則,主要有以下四種:

  • 精確匹配:也就是我們在上面配置的匹配規則,需要完全相等才能匹配成功,這也是我們經常發生錯誤的地方,請求Servlet時的大小寫拼寫錯誤導致404;
  • 路徑匹配:比如想匹配以rest開頭的所有請求,可以寫成"/rest/*",其格式為以'/‘字元開頭,並以'/*'結尾;
  • 副檔名匹配:比如想匹配所有以.do結尾的請求,可以寫成"*.do",其格式為以'*.',後面跟上副檔名;
  • 預設匹配:對映路徑為"/",那麼這個Servlet就是當前應用的預設Servlet,預設處理無法匹配到虛擬路徑的請求。

​需要注意的是,路徑匹配和擴充套件匹配無法混合使用,即urlPattern無法寫成"/rest/*.do";這也是讓部分同學感到困惑的地方,Servlet的虛擬路徑匹配並不是完全的按照正則來匹配的,雖然路徑匹配和擴充套件匹配是按照正則中的萬用字元(*)來匹配的,這也是部分同學可以會寫出特定的正則,但是卻不是一個合法的虛擬路徑;Servlet容器收到請求後,會將請求從上下文路徑(通過request.getContextPath()獲取的)處截斷,使用剩餘的部分來進行路徑匹配,比如請求url為http://localhost:8080/FirstProject/HelloServlet,那麼Servlet容器就會使用"/HelloServlet"來匹配Servlet。

​最後需要注意的是,我們說了上面四種匹配規則,尤其是預設匹配,可以匹配到任意請求,那麼一個請求如果可以匹配多個Servlet的虛擬路徑,那麼該執行哪個Servlet?其實啊,這些匹配規則是有優先順序的,具體的優先順序為:精確匹配>路徑匹配>副檔名匹配>預設匹配,Servlet容器會從優先順序高的虛擬路徑開始匹配,匹配到後就會立刻將請求交給對應的Servlet來處理,不會再關心其他Servlet的虛擬路徑是否會匹配成功。

​下面我們來一組Servlet及其對應的虛擬路徑:

urlPatterns Servlet Name
/abc/* Servlet1
/ Servlet2
/abc Servlet3
*.do Servlet4

​當請求去除上下文路徑後路徑為:"/abc/a.html"時,根據上述規則,會呼叫Servlet1;

​請求為:"/abc",根據匹配優先順序,會呼叫Servlet3;

​請求為:"/abc/a.do",會匹配到'/abc/*'、'*.do',但根據匹配優先順序,會呼叫Servlet1;

​請求為:"/a.do",會匹配到'/'、'*.do',但根據匹配優先順序,會呼叫Servlet4;

3.Tomcat提供的預設Servlet

​為了測試預設Servlet,我們來進行一個測試。我們新建個SelfDefaultServlet,其urlPatterns我們配置為"/",其中的方法我們不做任何修改。

@WebServlet(
		description = "Self create default Servlet",urlPatterns = { "/" }
		)
public class SelfDefaultServlet extends HttpServlet {
 //...
}

我們啟動專案後,在瀏覽器上輸入http://localhost:8080/FirstProject/hahaha或者其他任意無法匹配到HelloServlet虛擬路徑的請求,發現頁面上的結果都如下所示,是不是這樣也不錯,不會報404錯誤了。

Servlet虛擬路徑對映配置詳解

​但是,此時我們想訪問WebContent目錄下的靜態頁面(新建的一個welcome.html檔案),瀏覽器上輸入http://localhost:8080/FirstProject/welcome.html,猜猜會發生什麼?我們來一起看下結果,如圖所示,請求結果並沒有按照我們的想法,根據請求路徑找到welcome.htm頁面,而是呼叫了SelfDefaultServlet,是不是很懵?

Servlet虛擬路徑對映配置詳解

​其實,客戶端的每個請求,都是由Servlet容器根據虛擬路徑的匹配規則來進行處理的,包括靜態資源。並且,如果路徑輸入錯誤(去除了自己配置的預設Servlet後),我們常見的下面的錯誤,也是Servlet返回給我們,哈哈,還是很意外?

Servlet虛擬路徑對映配置詳解

​我們能通過servlet方便簡單的開發網站,是因為我們站在了巨人的肩膀上,下面我們一起來看下Sun公司都為我們開發者提前做了些什麼工作。Tomcat會為專案配置一個預設的Servlet(如果專案中自行配置,則不會生效),配置檔案在tomcat安裝目錄下conf目錄中的web.xml檔案中,具體內容如下,預設的Servlet名為DefaultServlet。

<servlet>
 <servlet-name>default</servlet-name>
 <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
 <init-param>
  <param-name>debug</param-name>
  <param-value>0</param-value>
 </init-param>
 <init-param>
  <param-name>listings</param-name>
  <param-value>false</param-value>
 </init-param>
 <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
 <servlet-name>default</servlet-name>
 <url-pattern>/</url-pattern>
</servlet-mapping>

客戶端請求靜態資原始檔時,也是由預設的Servlet處理的(自己單獨配置Servlet除外),如果請求檔案能找到,就會將頁面通過HttpServletResponse物件以流的方式返回給客戶端,否則報404錯誤。

​不過講到這裡,大家可以自己試一試配置了預設Servelt時,訪問welcome.html的情況(會呼叫SelfDefaultServlet),但是,如果我們在瀏覽器中輸入http://localhost:8080/FirstProject/index.jsp(index.jsp是建立的第一個jsp頁面)呢?會是什麼樣一個結果?也是呼叫預設的Servlet麼?真是的執行結果如下:

Servlet虛擬路徑對映配置詳解

​這是什麼原因?為什麼不是呼叫預設的servlet了?這是因為tomcat除了預設Serlvet外,還給我們提供一個處理jsp檔案的Servlet,配置如下,因為字尾匹配的優先順序高於預設的Servlet,所以訪問JSP的時候需要交由JspServlet來處理(JSP因為可能包含Java程式碼,所以第一次執行的時候需要先編譯,這個工作由JspServlet完成)

<servlet>
 <servlet-name>jsp</servlet-name>
 <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
 <init-param>
  <param-name>fork</param-name>
  <param-value>false</param-value>
 </init-param>
 <init-param>
  <param-name>xpoweredBy</param-name>
  <param-value>false</param-value>
 </init-param>
 <load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
 <servlet-name>jsp</servlet-name>
 <url-pattern>*.jsp</url-pattern>
 <url-pattern>*.jspx</url-pattern>
</servlet-mapping>

4.總結

​本文具體討論了urlPatterns屬性的匹配規則,主要為四種,其優先順序也各不相同,我們在使用時,也需要根據自己的需求自己設定urlPatterns,不過知道了匹配規則,使用起來也會方便很多,也能幫我們快速的定位錯誤。

到此這篇關於Servlet虛擬路徑對映配置詳解的文章就介紹到這了,更多相關Servlet 虛擬路徑對映內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!