你真的理解SpringMVC DispatcherServlet中的映射了嗎?

 

1、Request URL 與 Servlet url-pattern匹配順序與關係html

   當一個請求發送到servlet容器(服務器)的時候,容器先會將請求的url減去當前應用上下文的路徑,就是scheme://ip:port/context url做爲servlet的映射url,訪問的是http://localhost:8080/test/index.html,個人應用上下文(context)是test,容器會將http://localhost:8080/test去掉,剩下的/index.html部分拿來和servleturl-pattern進行匹配。前端

1.        精確路徑匹配(徹底匹配)java

」/」開始的,不包含通配符*(不以通配符結尾)的,例如:web

<servlet-mapping>

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

    <url-pattern>/index.html</url-pattern>

  </servlet-mapping>

 

2.        最長路徑匹配(路徑匹配)spring

」/」開始的,而且以通配符*結尾的(通配符只能在結尾,不能放中間。例如,/index/te*/index.html這樣的)tomcat

<servlet-mapping>

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

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

 </servlet-mapping>

對於最長路徑匹配,老是會匹配路徑長的,例如,有2servlet-mapping以下。(本地服務器)服務器

<servlet-mapping>

    <servlet-name>A</servlet-name>

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

  </servlet-mapping>

<servlet-mapping>

    <servlet-name>B</servlet-name>

    <url-pattern>/test/a/*</url-pattern>

  </servlet-mapping>

   對於請求http://localhost/test/a雖然AB都知足,可是servlet容器就會選擇B,由於B匹配到的長度更長。app

3.        擴展匹配jsp

*.開始,以擴展名結束的,例如: 測試

<servlet-mapping>

    <servlet-name>spring-dispatcher-servlet</servlet-name>

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

  </servlet-mapping>

4.        默認servlet匹配

只有一個」/」,例如:

<servlet-mapping>

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

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

  </servlet-mapping>

 

2、DispatcherServlet 的url-pattern

   在說DispatcherServlet url-pattern以前得先介紹一個比較重要的點,就是咱們的項目下的WEB-INFweb.xml中的url-pattern是不容許重複的,例如同時在項目中配置以下2個相同默認的映射路徑,服務器啓動就會報錯。

<servlet-mapping>

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

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

  </servlet-mapping>

<servlet-mapping>

    <servlet-name>spring-dispatcher-servlet</servlet-name>

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

  </servlet-mapping>

   可能會有人有疑問,在tomcat服務器的web.xml中已經定義了以下圖所示的servleturl-pattern,而在咱們本身的項目中的web.xml中定義一樣的默認servlet-mapping  url-pattern爲何沒有報錯呢?

圖1  tomcat默認的Servlet

               

圖2 tomcat jsp Servlet

                    

圖3 tomcat 默認的映射

   對於這個問題尚未仔細研究過,不過應該是default servlet是單獨的最後處理的,想一下這個道理很簡單,只有咱們的web.xml中沒有找到映射纔會到default servlet因此不存在衝突的問題。

下載再來看DispatcherServlet中下面這2servlet-mapping的區別

<servlet-mapping>

    <servlet-name>spring-dispatcher-servlet</servlet-name>

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

  </servlet-mapping>

<servlet-mapping>

    <servlet-name>spring-dispatcher-servlet</servlet-name>

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

  </servlet-mapping>

       DispatcherServlet本質上仍是一個servlet,根據上面所介紹的servlet匹配順序和規則很容易得出」/*」是路徑匹配,只不過它是匹配全部路徑,就是隻有是頁面請求的不論是客戶端來的頁面請求仍是,服務器轉發的頁面請求都會被DispatcherServlet處理。

   如今對於把DispatcherServletservlet-mapping配置爲」/*」出現的各類404錯誤就很是明顯了。DispatcherServlet處理請求是咱們本身實現的,可是全部請求(根據最長路徑匹配規則,除非有更加精確的匹配,例如,/view/*)都到了DispatcherServlet顯然咱們沒有實現的映射的部分就會出現404錯誤,例如各類靜態資源的請求等。

       DispatcherServletservlet-mapping若是配置的是」/」,這個是個默認的servlet,就是在沒有找到匹配的servlet的時候就使用DispatcherServlet。這個一樣由於咱們使用SpringMVC一般值配置了DispatcherServlet,而沒有配置其餘的servlet,對於這種狀況」/」」/*」相差不大。

   不過有一點DispatcherServletservlet-mapping若是配置的是」/」則能夠訪問的<welcome-file-list>設置的頁面。而」/*」訪問不到,這個緣由尚未仔細研究。關於」/」」/*」之間的差異在stackoverflow上有一個問題 」/」」/*」 的差異 對於這個問題的有的回答剛剛開始看以爲很對,可是經過不斷的測試和更加深刻的思考也會發現一些問題,能夠參考測試一下,順便想想Servlet的匹配規則。

 

3、DispatcherServlet servlet-mapping配置策略參考

   配置url-pattern的時候儘可能使用更加具體的模式,例如使用後綴匹配,例如,*.do,*.html,*.action等方式。

   若是你以爲上面的方式不夠優雅,能夠把要按模塊設置前綴,例如,使用/user/*,/shop/*這樣的方式來處理。

   對於靜態資源的映射能夠直接經過像下面的方式直接經過default Servlet來解決,這樣就避免過多的轉發,提升效率。

<servlet-mapping>

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

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

  </servlet-mapping>

 

 

4、其餘一些問題

   常常有一些404錯誤很難找到緣由,由於不少狀況能夠引發服務器返回404錯誤,我沒有讀過tomcat的源碼,因此很難知道根本緣由,不過對於使用SpringMVC若是出現了像下面這樣常見的錯誤。

No mapping found for HTTP request with URI [/context/xxx/xxx] in DispatcherServlet with name 'spring-dispatcher-servlet'

   那麼就是servlet容器已經找到了DispatcherServlet可是DispatcherServlet沒有設置相應的映射的方法。

   還有就是路徑前面帶不帶」/」的的區別,這裏可使用一個小技巧幫助記憶,就是服務器端(servlet,web.xmlRequestMapping等配置中)的路徑加上」/」表示的是相對於上下文環境(context),例如,

request.getRequestDispatcher("/index.html").forward(request, response);

   假如是本地服務器,端口是8080項目上下文環境是test,那麼上面的就表示轉發到http://localhost:8080/test/index.html這個路徑。而在前端頁面(jsp中編譯也是這個原則)中的」/」則表示根路徑,例如,在jsp中有連接是」/index.html」表示的就是http://localhost:8080/index.html這個路徑。

   對於沒有加上」/」的路徑都是相對路徑,就是當前文件所在目錄的路徑加上指定的連接。

相關文章
相關標籤/搜索