1. 程式人生 > >SpringMVC靜態資源訪問

SpringMVC靜態資源訪問

 一,SpringMVC靜態資源攔截問題

SpringMVC的工作機制是:來自瀏覽器的所有訪問都會被前端控制器(DispatcherServlet)捕獲,然後前端控制器把請求轉交給處理器對映(HandlerMapping),HandlerMapping為請求分配對應的控制器(Controller)進行請求處理。

<servlet>
        <servlet-name>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

通過上面的配置,DispatcherServlet將捕獲Web容器所有請求,包括靜態資源請求。

通過學習HTTP協議我們知道,瀏覽器訪問伺服器的一個頁面,實際上是包含了很多次請求的。除了請求頁面本身,頁面上的圖片,js等靜態資源也是通過請求資源在伺服器上的相對地址實現的。但是SpringMVC的環境下,對靜態資源的請求也會被前端控制器捕獲,並轉交給處理器對映。由於我們的程式碼中不會有對應的控制器處理請求,因此請求無法被相應,導致網頁無法載入靜態資源。

二,解決靜態資源攔截問題

  • 方法一:採用<mvc:default-servlet-handler default-servlet-name="default"/>

在Springmvc-servlet.xml中配置<mvc:default-servlet-handler>後,會在SpringMVC上下文中定義一個org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它會像一個檢查員,對進入DispatcherServlet的URL進行篩查,如果發現是靜態資源請求,就將該請求轉由Web伺服器(Tomcat)預設的Servlet處理,如果不是靜態資源請求,才由DispatcherServlet繼續處理。

一般Web應用伺服器預設的servlet名稱是“default”,因此DefaultServletHttpRequestHandler可以找到它。如果你的Web應用伺服器的預設servlet名稱不是default,則需要通過default-servlet-name屬性顯式指定:

<mvc:default-servlet-handler default-servlet-name="Web伺服器使用的Servlet名稱" />

這樣的方法簡便而有效,但卻使得靜態資源的訪問繞過了SpringMVC,使得我們的很多攔截、資訊驗證等功能失效。因此並不適用於所有場景。下面介紹第二種方法。

  • 方法二:採用<mvc:resources> 

<mvc:resources>,由springMVC框架自己處理靜態資源,並可以新增一些有用的附加功能。

首先,<mvc:resources />允許靜態資源放在任何地方,如WEB-INF目錄下、類路徑下等,你甚至可以將JavaScript等靜態檔案打到JAR包中。通過location屬性指定靜態資源的位置,由於location屬性是Resources型別,因此可以使用諸如"classpath:"等的資源字首指定資源位置。傳統Web容器的靜態資源只能放在Web容器的根路徑下,<mvc:resources />完全打破了這個限制。

其次,<mvc:resources />依據當前著名的Page Speed、YSlow等瀏覽器優化原則對靜態資源提供優化。你可以通過cacheSeconds屬性指定靜態資源在瀏覽器端的快取時間,一般可將該時間設定為一年,以充分利用瀏覽器端的快取。在輸出靜態資源時,會根據配置設定好響應報文頭的Expires 和 Cache-Control值。

在接收到靜態資源的獲取請求時,會檢查請求頭的Last-Modified值,如果靜態資源沒有發生變化,則直接返回303相應狀態碼,提示客戶端使用瀏覽器快取的資料,而非將靜態資源的內容輸出到客戶端,以充分節省頻寬,提高程式效能。

例如,在springMVC-servlet中新增如下配置:

<mvc:resources location="/,classpath:/META-INF/publicResources/" mapping="/resources/**"/>

以上配置將Web根路徑"/"及類路徑下 /META-INF/publicResources/ 的目錄對映為/resources路徑。假設Web根路徑下擁有images、js這兩個資源目錄,在images下面有bg.gif圖片,在js下面有test.js檔案,則可以通過 /resources/images/bg.gif 和 /resources/js/test.js 訪問這二個靜態資源。

假設WebRoot還擁有images/bg1.gif 及 js/test1.js,則也可以在網頁中通過 /resources/images/bg1.gif 及 /resources/js/test1.js 進行引用。

再比如:

以上配置,將/img/的靜態資源路徑,對映為/img的資源路徑路徑。也就是可以直接把/img路徑當作靜態路徑來使用了。上例中,設定publicResources檔案目錄的方法,是更通用的統一管理靜態資源的方法。

在JSP頁面中:

<img src="/img/test.JPG" />
<img src="/img/1/test2.JPG" />

都可以訪問到圖片。