1. 程式人生 > 實用技巧 >第十章:Spring MVC的配置訪問靜態資源

第十章: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 />

該配置作用是註冊RequestMappingHandlerMappingRequestMappingHandlerAdapter兩個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 是匹配 "/**" 的,所以一定會匹配上,再響應圖片。