更新時(shí)間:2021-12-09 12:07:18 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽1629次
由于早期的Spring MVC對(duì)靜態(tài)資源的處理不好,DispatCherServlet的請(qǐng)求映射是在Web.xml中配置的,經(jīng)常在*.do,*. Xhtml。這就決定了請(qǐng)求的 URL 必須是后綴 URL,不能使用真正的 REST 風(fēng)格的 URL。
如果將 DispatcherServlet 請(qǐng)求映射配置為“”,則 Spring MVC 會(huì)捕獲 Web 容器的所有請(qǐng)求,包括靜態(tài)資源,Spring MVC 會(huì)將它們視為正常的請(qǐng)求過(guò)程,從而導(dǎo)致相應(yīng)處理器的錯(cuò)誤。
如何讓Spring框架捕獲所有的URL請(qǐng)求,同時(shí)從Web容器中傳輸靜態(tài)資源,前提是DispatcherServlet的請(qǐng)求映射為“/”。由于REST是Spring的重要特性之一,因此Spring團(tuán)隊(duì)非常接近靜態(tài)資源來(lái)處理這個(gè)任務(wù),給出了兩個(gè)經(jīng)典的解決方案。
在學(xué)習(xí)這兩個(gè)場(chǎng)景之前,調(diào)整Web.xml中DispatcherServlet的配置,使其能夠捕獲所有請(qǐng)求。
< servlet >
< servlet-name > smart </ servlet-name >
< servlet-class > org.springframework.web.servlet.DispatcherServlet </ servlet-class >
< load-on-startup > 1 </ load-on-startup >
</小服務(wù)程序>
< servlet-mapping >
< servlet-name > smart </ servlet-name >
< url-pattern > / </ url-pattern >
</ servlet-mapping >
所有的URL請(qǐng)求都會(huì)通過(guò)<url-pattern> / </ url-pattern>的配置被Spring MVC的DispatcherServlet攔截。
在 smart-servlet.xml 中配置 <mvc: default-servlet-handler /> 后,您將在 Spring MVC 上下文中定義一個(gè) org.springframework.web.servlet.resource.defaultservlettpRequestHandler,它將充當(dāng)檢查員的角色,輸入用于篩選的 DispatcherServlet 的 URL。如果發(fā)現(xiàn)是靜態(tài)資源請(qǐng)求,則轉(zhuǎn)由WEB應(yīng)用服務(wù)器默認(rèn)servlet請(qǐng)求;如果不是靜態(tài)資源請(qǐng)求,則繼續(xù)由 DispatcherServlet 處理。
一般的web應(yīng)用服務(wù)器(包括Tomcat、Jetty、GlassFish、JBoss、Resin、WebLogic和WebSphere)默認(rèn)的servlet名稱(chēng)是default,所以defaultservlettpRequestHandler可以找到。如果用戶(hù)使用的Web應(yīng)用服務(wù)器的默認(rèn)servlet名稱(chēng)不是default,則需要通過(guò)default-servlet-name屬性明確指定。
< mvc:default-servlet-handler default—serv1et—name ="yourServerDefaultServlet Name" />
<mvc: default-servlet-handler />通過(guò) Spring MVC 框架返回一個(gè)靜態(tài)資源給 web 應(yīng)用服務(wù)器。而 <mvc:resources /> 進(jìn)一步由 Spring MVC 框架處理靜態(tài)資源,并添加了一些有用的附加功能。
首先,<mvc:resources />允許靜態(tài)資源放置在任何地方,比如web-inflicity、classpath等,甚至JavaScript等靜態(tài)文件都可以打包到JAR包中。靜態(tài)資源的位置由Location屬性指定,由于location屬性是資源類(lèi)型,資源前綴指定資源前綴,如“ClassPath:”。傳統(tǒng)Web容器的靜態(tài)資源只能放在Web容器的根路徑下,完全打破了這個(gè)限制。
其次,<mvc:resources /> 提供基于當(dāng)前瀏覽器優(yōu)化原則如Page Speed、YSLOW 的靜態(tài)資源優(yōu)化??梢灾付ㄒ粋€(gè)cacheseconds屬性來(lái)指定瀏覽器端的緩存時(shí)間,一般設(shè)置為一年,以充分利用瀏覽器端。輸出靜態(tài)資源時(shí),應(yīng)根據(jù)配置設(shè)置文本的 expires 和 cache-control 值。
當(dāng)接收到靜態(tài)資源獲取請(qǐng)求時(shí),檢查請(qǐng)求頭的Last-Modified值。如果靜態(tài)資源沒(méi)有變化,直接返回303響應(yīng)狀態(tài)碼,表示客戶(hù)端使用瀏覽器緩存的數(shù)據(jù),而不是將靜態(tài)資源的內(nèi)容輸出給客戶(hù)端到足夠的帶寬,提高程序性能。
在 smart-servlet.xml 中添加以下配置:
< mvc:resources mapping ="/resources/**" location ="/,classpath:/META—INF/publicResources/" />
以上配置將web根路徑“/”和類(lèi)路徑/meta-inf/publicresources/映射到/resources路徑下。假設(shè)web根路徑下有Images和JS兩個(gè)資源目錄,可以通過(guò)下圖的方式來(lái)引用靜態(tài)資源。

