Servlet虛擬路徑映射配置詳解
在上一篇中我們初識了Servlet,相信大家對Servlet也都有了些了解,知道了如何創(chuàng)建一個Servlet,并且為其添加虛擬映射,最終發(fā)布項目,并在瀏覽器上請求對應的Servlet。
我們知道,只有給Servlet配置好虛擬路徑,客戶端才可以進行訪問,但是對于Servlet的路徑映射,真的只有現(xiàn)在所知的這么簡單么?
答案當時是No了,不然怎么會有這篇文章😝,下面讓我們一起來探究其中的秘密吧!
Servlet虛擬路徑映射
在web.xml文件中,一個<servlet-mapping>元素用于映射一個Servlet的對外訪問路徑,該路徑也稱為虛擬路徑。例如<url-pattern>/TestServlet</url-pattern>,其中“/TestServlet”就是一個虛擬路徑。
1.配置多個映射路徑
在上一文中,我們說到@WebServlet中的urlPatterns屬性,其可以是一組匹配規(guī)則,也就是說一個Servlet是可以配置多個虛擬路徑的,也就是Servlet和虛擬路徑可以是一對多的一個關(guān)系(并不是多對多,一個虛擬路徑只能映射一個Servlet),其具體實現(xiàn)如下,并修改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頁面上得到的輸出內(nèi)容均一致。
urlPatterns在Servlet 3.0版本之前,都是配置在web.xml中的,每個Servlet會有一個對應的<servlet-mapping>
標簽,其中可以配置多個<url-pattern>
。
2.urlPatterns匹配規(guī)則
說到Servlet虛擬路勁的匹配規(guī)則,還需要說到urlPatterns的幾種匹配規(guī)則,主要有以下四種:
- 精確匹配:也就是我們在上面配置的匹配規(guī)則,需要完全相等才能匹配成功,這也是我們經(jīng)常發(fā)生錯誤的地方,請求Servlet時的大小寫拼寫錯誤導致404;
- 路徑匹配:比如想匹配以rest開頭的所有請求,可以寫成"/rest/*",其格式為以'/‘字符開頭,并以'/*'結(jié)尾;
- 擴展名匹配:比如想匹配所有以.do結(jié)尾的請求,可以寫成"*.do",其格式為以'*.',后面跟上擴展名;
- 缺省匹配:映射路徑為"/",那么這個Servlet就是當前應用的缺省Servlet,默認處理無法匹配到虛擬路徑的請求。
需要注意的是,路徑匹配和擴展匹配無法混合使用,即urlPattern無法寫成"/rest/*.do";這也是讓部分同學感到困惑的地方,Servlet的虛擬路徑匹配并不是完全的按照正則來匹配的,雖然路徑匹配和擴展匹配是按照正則中的通配符(*)來匹配的,這也是部分同學可以會寫出特定的正則,但是卻不是一個合法的虛擬路徑;Servlet容器收到請求后,會將請求從上下文路徑(通過request.getContextPath()獲取的)處截斷,使用剩余的部分來進行路徑匹配,比如請求url為http://localhost:8080/FirstProject/HelloServlet,那么Servlet容器就會使用"/HelloServlet"來匹配Servlet。
最后需要注意的是,我們說了上面四種匹配規(guī)則,尤其是缺省匹配,可以匹配到任意請求,那么一個請求如果可以匹配多個Servlet的虛擬路徑,那么該執(zhí)行哪個Servlet?其實啊,這些匹配規(guī)則是有優(yōu)先級的,具體的優(yōu)先級為:精確匹配>路徑匹配>擴展名匹配>缺省匹配,Servlet容器會從優(yōu)先級高的虛擬路徑開始匹配,匹配到后就會立刻將請求交給對應的Servlet來處理,不會再關(guān)心其他Servlet的虛擬路徑是否會匹配成功。
下面我們來一組Servlet及其對應的虛擬路徑:
urlPatterns | Servlet Name |
---|---|
/abc/* | Servlet1 |
/ | Servlet2 |
/abc | Servlet3 |
*.do | Servlet4 |
當請求去除上下文路徑后路徑為:"/abc/a.html"時,根據(jù)上述規(guī)則,會調(diào)用Servlet1;
請求為:"/abc",根據(jù)匹配優(yōu)先級,會調(diào)用Servlet3;
請求為:"/abc/a.do",會匹配到'/abc/*'、'*.do',但根據(jù)匹配優(yōu)先級,會調(diào)用Servlet1;
請求為:"/a.do",會匹配到'/'、'*.do',但根據(jù)匹配優(yōu)先級,會調(diào)用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虛擬路徑的請求,發(fā)現(xiàn)頁面上的結(jié)果都如下所示,是不是這樣也不錯,不會報404錯誤了。

但是,此時我們想訪問WebContent目錄下的靜態(tài)頁面(新建的一個welcome.html文件),瀏覽器上輸入http://localhost:8080/FirstProject/welcome.html,猜猜會發(fā)生什么?我們來一起看下結(jié)果,如圖所示,請求結(jié)果并沒有按照我們的想法,根據(jù)請求路徑找到welcome.htm頁面,而是調(diào)用了SelfDefaultServlet,是不是很懵?

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

我們能通過servlet方便簡單的開發(fā)網(wǎng)站,是因為我們站在了巨人的肩膀上,下面我們一起來看下Sun公司都為我們開發(fā)者提前做了些什么工作。Tomcat會為項目配置一個缺省的Servlet(如果項目中自行配置,則不會生效),配置文件在tomcat安裝目錄下conf目錄中的web.xml文件中,具體內(nèi)容如下,缺省的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>
客戶端請求靜態(tài)資源文件時,也是由缺省的Servlet處理的(自己單獨配置Servlet除外),如果請求文件能找到,就會將頁面通過HttpServletResponse對象以流的方式返回給客戶端,否則報404錯誤。
不過講到這里,大家可以自己試一試配置了缺省Servelt時,訪問welcome.html的情況(會調(diào)用SelfDefaultServlet),但是,如果我們在瀏覽器中輸入http://localhost:8080/FirstProject/index.jsp(index.jsp是創(chuàng)建的第一個jsp頁面)呢?會是什么樣一個結(jié)果?也是調(diào)用缺省的Servlet么?真是的運行結(jié)果如下:

這是什么原因?為什么不是調(diào)用缺省的servlet了?這是因為tomcat除了缺省Serlvet外,還給我們提供一個處理jsp文件的Servlet,配置如下,因為后綴匹配的優(yōu)先級高于缺省的Servlet,所以訪問JSP的時候需要交由JspServlet來處理(JSP因為可能包含Java代碼,所以第一次執(zhí)行的時候需要先編譯,這個工作由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.總結(jié)
本文具體討論了urlPatterns屬性的匹配規(guī)則,主要為四種,其優(yōu)先級也各不相同,我們在使用時,也需要根據(jù)自己的需求自己設定urlPatterns,不過知道了匹配規(guī)則,使用起來也會方便很多,也能幫我們快速的定位錯誤。
到此這篇關(guān)于Servlet虛擬路徑映射配置詳解的文章就介紹到這了,更多相關(guān)Servlet 虛擬路徑映射內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot Cache @CacheEvict 無法模糊刪除的解決方案
這篇文章主要介紹了Springboot Cache @CacheEvict 無法模糊刪除的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12Netty分布式NioEventLoop優(yōu)化selector源碼解析
這篇文章主要介紹了Netty分布式NioEventLoop優(yōu)化selector源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-03-03基于Comparator對象集合實現(xiàn)多個條件按照優(yōu)先級的比較
這篇文章主要介紹了基于Comparator對象集合實現(xiàn)多個條件按照優(yōu)先級的比較,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07