Spring MVC中處理靜態資源的多種方法
處理靜態資源,我想這可能是框架搭建完成之后Web開發的”頭等大事“了。
因為一個網站的顯示肯定會依賴各種資源:腳本、圖片等,那么問題來了,如何在頁面中請求這些靜態資源呢?
還記得Spring MVC中的DispatcherServlet嗎?它是Spring MVC中的前置控制器,若配置的攔截路徑為“/”,那么所有的請求都將被它攔截。對靜態資源的訪問也屬于一個請求,那么也會被它攔截,然后進入它的匹配流 程,我們知道它是根據HandlerMapping的配置來匹配的。而對于靜態資源來說,默認的Spring MVC是沒有注冊匹配規則的,此時若你去請求一個靜態資源,則會報404錯誤。
如何處理靜態資源的請求呢?
根據上面介紹的,我們可以配置一個處理靜態資源的HandlerMapping
<bean id="resourceHttpRequestHandler" class="org.springframework.web.servlet.resource.ResourceHttpRequestHandler">
<property name="locations" value="classpath:/META-INF/resources/"></property>
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/resources/**">resourceHttpRequestHandler</prop>
</props>
</property>
</bean> 其中ResourceHttpRequestHandler就是處理靜態資源請求的類,當然如果你愿意,也可以自己嘗試寫一個。
不過現在這樣自己寫SimpleUrlHandlerMapping比較少了吧,項目中都是采用的注解配置,只不過是將匹配關系放到注解上
另外,還可以使用mvc命名空間的resources標簽來配置
<mvc:resources mapping="/resources/**" location="/resources/" />
本質上也是把ResourceHttpRequestHandler注冊到SimpleUrlHandlerMapping上。
還有別的方法來處理靜態資源請求嗎?
Spring MVC還提供了一個配置項:mvc:default-servlet-handler
這個標簽對于匹配規則為"/"的DispatcherServlet才生效(因為別的匹配規則一般也不會攔截靜態資源)。它會為DefaultServletHttpRequestHandler配置上"/**"的攔截規則和最低的匹配優先級。
DefaultServletHttpRequestHandler處理請求時會將其全部轉發到容器的DefaultServlet上。因此它在 HandlerMapping必須是優先級最低的。如果你使用<mvc:annotation-driven>或你使用了自定義的 HandlerMapping實例,確保它們的order值比DefaultServletHttpRequestHandler小 (Integer.MAX)。
另外需要注意的是,這里尋找容器的DefaultServlet是用名字而不是路徑。所以首先要搞清楚容器的DefaultServlet的名字, 當然一般主流容器的名字是無需指定的,比如Tomcat, Jetty, JBoss, and GlassFish等。若非常用容器,則可能需要手動指定:
<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>
這種方式也是依賴于容器的DefaultServlet的,那么我們是否能直接用容器的DefaultServlet來處理靜態資源請求,而不是這樣先通過Spring MVC來轉發呢?(相比性能上會好很多),答案是肯定的。
比如我們將資源文件都放在resouces目錄下,那么只需要在web.xml中配置:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/resource/*</url-pattern>
</servlet-mapping> 并將它放在所有Servlet的最前面(為了讓它最先匹配),這樣的話性能上應該比較好
但是這樣還會有個問題,就是無法訪問到classpath下的資源文件,看了tomcat的DefaultServlet的配置項,似乎也沒有可以指定目錄的地方。
所以,綜上所述,性能最好的應該是直接利用容器的DefaultServlet,讓它最先攔截靜態資源請求,這樣就避免了后續的轉發等操作,提高了 性能,但是無法訪問classpath下的資源文件。而通過mvc:resources標簽可以簡單配置匹配規則和資源文件路徑,應該說是最簡單快捷的一 種方式,當然這大概也是mvc命名空間設計的初衷。
另外,若想結合兩者的話,自己倒是可以嘗試寫一個Servlet來處理,不過估計有難度且麻煩。