前言
對于springmvc中前端控制器url-pattern配置, 看了很多博客, 發(fā)現(xiàn)好多人理解都是錯(cuò)誤, 并不清楚會攔截什么路徑的請求, 有點(diǎn)小的細(xì)節(jié)并不被大家所關(guān)注.
DispatcherServlet常見的配置
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation配置springmvc加載的配置文件(配置處理器映射器,適配器等等)
如果不配置,默認(rèn)加載的是/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' , 以指定后綴結(jié)尾的請求都交由DispatcherServlet處理
- 第二種:
'/' 將會覆蓋容器的default servlet, 凡是在web.xml文件中找不到匹配的URL,,它們的訪問請求都將交給該Servlet處理(靜態(tài)資源也將會攔截). 所以web.xml沒有配置其他特殊路徑的servlet, 基本上所有的請求都交由DispatcherServlet處理.
關(guān)于什么是default servlet, 可以參考我之前的博文.
- 第三種:
'/*' 錯(cuò)誤的配置,會攔截*.jsp, *.jspx 的請求, 使用這種配置最終要轉(zhuǎn)發(fā)到一個(gè)JSP頁面,仍然會由DispatcherServlet, 解析jsp地址, 不能根據(jù)jsp頁面找到handler, 會報(bào)錯(cuò)
對于第一種擴(kuò)展匹配, 是最簡單的. 也是使用最簡單的了.但是現(xiàn)在如此流行restful風(fēng)格的URL, 這種帶小尾巴的URL, 還是有點(diǎn)low的.
第二種配置使用/ , 通過該配置是可以實(shí)現(xiàn)rustful風(fēng)格的URL的.
url-pattern配置為 ‘/*’, 為什么是錯(cuò)誤的?
為了驗(yàn)證這種配置, 我做了一個(gè)簡單的測試
在webapp/WEB-INF/jsp下新建test.jsp, controller中只做轉(zhuǎn)發(fā).
@Controller
@RequestMapping("")
public class Test {
@RequestMapping("/test")
public String test() {
return "test";
}
}
測試請求路徑: /test
結(jié)果: 執(zhí)行該請求后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轉(zhuǎn)發(fā)請求’/WEB-INF/jsp/test.jsp’, 同樣被DispatcherServlet處理, 之后就發(fā)出了/WEB-INF/jsp/test.jsp這樣的轉(zhuǎn)發(fā)請求, 自然會找不到handler, No mapping. 所以這樣的請求會一直為404.
這里DispatcherServlet為什么會繼續(xù)攔截/WEB-INF/jsp/test.jsp?
這里DispatcherServlet配置為:
按照servlet的匹配規(guī)則,,則路徑匹配(/* )會優(yōu)先于擴(kuò)展匹配(*.jsp, *.jspx ),導(dǎo)致對jsp的請求會被DispatcherServlet攔截掉。
*.jsp, *.jspx 所對應(yīng)的servlet為org.apache.jasper.servlet.JspServlet , 位于tomcat_home/conf/web.xml中, 下文會講到.
對于servlet的匹配規(guī)則和順序不清楚的同學(xué), 可以參看這篇博文
將url-pattern配置為 ‘/’ 看一下控制臺的日志, 對比一下
請求路徑為: /test
結(jié)果: 正確找到view, 并進(jìn)行渲染.
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
看到這里的日志, 很多同學(xué)就奇怪了, 這里DispatcherServlet并不攔截轉(zhuǎn)發(fā)的請求[/WEB-INF/jsp/test.jsp], 就直接找到了view.
DispatcherServlet配置為’/’, 為什么不攔截*.jsp, *.jspx.的請求?
前面說的當(dāng)DispatcherServlet配置為’/’, 將會覆蓋default servlet , 將會處理所有其他Servlet都不處理的訪問請求. 所以這里不攔截?cái)r截.jsp, .jspx.的請求, 一定有其他地方攔截了該請求, 但是仔細(xì)查找web.xml并沒有發(fā)現(xiàn)其他的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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
從該web.xml也看到DefaultServlet 的定義了(文件中總共就定義了這兩個(gè)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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
這也就是為什么我們直接訪問不在WEB-INF的jsp, 可以直接找到并解析的原因了.
我們將test.jsp拷貝一份到webapp下, 直接訪問/test.jsp, 訪問到j(luò)sp中的內(nèi)容了.并未出現(xiàn)404, 從而驗(yàn)證了我們的猜想.
|