1. 程式人生 > >DispatcherServlet的url-pattern配置

DispatcherServlet的url-pattern配置

DispatcherServlet常見的配置

   <servlet>
       <servlet-name>springmvc</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <!-- contextConfigLocation配置springmvc載入的配置檔案(配置處理器對映器,介面卡等等)
       如果不配置,預設載入的是/WEB-INF/[DispatcherServlet 的Servlet 名字]-servlet.xml(springmvc-servlet.xml) -->
       <init-param>
           <param-name>contextConfigLocation</param-name>
           <param-value>classpath:spring/springmvc.xml</param-value>
       </init-param>
       <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
       <servlet-name>springmvc</servlet-name>
       <url-pattern>/</url-pattern>
   </servlet-mapping>

常見的url-pattern配置有以下三種:

第一種:

'*.xxx', 以指定字尾結尾的請求都交由DispatcherServlet處理

第二種:

'/' 將會覆蓋容器的default servlet, 凡是在web.xml檔案中找不到匹配的URL,它們的訪問請求都將交給該Servlet處理(靜態資源也將會攔截). 所以web.xml沒有配置其他特殊路徑的servlet, 基本上所有的請求都交由DispatcherServlet處理.

'/*' 錯誤的配置,會攔截*.jsp, *.jspx的請求, 使用這種配置最終要轉發到一個JSP頁面,仍然會由DispatcherServlet, 解析jsp地址, 不能根據jsp頁面找到handler, 會報錯

對於第一種擴充套件匹配, 是最簡單的. 也是使用最簡單的了.但是現在如此流行restful風格的URL, 這種帶小尾巴的URL, 還是有點low的. 第二種配置使用/, 通過該配置是可以實現rustful風格的URL的.

url-pattern配置為 ‘/*’, 為什麼是錯誤的?

為了驗證這種配置, 我做了一個簡單的測試 在webapp/WEB-INF/jsp下新建test.jsp, controller中只做轉發.

@Controller
@RequestMapping("")
public class Test {
    @RequestMapping("/test")
    public String test() {
        return "test";
    }
}

測試請求路徑: /test 結果: 執行該請求後404 console列印如下日誌:

DispatcherServlet with name ‘taotao-sso’ processing GET request for [/test] RequestMappingHandlerMapping]-[DEBUG] Looking up handler method for path /test RequestMappingHandlerMapping]-[DEBUG] Returning handler method [public java.lang.String com.taotao.sso.controller.Test.test()] DispatcherServlet]-[DEBUG] Rendering view [org.springframework.web.servlet.view.InternalResourceView: name ‘test’; URL [/WEB-INF/jsp/test.jsp]] in DispatcherServlet with name ‘taotao-sso’ InternalResourceView]-[DEBUG] Forwarding to resource [/WEB-INF/jsp/test.jsp] in InternalResourceView ‘test’ DispatcherServlet]-[DEBUG] DispatcherServlet with name ‘taotao-sso’ processing GET request for [/WEB-INF/jsp/test.jsp] RequestMappingHandlerMapping]-[DEBUG] Looking up handler method for path /WEB-INF/jsp/test.jsp RequestMappingHandlerMapping]-[DEBUG] Did not find handler method for [/WEB-INF/jsp/test.jsp] PageNotFound]-[WARN] No mapping found for HTTP request with URI [/WEB-INF/jsp/test.jsp] in DispatcherServlet with name ‘taotao-sso’ DispatcherServlet]-[DEBUG] Successfully completed request

從日誌可以清晰的看出, springmvc可以找到請求/test的handler, 之後springmvc轉發請求’/WEB-INF/jsp/test.jsp’, 同樣被DispatcherServlet處理, 之後就發出了/WEB-INF/jsp/test.jsp這樣的轉發請求, 自然會找不到handler, No mapping. 所以這樣的請求會一直為404.

這裡DispatcherServlet為什麼會繼續攔截/WEB-INF/jsp/test.jsp?

這裡DispatcherServlet配置為: 按照servlet的匹配規則,則路徑匹配(/*)會優先於擴充套件匹配(*.jsp, *.jspx),導致對jsp的請求會被DispatcherServlet攔截掉。

*.jsp, *.jspx所對應的servlet為org.apache.jasper.servlet.JspServlet, 位於tomcat_home/conf/web.xml中, 下文會講到. 對於servlet的匹配規則和順序不清楚的同學, 可以參看這篇博文

將url-pattern配置為 ‘/’ 看一下控制檯的日誌, 對比一下

請求路徑為: /test 結果: 正確找到view, 並進行渲染.

DispatcherServlet]-[DEBUG] DispatcherServlet with name ‘springmvc’ processing GET request for [/test] RequestMappingHandlerMapping]-[DEBUG] Looking up handler method for path /test RequestMappingHandlerMapping]-[DEBUG] Returning handler method [public java.lang.String com.taotao.sso.controller.Test.test()] DefaultListableBeanFactory]-[DEBUG] Invoking afterPropertiesSet() on bean with name ‘test’ DispatcherServlet]-[DEBUG] Rendering view [org.springframework.web.servlet.view.InternalResourceView: name ‘test’; URL [/WEB-INF/jsp/test.jsp]] in DispatcherServlet with name ‘springmvc’ InternalResourceView]-[DEBUG] Forwarding to resource [/WEB-INF/jsp/test.jsp] in InternalResourceView ‘test’ DispatcherServlet]-[DEBUG] Successfully completed request

看到這裡的日誌, 很多同學就奇怪了, 這裡DispatcherServlet並不攔截轉發的請求[/WEB-INF/jsp/test.jsp], 就直接找到了view.

DispatcherServlet配置為’/’, 為什麼不攔截*.jsp, *.jspx.的請求?

前面說的當DispatcherServlet配置為’/’, 將會覆蓋default servlet, 將會處理所有其他Servlet都不處理的訪問請求. 所以這裡不攔截攔截.jsp, .jspx.的請求, 一定有其他地方攔截了該請求, 但是仔細查詢web.xml並沒有發現其他的servlet啊!那一定是在容器中定義的啦~果不其然, 在%TOMCAT_HOME%/conf/web.xml中繼承過來的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>

從該web.xml也看到DefaultServlet的定義了(檔案中總共就定義了這兩個servlet)

     <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>

這也就是為什麼我們直接訪問不在WEB-INF的jsp, 可以直接找到並解析的原因了. 我們將test.jsp拷貝一份到webapp下, 直接訪問/test.jsp, 訪問到jsp中的內容了.並未出現404, 從而驗證了我們的猜想.