第十章:Spring MVC的配置訪問靜態資源
Spring MVC的配置訪問靜態資源的三種方案
訪問靜態資源出現問題(找不到靜態檔案報404)的原因:
在web.xml中配置DispatcherServlet是將url-pattern配置了【/】,該配置攔截了所有的請求,同時對*.js,*.jpg的訪問也就被攔截了。
但是在Controller中又找不到相對應的靜態資源處理器,所以出錯。
如果你的DispatcherServlet攔截 *.do這樣的URL,就不存在訪問不到靜態資源的問題。
問題原因:罪魁禍首是web.xml下對spring的DispatcherServlet請求url對映的配置,原配置如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 5 version="4.0"> 6 <servlet> 7 <servlet-name>dispatcher</servlet-name> 8 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 9 <init-param> 10 <param-name>contextConfigLocation</param-name> 11 <param-value>classpath:dispatcher-servlet.xml</param-value> 12 </init-param> 13 <load-on-startup>1</load-on-startup> 14 </servlet> 15 <servlet-mapping> 16 <servlet-name>dispatcher</servlet-name> 17 <url-pattern>/</url-pattern> 18 </servlet-mapping> 19 </web-app>
下面是查詢到的三種解決方案:
方案一:啟用Tomcat的defaultServlet來處理靜態檔案
因為在tomcat的web.xml中有下面的程式碼:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 5 http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 6 version="3.1"> 7 8 <servlet> 9 <servlet-name>default</servlet-name> 10 <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> 11 <init-param> 12 <param-name>debug</param-name> 13 <param-value>0</param-value> 14 </init-param> 15 <init-param> 16 <param-name>listings</param-name> 17 <param-value>false</param-value> 18 </init-param> 19 <load-on-startup>1</load-on-startup> 20 </servlet> 21 22 <servlet> 23 <servlet-name>jsp</servlet-name> 24 <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> 25 <init-param> 26 <param-name>fork</param-name> 27 <param-value>false</param-value> 28 </init-param> 29 <init-param> 30 <param-name>xpoweredBy</param-name> 31 <param-value>false</param-value> 32 </init-param> 33 <load-on-startup>3</load-on-startup> 34 </servlet> 35 36 <!-- The mapping for the default servlet --> 37 <servlet-mapping> 38 <servlet-name>default</servlet-name> 39 <url-pattern>/</url-pattern> 40 </servlet-mapping> 41 42 <!-- The mappings for the JSP servlet --> 43 <servlet-mapping> 44 <servlet-name>jsp</servlet-name> 45 <url-pattern>*.jsp</url-pattern> 46 <url-pattern>*.jspx</url-pattern> 47 </servlet-mapping> 48 </web-app>
所以我們可以在web.xml中配置如下:要寫在DispatcherServlet的前面, 讓defaultServlet先攔截,這個就不會進入dispatcher了,我想效能是最好的吧。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 5 version="4.0"> 6 <!--處理靜態資源的第一種方法: 7 啟用Tomcat的defaultServlet來處理靜態檔案 8 --> 9 <servlet-mapping> 10 <servlet-name>default</servlet-name> 11 <url-pattern>*.jpg</url-pattern> 12 </servlet-mapping> 13 <servlet-mapping> 14 <servlet-name>default</servlet-name> 15 <url-pattern>*.js</url-pattern> 16 </servlet-mapping> 17 <servlet-mapping> 18 <servlet-name>default</servlet-name> 19 <url-pattern>*.css</url-pattern> 20 </servlet-mapping> 21 22 <servlet> 23 <servlet-name>dispatcher</servlet-name> 24 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 25 <init-param> 26 <param-name>contextConfigLocation</param-name> 27 <param-value>classpath:dispatcher-servlet.xml</param-value> 28 </init-param> 29 <load-on-startup>1</load-on-startup> 30 </servlet> 31 <servlet-mapping> 32 <servlet-name>dispatcher</servlet-name> 33 <url-pattern>/</url-pattern> 34 </servlet-mapping> 35 </web-app>
補充:預設 Servlet的名字
Tomcat, Jetty, JBoss, and GlassFish 預設 Servlet的名字 -- "default"
Google App Engine 預設 Servlet的名字 -- "_ah_default"
Resin 預設 Servlet的名字 -- "resin-file"
WebLogic 預設 Servlet的名字 -- "FileServlet"
WebSphere 預設 Servlet的名字 -- "SimpleFileServlet"
方案二: 在spring3.0.4以後版本提供了mvc:resources
mvc:resources 的使用方法:<mvc:resources mapping="" location="" />+<mvc:annotation-driven>
1 <!-- 靜態資源對映 --> 2 <mvc:resources mapping="/static/**" location="/static/" cache-period="31536000"/> 3 4 <mvc:annotation-driven />location:指location指定的目錄不要攔截,直接請求
mapping:指在static目錄下的所有檔案(**代表所有檔案)
cache-period:設定靜態資源在客戶端瀏覽器中的快取有效時間
該配置意思就是在根目錄下static的所有檔案不會被
DispatcherServlet
攔截,直接訪問,當做靜態資源交給Servlet處理
如果出現下面的錯誤,可能是沒有配置<mvc:annotation-driven />的原因。
頁面報404
控制檯:報錯WARNING: No mapping found for HTTP request with URI [/mvc/user/findUser/lisi/770] in DispatcherServlet with name 'springMVC'
<mvc:annotation-driven />該配置作用是註冊RequestMappingHandlerMapping
與RequestMappingHandlerAdapter
兩個Bean,這是Spring MVC為@Controller
分發請求所必需的,
並且提供了資料繫結支援,@NumberFormatannotation
支援,@DateTimeFormat
支援,@Valid
支援讀寫XML的支援(JAXB)和讀寫JSON的支援(預設Jackson)等功能
方案三 ,使用<mvc:default-servlet-handler/>+<mvc:annotation-driven>
<mvc:default-servlet-handler/>會把 "/**" url,註冊到 SimpleUrlHandlerMapping 的 urlMap 中,
把對靜態資源的訪問由 HandlerMapping 轉到 org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler 處理並返回.
DefaultServletHttpRequestHandler 使用就是各個 Servlet 容器自己的預設 Servlet.
補充說明:多個HandlerMapping的執行順序問題:
DefaultAnnotationHandlerMapping 的 order 屬性值是:0
<mvc:resources/ >自動註冊的 SimpleUrlHandlerMapping 的 order 屬性值是: 2147483646
<mvc:default-servlet-handler/>自動註冊的 SimpleUrlHandlerMapping 的 order 屬性值是:2147483647
spring 會先執行 order 值比較小的。當訪問一個 a.jpg 圖片檔案時,先通過 DefaultAnnotationHandlerMapping 來找處理器,一定是找不到的,我們沒有叫 a.jpg 的 Action。
再按 order 值升序找,由於最後一個 SimpleUrlHandlerMapping 是匹配 "/**" 的,所以一定會匹配上,再響應圖片。