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