假設(shè)classpread/meta-inf/publicresources/下Images/Bg1.gif和JS/Test1.js也可以通過(guò)/resources/iImages/bg1.gif和/resources/js/test1.js在網(wǎng)頁(yè)中進(jìn)行引用,如以下代碼所示。
< script src ="<c:url value=" / resources / js / test.js" /> " type= " text / javascript">< / script >
由于<mvc:resources />可以將多個(gè)物理路徑映射到一個(gè)邏輯路徑,所以一個(gè)邏輯路徑所代表的資源存在于多個(gè)物理路徑中。對(duì)于這個(gè)問(wèn)題,<mvc:resources />的處理機(jī)制是只要找到匹配的資源,查找的順序和Location中的物理路徑按照Location的location中配置的順序一致在物理路徑下。
聰明的讀者可能會(huì)問(wèn):既然網(wǎng)頁(yè)根路徑“/”映射了“/resources/**”,那么是否可以通過(guò)“/resources/web-inf/web.xml”訪問(wèn)網(wǎng)頁(yè)中的這個(gè)敏感文件?答案是否定的。Spring MVC 在處理地圖的靜態(tài)資源時(shí),會(huì)看到引用路徑中是否包含Web-INF 或META-INF。如果包含,直接返回NULL值,保護(hù)安全文件不泄露。當(dāng)然,如果/web-INF/Settings在location屬性中,則可以通過(guò)/resources/web.xml的URL查看Web.xml。
< mvc:resources mapping ="/resources/**" location ="/WEB-INF/" />
所以在使用<mvc:resources />時(shí)要特別注意,不要在意,你不在意,你不要期望暴露的資源。
靜態(tài)資源的緩存有效時(shí)間可以通過(guò)<mvc:resources />的cache-period屬性在客戶(hù)端瀏覽器中設(shè)置。
< mvc:resources mapping ="/resources/**" location ="/,classpath:/META—INF/publicResources/" cache-period ="31536000" />
一般情況下,將cache-period 設(shè)置為一年,以充分利用客戶(hù)端的緩存數(shù)據(jù)。
在發(fā)布新版本的app時(shí),即使服務(wù)器端的JavaScript、CSS等靜態(tài)資源文件發(fā)生了變化,但由于客戶(hù)端瀏覽器本身的問(wèn)題,客戶(hù)端并沒(méi)有從服務(wù)器端下載新的靜態(tài)資源。一個(gè)好的解決辦法是在Page的path中添加應(yīng)用版本號(hào),這個(gè)版本號(hào)被新的部署版本改變了,導(dǎo)致這些靜態(tài)資源由于新的部署版本而變成這些靜態(tài)資源。“新資源”,客戶(hù)端瀏覽器下載這個(gè)“新資源”而不使用緩存中的數(shù)據(jù)。對(duì)于這個(gè)方案,可以通過(guò)<mvc:resources/>的靜態(tài)資源邏輯路徑給出一個(gè)通用的方案。
發(fā)布版本號(hào)包含在的靜態(tài)資源邏輯路徑中。首先創(chuàng)建一個(gè)servletContextaWare實(shí)現(xiàn)類(lèi),如下代碼所示。
導(dǎo)入javax.servlet.ServletContext;
導(dǎo)入org.springframework.web.context.ServletContextAware;
公共 類(lèi)ResourcePathExposer實(shí)現(xiàn)ServletContextAware {
private ServletContext servletContext;
私有字符串資源根;
公共 無(wú)效初始化(){
字符串版本= "1.2.1"; // 1 在實(shí)際應(yīng)用中,可以將應(yīng)用的發(fā)布版本號(hào)保存在外部屬性文件或數(shù)據(jù)庫(kù)中,這里可以獲取。這里只有一個(gè)模擬值。
resourceRoot = "/resources-" + 版本;// 2 發(fā)布資源邏輯路徑上應(yīng)用的版本號(hào)
getServletContext().setAttribute("resourceRoot" ,
getServletContext().getContextPath() +resourceRoot); // 3 在servletContext的屬性列表的資源邏輯路徑列表中
}
public void setServletContext(ServletContext servletContext) {
this .servletContext = servletContext;
}
公共字符串 getResourceRoot() {
返回資源根;
}
公共ServletContext getServletContext() {
返回servletContext;
}
}
在ResourcePatHexposer中獲取應(yīng)用的發(fā)布版本號(hào),生成帶有版本號(hào)的靜態(tài)資源路徑,將其值發(fā)布到servletContext,servletContext可以通過(guò)${resourceeroot}引用其值。
接下來(lái),您要調(diào)整配置以使用靜態(tài)資源邏輯路徑的版本。
< bean id ="rpe" class ="com.smart.web.ResourcePathExposer" init-method ="init" />
< mvc:resources mapping ="#{rpe.resourceRoot}/**" location ="/"緩存-期間="31536000" />
將ResourcePatHexposer配置為1,并在init()中指定其初始化方法,以便在容器啟動(dòng)時(shí)初始化ResourceRoot的值。由于它實(shí)現(xiàn)了 servletContextaWare 接口,因此 Spring 將在 bean 的初始化中注入 servletContext 引用。
2處,通過(guò)Spring EL表達(dá)式引用resourceRootHexposer的resourceerOot屬性值,生成動(dòng)態(tài)靜態(tài)資源邏輯路徑。
最后調(diào)整在網(wǎng)頁(yè)中引用靜態(tài)資源的方式,如下代碼所示。
< script src ="<c:url value=" ${resourceRoot}/js/test.js" /> " type= " text / javascript">< / script >
由于引用的resourceroot值和#{rpe.resourceroot}引用的<mvc:resources />,可以正確訪問(wèn)物理靜態(tài)資源。這樣,每次發(fā)布新版本后,客戶(hù)端會(huì)自動(dòng)下載新的靜態(tài)資源,發(fā)布版本號(hào)發(fā)生變化。
Java實(shí)驗(yàn)班
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
Java就業(yè)班
有基礎(chǔ) 直達(dá)就業(yè)
Java夜校直播班
業(yè)余時(shí)間 高薪轉(zhuǎn)行
Java在職加薪班
工作1~3年,加薪神器
Java架構(gòu)師班
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問(wèn)老師會(huì)電話與您溝通安排學(xué)習(xí)