Spring?MVC和springboot靜態(tài)資源處理問(wèn)題
1、springmvc
優(yōu)雅REST風(fēng)格的資源URL不希望帶 .html 或 .do 等后綴.由于早期的Spring MVC不能很好地處理靜態(tài)資源,所以在web.xml中配置DispatcherServlet的請(qǐng)求映射,往往使用 *.do 、 *.xhtml等方式。這就決定了請(qǐng)求URL必須是一個(gè)帶后綴的URL,而無(wú)法采用真正的REST風(fēng)格的URL。
如果將DispatcherServlet請(qǐng)求映射配置為"/",則Spring MVC將捕獲Web容器所有的請(qǐng)求,包括靜態(tài)資源的請(qǐng)求,Spring MVC會(huì)將它們當(dāng)成一個(gè)普通請(qǐng)求處理,因此找不到對(duì)應(yīng)處理器將導(dǎo)致錯(cuò)誤。
如何讓Spring框架能夠捕獲所有URL的請(qǐng)求,同時(shí)又將靜態(tài)資源的請(qǐng)求轉(zhuǎn)由Web容器處理,是可將DispatcherServlet的請(qǐng)求映射配置為"/"的前提。由于REST是Spring3.0最重要的功能之一,所以Spring團(tuán)隊(duì)很看重靜態(tài)資源處理這項(xiàng)任務(wù),給出了堪稱經(jīng)典的兩種解決方案。
先調(diào)整web.xml中的DispatcherServlet的配置,使其可以捕獲所有的請(qǐng)求:
<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>
通過(guò)上面url-pattern的配置,所有URL請(qǐng)求都將被Spring MVC的DispatcherServlet截獲。
1)采用<mvc:default-servlet-handler />
在springMVC-servlet.xml中配置<mvc:default-servlet-handler />后,會(huì)在Spring MVC上下文中定義一個(gè)org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它會(huì)像一個(gè)檢查員,對(duì)進(jìn)入DispatcherServlet的URL進(jìn)行篩查,如果發(fā)現(xiàn)是靜態(tài)資源的請(qǐng)求,就將該請(qǐng)求轉(zhuǎn)由Web應(yīng)用服務(wù)器默認(rèn)的Servlet處理,如果不是靜態(tài)資源的請(qǐng)求,才由DispatcherServlet繼續(xù)處理。
一般Web應(yīng)用服務(wù)器默認(rèn)的Servlet名稱是"default",因此DefaultServletHttpRequestHandler可以找到它。如果你所有的Web應(yīng)用服務(wù)器的默認(rèn)Servlet名稱不是"default",則需要通過(guò)default-servlet-name屬性顯示指定:
<mvc:default-servlet-handler default-servlet-name="所使用的Web服務(wù)器默認(rèn)使用的Servlet名稱" />
2)采用<mvc:resources />
<mvc:default-servlet-handler />將靜態(tài)資源的處理經(jīng)由Spring MVC框架交回Web應(yīng)用服務(wù)器處理。而<mvc:resources />更進(jìn)一步,由Spring MVC框架自己處理靜態(tài)資源,并添加一些有用的附加值功能。
首先,<mvc:resources />允許靜態(tài)資源放在任何地方,如WEB-INF目錄下、類路徑下等,你甚至可以將JavaScript等靜態(tài)文件打到JAR包中。通過(guò)location屬性指定靜態(tài)資源的位置,由于location屬性是Resources類型,因此可以使用諸如"classpath:"等的資源前綴指定資源位置。傳統(tǒng)Web容器的靜態(tài)資源只能放在Web容器的根路徑下,<mvc:resources />完全打破了這個(gè)限制。
其次,<mvc:resources />依據(jù)當(dāng)前著名的Page Speed、YSlow等瀏覽器優(yōu)化原則對(duì)靜態(tài)資源提供優(yōu)化。你可以通過(guò)cacheSeconds屬性指定靜態(tài)資源在瀏覽器端的緩存時(shí)間,一般可將該時(shí)間設(shè)置為一年,以充分利用瀏覽器端的緩存。在輸出靜態(tài)資源時(shí),會(huì)根據(jù)配置設(shè)置好響應(yīng)報(bào)文頭的Expires 和 Cache-Control值。
在接收到靜態(tài)資源的獲取請(qǐng)求時(shí),會(huì)檢查請(qǐng)求頭的Last-Modified值,如果靜態(tài)資源沒有發(fā)生變化,則直接返回303相應(yīng)狀態(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路徑。假設(shè)Web根路徑下?lián)碛衖mages、js這兩個(gè)資源目錄,在images下面有bg.gif圖片,在js下面有test.js文件,則可以通過(guò) /resources/images/bg.gif 和 /resources/js/test.js 訪問(wèn)這二個(gè)靜態(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>
這里可以看到我所有的頁(yè)面引用到/styles/**的資源都從/static_resources/css里面進(jìn)行查找。
<%@ 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)資源的訪問(wèn)不會(huì)類似CONTROLLER一樣被攔截,區(qū)分出關(guān)注的資源的訪問(wèn),一般我們?cè)趕pringMVC里面的攔截都會(huì)配置為"/",攔截所有的。
2、springboot
我們之前創(chuàng)建的web工程的時(shí)候,直接把靜態(tài)資源,比如html文件、圖片等放在src/main/webapp目錄下,在瀏覽器中是直接可以訪問(wèn)到這些靜態(tài)資源的。
那么對(duì)于springboot來(lái)說(shuō)該如何處理這些資源文件呢?
1)webapp目錄下的資源文件
在創(chuàng)建spring boot工程中,默認(rèn)是沒有創(chuàng)建webapp目錄的,如果要把靜態(tài)資源放在webapp目錄下,需要手動(dòng)在src/main/目錄下創(chuàng)建一個(gè)webapp目錄,然后把靜態(tài)資源放在該目錄下就可以,此時(shí)從瀏覽器中是可以直接訪問(wèn)到spring boot工程中的這些資源的。
如上圖,我們?cè)跒g覽器上通過(guò)http://localhost:8080/js/jquery-1.11.3.min.js 即可訪問(wèn)到。
2)springboot默認(rèn)的靜態(tài)資源目錄
在spring boot工程中,我們沒必要去創(chuàng)建webapp,因?yàn)閟pring boot已經(jīng)為我們創(chuàng)建好了默認(rèn)的目錄,只需要把靜態(tài)資源放在默認(rèn)目錄下,瀏覽器就可以直接訪問(wèn)到。
默認(rèn)的靜態(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)資源存放的默認(rèn)位置由4個(gè)目錄,分別在根目錄,即 /src/main/resources/
目錄下的 /META-INF/resources/
、 /resources/
、 /static/
、 /public/
目錄下(優(yōu)先級(jí)也是這個(gè)順序)。
我們?cè)跒g覽器上輸入http://localhost:8080/1.png,即可訪問(wèn)到該圖片
3)自定義靜態(tài)資源默認(rèn)存儲(chǔ)位置
spring boot工程默認(rèn)情況下,瀏覽器可以直接訪問(wèn)到4個(gè)目錄下的靜態(tài)資源,但是若想瀏覽器訪問(wèn)自定義的目錄,我們也可以手動(dòng)指定。
@Configuration public class MyMvcConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/img/**") .addResourceLocations("classpath:/imgs/"); super.addResourceHandlers(registry); } }
@Configuration標(biāo)識(shí)一個(gè)配置類,WebMvcConfigurerAdapter是Spring提供的一個(gè)配置mvc的適配器,里面有很多配置的方法,addResourceHandlers就是專門處理靜態(tài)資源的方法。這里表示增加了一個(gè)img這樣的資源匹配路徑,目錄在classpath:/imgs下。
注意:文件目錄也可以外部額路徑,如:registry.addResourceHandler("/img/**").addResourceLocations("file:E:/imgs/");
這時(shí)在瀏覽器上輸入:http://localhost:8080/img/abc.png 即可訪問(wèn)到
4)修改配置文件
同方式3)類似,我們可以在springboot的application.propertes配置文件中修改資源文件的訪問(wèn)匹配方式和文件路徑。
注意,這個(gè)配置會(huì)覆蓋Spring boot默認(rèn)的靜態(tài)資源目錄,例如如果按示例中配置,則無(wú)法再訪問(wèn)static、public、resources等目錄下的資源了。
靜態(tài)資源,例如HTML文件、JS文件,設(shè)計(jì)到的Spring Boot配置有兩項(xiàng):
- spring.mvc.static-path-pattern
- spring.resources.static-locations
1)spring.mvc.static-path-pattern:
代表的含義是我們應(yīng)該以什么樣的路徑來(lái)訪問(wèn)靜態(tài)資源,換句話說(shuō),只有靜態(tài)資源滿足什么樣的匹配條件,Spring Boot才會(huì)處理靜態(tài)資源請(qǐng)求。
類似于springmvc中處理靜態(tài)資源的mapping標(biāo)簽,以官方配置為例:
# 這表示只有靜態(tài)資源的訪問(wèn)路徑為/resources/**時(shí),才會(huì)當(dāng)作靜態(tài)資源處理請(qǐng)求 spring.mvc.static-path-pattern=/resources/**,
假定采用默認(rèn)的配置端口,那么只有請(qǐng)求地址類似于“http://localhost:8080/resources/jquery.js”時(shí),Spring Boot才會(huì)處理此請(qǐng)求,處理方式是將根據(jù)模式匹配后的文件名查找本地文件,那么應(yīng)該在什么地方查找本地文件呢?這就是“spring.resources.static-locations”的作用了。
2)spring.resources.static-locations:
用于告訴Spring Boot應(yīng)該在何處查找靜態(tài)資源文件,這是一個(gè)列表性的配置,查找文件時(shí)會(huì)依賴于配置的先后順序依次進(jìn)行。
類似于springmvc中的location標(biāo)簽,默認(rèn)的官方配置如下:
spring.resources.static-locations=classpath:/static,classpath:/public,classpath:/resources,classpath:/META-INF/resources
繼續(xù)以上面的請(qǐng)求地址為例,“http://localhost:8080/resources/jquery.js”就會(huì)在上述的四個(gè)路徑中依次查找是否存在“jquery.js”文件,如果找到了,則返回此文件,否則返回404錯(cuò)誤。
等價(jià)于:
<mvc:resources mapping="/resources/**" location="/public-resources/"> <mvc:cache-control max-age="3600" cache-public="true"/> </mvc:resources>
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot如何手寫一個(gè)starter并使用這個(gè)starter詳解
starter是SpringBoot中的一個(gè)新發(fā)明,它有效的降低了項(xiàng)目開發(fā)過(guò)程的復(fù)雜程度,對(duì)于簡(jiǎn)化開發(fā)操作有著非常好的效果,下面這篇文章主要給大家介紹了關(guān)于SpringBoot如何手寫一個(gè)starter并使用這個(gè)starter的相關(guān)資料,需要的朋友可以參考下2022-12-12Spring?MVC異步上傳、跨服務(wù)器上傳和文件下載功能實(shí)現(xiàn)
這篇文章主要介紹了Spring?MVC異步上傳、跨服務(wù)器上傳和文件下載功能實(shí)現(xiàn),本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07Java實(shí)現(xiàn)LeetCode(報(bào)數(shù))
這篇文章主要介紹了Java實(shí)現(xiàn)LeetCode(報(bào)數(shù)),本文通過(guò)使用java實(shí)現(xiàn)leetcode的報(bào)數(shù)題目和實(shí)現(xiàn)思路分析,需要的朋友可以參考下2021-06-06Java通過(guò)正則表達(dá)式獲取字符串中數(shù)字的方法示例
最近工作中遇到了一個(gè)需求,需要利用java獲取字符串中的數(shù)字,嘗試幾種方法后發(fā)現(xiàn)利用正則表達(dá)式實(shí)現(xiàn)最為方法,下面這篇文章就主要介紹了Java通過(guò)正則表達(dá)式獲取字符串中數(shù)字的方法,文中給出了詳細(xì)的示例代碼,需要的朋友可以參考下。2017-03-03導(dǎo)入maven項(xiàng)目各個(gè)注解均報(bào)錯(cuò)的解決方案
這篇文章主要介紹了導(dǎo)入maven項(xiàng)目各個(gè)注解均報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12springboot+thymeleaf+druid+mybatis 多模塊實(shí)現(xiàn)用戶登錄功能
這篇文章主要介紹了springboot+thymeleaf+druid+mybatis 多模塊實(shí)現(xiàn)用戶登錄功能,本文通過(guò)示例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07