Spring?MVC和springboot靜態(tài)資源處理問題
1、springmvc
優(yōu)雅REST風格的資源URL不希望帶 .html 或 .do 等后綴.由于早期的Spring MVC不能很好地處理靜態(tài)資源,所以在web.xml中配置DispatcherServlet的請求映射,往往使用 *.do 、 *.xhtml等方式。這就決定了請求URL必須是一個帶后綴的URL,而無法采用真正的REST風格的URL。
如果將DispatcherServlet請求映射配置為"/",則Spring MVC將捕獲Web容器所有的請求,包括靜態(tài)資源的請求,Spring MVC會將它們當成一個普通請求處理,因此找不到對應處理器將導致錯誤。
如何讓Spring框架能夠捕獲所有URL的請求,同時又將靜態(tài)資源的請求轉(zhuǎn)由Web容器處理,是可將DispatcherServlet的請求映射配置為"/"的前提。由于REST是Spring3.0最重要的功能之一,所以Spring團隊很看重靜態(tài)資源處理這項任務,給出了堪稱經(jīng)典的兩種解決方案。
先調(diào)整web.xml中的DispatcherServlet的配置,使其可以捕獲所有的請求:
<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>通過上面url-pattern的配置,所有URL請求都將被Spring MVC的DispatcherServlet截獲。
1)采用<mvc:default-servlet-handler />
在springMVC-servlet.xml中配置<mvc:default-servlet-handler />后,會在Spring MVC上下文中定義一個org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它會像一個檢查員,對進入DispatcherServlet的URL進行篩查,如果發(fā)現(xiàn)是靜態(tài)資源的請求,就將該請求轉(zhuǎn)由Web應用服務器默認的Servlet處理,如果不是靜態(tài)資源的請求,才由DispatcherServlet繼續(xù)處理。
一般Web應用服務器默認的Servlet名稱是"default",因此DefaultServletHttpRequestHandler可以找到它。如果你所有的Web應用服務器的默認Servlet名稱不是"default",則需要通過default-servlet-name屬性顯示指定:
<mvc:default-servlet-handler default-servlet-name="所使用的Web服務器默認使用的Servlet名稱" />
2)采用<mvc:resources />
<mvc:default-servlet-handler />將靜態(tài)資源的處理經(jīng)由Spring MVC框架交回Web應用服務器處理。而<mvc:resources />更進一步,由Spring MVC框架自己處理靜態(tài)資源,并添加一些有用的附加值功能。
首先,<mvc:resources />允許靜態(tài)資源放在任何地方,如WEB-INF目錄下、類路徑下等,你甚至可以將JavaScript等靜態(tài)文件打到JAR包中。通過location屬性指定靜態(tài)資源的位置,由于location屬性是Resources類型,因此可以使用諸如"classpath:"等的資源前綴指定資源位置。傳統(tǒng)Web容器的靜態(tài)資源只能放在Web容器的根路徑下,<mvc:resources />完全打破了這個限制。
其次,<mvc:resources />依據(jù)當前著名的Page Speed、YSlow等瀏覽器優(yōu)化原則對靜態(tài)資源提供優(yōu)化。你可以通過cacheSeconds屬性指定靜態(tài)資源在瀏覽器端的緩存時間,一般可將該時間設置為一年,以充分利用瀏覽器端的緩存。在輸出靜態(tài)資源時,會根據(jù)配置設置好響應報文頭的Expires 和 Cache-Control值。
在接收到靜態(tài)資源的獲取請求時,會檢查請求頭的Last-Modified值,如果靜態(tài)資源沒有發(fā)生變化,則直接返回303相應狀態(tài)碼,提示客戶端使用瀏覽器緩存的數(shù)據(jù),而非將靜態(tài)資源的內(nèi)容輸出到客戶端,以充分節(jié)省帶寬,提高程序性能。
在springMVC-servlet中添加如下配置:
<mvc:resources location="/,classpath:/META-INF/publicResources/" mapping="/resources/**"/>
以上配置將Web根路徑"/"及類路徑下 /META-INF/publicResources/ 的目錄映射為/resources路徑。假設Web根路徑下?lián)碛衖mages、js這兩個資源目錄,在images下面有bg.gif圖片,在js下面有test.js文件,則可以通過 /resources/images/bg.gif 和 /resources/js/test.js 訪問這二個靜態(tài)資源。
示例:
<servlet-mapping> <servlet-name>springMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:resources mapping="/javascript/**" location="/static_resources/javascript/"/>
<mvc:resources mapping="/styles/**" location="/static_resources/css/"/>
<mvc:resources mapping="/images/**" location="/static_resources/images/"/>
<mvc:default-servlet-handler />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans> 這里可以看到我所有的頁面引用到/styles/**的資源都從/static_resources/css里面進行查找。
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core"%> <HTML> <HEAD> <TITLE> ABCDEFG </TITLE> <link type="text/css" rel="stylesheet" href="<c:url value='/styles/siteboard.css'/>"> ... ... ...
這樣引用靜態(tài)資源的訪問不會類似CONTROLLER一樣被攔截,區(qū)分出關注的資源的訪問,一般我們在springMVC里面的攔截都會配置為"/",攔截所有的。
2、springboot
我們之前創(chuàng)建的web工程的時候,直接把靜態(tài)資源,比如html文件、圖片等放在src/main/webapp目錄下,在瀏覽器中是直接可以訪問到這些靜態(tài)資源的。
那么對于springboot來說該如何處理這些資源文件呢?
1)webapp目錄下的資源文件
在創(chuàng)建spring boot工程中,默認是沒有創(chuàng)建webapp目錄的,如果要把靜態(tài)資源放在webapp目錄下,需要手動在src/main/目錄下創(chuàng)建一個webapp目錄,然后把靜態(tài)資源放在該目錄下就可以,此時從瀏覽器中是可以直接訪問到spring boot工程中的這些資源的。

如上圖,我們在瀏覽器上通過http://localhost:8080/js/jquery-1.11.3.min.js 即可訪問到。

2)springboot默認的靜態(tài)資源目錄
在spring boot工程中,我們沒必要去創(chuàng)建webapp,因為spring boot已經(jīng)為我們創(chuàng)建好了默認的目錄,只需要把靜態(tài)資源放在默認目錄下,瀏覽器就可以直接訪問到。
默認的靜態(tài)資源目錄配置在 spring-boot-autoconfigure jar包下的org.springframework.boot.autoconfigure.web包下ResourceProperties類,下面是源碼:
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/" };從源碼中可以看出,靜態(tài)資源存放的默認位置由4個目錄,分別在根目錄,即 /src/main/resources/ 目錄下的 /META-INF/resources/ 、 /resources/ 、 /static/ 、 /public/ 目錄下(優(yōu)先級也是這個順序)。

我們在瀏覽器上輸入http://localhost:8080/1.png,即可訪問到該圖片

3)自定義靜態(tài)資源默認存儲位置
spring boot工程默認情況下,瀏覽器可以直接訪問到4個目錄下的靜態(tài)資源,但是若想瀏覽器訪問自定義的目錄,我們也可以手動指定。
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/img/**")
.addResourceLocations("classpath:/imgs/");
super.addResourceHandlers(registry);
}
}@Configuration標識一個配置類,WebMvcConfigurerAdapter是Spring提供的一個配置mvc的適配器,里面有很多配置的方法,addResourceHandlers就是專門處理靜態(tài)資源的方法。這里表示增加了一個img這樣的資源匹配路徑,目錄在classpath:/imgs下。
注意:文件目錄也可以外部額路徑,如:registry.addResourceHandler("/img/**").addResourceLocations("file:E:/imgs/");

這時在瀏覽器上輸入:http://localhost:8080/img/abc.png 即可訪問到

4)修改配置文件
同方式3)類似,我們可以在springboot的application.propertes配置文件中修改資源文件的訪問匹配方式和文件路徑。
注意,這個配置會覆蓋Spring boot默認的靜態(tài)資源目錄,例如如果按示例中配置,則無法再訪問static、public、resources等目錄下的資源了。
靜態(tài)資源,例如HTML文件、JS文件,設計到的Spring Boot配置有兩項:
- spring.mvc.static-path-pattern
- spring.resources.static-locations
1)spring.mvc.static-path-pattern:
代表的含義是我們應該以什么樣的路徑來訪問靜態(tài)資源,換句話說,只有靜態(tài)資源滿足什么樣的匹配條件,Spring Boot才會處理靜態(tài)資源請求。
類似于springmvc中處理靜態(tài)資源的mapping標簽,以官方配置為例:
# 這表示只有靜態(tài)資源的訪問路徑為/resources/**時,才會當作靜態(tài)資源處理請求 spring.mvc.static-path-pattern=/resources/**,
假定采用默認的配置端口,那么只有請求地址類似于“http://localhost:8080/resources/jquery.js”時,Spring Boot才會處理此請求,處理方式是將根據(jù)模式匹配后的文件名查找本地文件,那么應該在什么地方查找本地文件呢?這就是“spring.resources.static-locations”的作用了。
2)spring.resources.static-locations:
用于告訴Spring Boot應該在何處查找靜態(tài)資源文件,這是一個列表性的配置,查找文件時會依賴于配置的先后順序依次進行。
類似于springmvc中的location標簽,默認的官方配置如下:
spring.resources.static-locations=classpath:/static,classpath:/public,classpath:/resources,classpath:/META-INF/resources
繼續(xù)以上面的請求地址為例,“http://localhost:8080/resources/jquery.js”就會在上述的四個路徑中依次查找是否存在“jquery.js”文件,如果找到了,則返回此文件,否則返回404錯誤。
等價于:
<mvc:resources mapping="/resources/**" location="/public-resources/">
<mvc:cache-control max-age="3600" cache-public="true"/>
</mvc:resources>總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
淺談Java循環(huán)中的For和For-each哪個更快
本文主要介紹了淺談Java循環(huán)中的For和For-each哪個更快,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-08-08

