更新時間:2021-12-09 12:07:18 來源:動力節點 瀏覽1387次
由于早期的Spring MVC對靜態資源的處理不好,DispatCherServlet的請求映射是在Web.xml中配置的,經常在*.do,*. Xhtml。這就決定了請求的 URL 必須是后綴 URL,不能使用真正的 REST 風格的 URL。
如果將 DispatcherServlet 請求映射配置為“”,則 Spring MVC 會捕獲 Web 容器的所有請求,包括靜態資源,Spring MVC 會將它們視為正常的請求過程,從而導致相應處理器的錯誤。
如何讓Spring框架捕獲所有的URL請求,同時從Web容器中傳輸靜態資源,前提是DispatcherServlet的請求映射為“/”。由于REST是Spring的重要特性之一,因此Spring團隊非常接近靜態資源來處理這個任務,給出了兩個經典的解決方案。
在學習這兩個場景之前,調整Web.xml中DispatcherServlet的配置,使其能夠捕獲所有請求。
< servlet >
< servlet-name > smart </ servlet-name >
< servlet-class > org.springframework.web.servlet.DispatcherServlet </ servlet-class >
< load-on-startup > 1 </ load-on-startup >
</小服務程序>
< servlet-mapping >
< servlet-name > smart </ servlet-name >
< url-pattern > / </ url-pattern >
</ servlet-mapping >
所有的URL請求都會通過<url-pattern> / </ url-pattern>的配置被Spring MVC的DispatcherServlet攔截。
在 smart-servlet.xml 中配置 <mvc: default-servlet-handler /> 后,您將在 Spring MVC 上下文中定義一個 org.springframework.web.servlet.resource.defaultservlettpRequestHandler,它將充當檢查員的角色,輸入用于篩選的 DispatcherServlet 的 URL。如果發現是靜態資源請求,則轉由WEB應用服務器默認servlet請求;如果不是靜態資源請求,則繼續由 DispatcherServlet 處理。
一般的web應用服務器(包括Tomcat、Jetty、GlassFish、JBoss、Resin、WebLogic和WebSphere)默認的servlet名稱是default,所以defaultservlettpRequestHandler可以找到。如果用戶使用的Web應用服務器的默認servlet名稱不是default,則需要通過default-servlet-name屬性明確指定。
< mvc:default-servlet-handler default—serv1et—name ="yourServerDefaultServlet Name" />
<mvc: default-servlet-handler />通過 Spring MVC 框架返回一個靜態資源給 web 應用服務器。而 <mvc:resources /> 進一步由 Spring MVC 框架處理靜態資源,并添加了一些有用的附加功能。
首先,<mvc:resources />允許靜態資源放置在任何地方,比如web-inflicity、classpath等,甚至JavaScript等靜態文件都可以打包到JAR包中。靜態資源的位置由Location屬性指定,由于location屬性是資源類型,資源前綴指定資源前綴,如“ClassPath:”。傳統Web容器的靜態資源只能放在Web容器的根路徑下,完全打破了這個限制。
其次,<mvc:resources /> 提供基于當前瀏覽器優化原則如Page Speed、YSLOW 的靜態資源優化。可以指定一個cacheseconds屬性來指定瀏覽器端的緩存時間,一般設置為一年,以充分利用瀏覽器端。輸出靜態資源時,應根據配置設置文本的 expires 和 cache-control 值。
當接收到靜態資源獲取請求時,檢查請求頭的Last-Modified值。如果靜態資源沒有變化,直接返回303響應狀態碼,表示客戶端使用瀏覽器緩存的數據,而不是將靜態資源的內容輸出給客戶端到足夠的帶寬,提高程序性能。
在 smart-servlet.xml 中添加以下配置:
< mvc:resources mapping ="/resources/**" location ="/,classpath:/META—INF/publicResources/" />
以上配置將web根路徑“/”和類路徑/meta-inf/publicresources/映射到/resources路徑下。假設web根路徑下有Images和JS兩個資源目錄,可以通過下圖的方式來引用靜態資源。
假設classpread/meta-inf/publicresources/下Images/Bg1.gif和JS/Test1.js也可以通過/resources/iImages/bg1.gif和/resources/js/test1.js在網頁中進行引用,如以下代碼所示。
< script src ="<c:url value=" / resources / js / test.js" /> " type= " text / javascript">< / script >
由于<mvc:resources />可以將多個物理路徑映射到一個邏輯路徑,所以一個邏輯路徑所代表的資源存在于多個物理路徑中。對于這個問題,<mvc:resources />的處理機制是只要找到匹配的資源,查找的順序和Location中的物理路徑按照Location的location中配置的順序一致在物理路徑下。
聰明的讀者可能會問:既然網頁根路徑“/”映射了“/resources/**”,那么是否可以通過“/resources/web-inf/web.xml”訪問網頁中的這個敏感文件?答案是否定的。Spring MVC 在處理地圖的靜態資源時,會看到引用路徑中是否包含Web-INF 或META-INF。如果包含,直接返回NULL值,保護安全文件不泄露。當然,如果/web-INF/Settings在location屬性中,則可以通過/resources/web.xml的URL查看Web.xml。
< mvc:resources mapping ="/resources/**" location ="/WEB-INF/" />
所以在使用<mvc:resources />時要特別注意,不要在意,你不在意,你不要期望暴露的資源。
靜態資源的緩存有效時間可以通過<mvc:resources />的cache-period屬性在客戶端瀏覽器中設置。
< mvc:resources mapping ="/resources/**" location ="/,classpath:/META—INF/publicResources/" cache-period ="31536000" />
一般情況下,將cache-period 設置為一年,以充分利用客戶端的緩存數據。
在發布新版本的app時,即使服務器端的JavaScript、CSS等靜態資源文件發生了變化,但由于客戶端瀏覽器本身的問題,客戶端并沒有從服務器端下載新的靜態資源。一個好的解決辦法是在Page的path中添加應用版本號,這個版本號被新的部署版本改變了,導致這些靜態資源由于新的部署版本而變成這些靜態資源。“新資源”,客戶端瀏覽器下載這個“新資源”而不使用緩存中的數據。對于這個方案,可以通過<mvc:resources/>的靜態資源邏輯路徑給出一個通用的方案。
發布版本號包含在的靜態資源邏輯路徑中。首先創建一個servletContextaWare實現類,如下代碼所示。
導入javax.servlet.ServletContext;
導入org.springframework.web.context.ServletContextAware;
公共 類ResourcePathExposer實現ServletContextAware {
private ServletContext servletContext;
私有字符串資源根;
公共 無效初始化(){
字符串版本= "1.2.1"; // 1 在實際應用中,可以將應用的發布版本號保存在外部屬性文件或數據庫中,這里可以獲取。這里只有一個模擬值。
resourceRoot = "/resources-" + 版本;// 2 發布資源邏輯路徑上應用的版本號
getServletContext().setAttribute("resourceRoot" ,
getServletContext().getContextPath() +resourceRoot); // 3 在servletContext的屬性列表的資源邏輯路徑列表中
}
public void setServletContext(ServletContext servletContext) {
this .servletContext = servletContext;
}
公共字符串 getResourceRoot() {
返回資源根;
}
公共ServletContext getServletContext() {
返回servletContext;
}
}
在ResourcePatHexposer中獲取應用的發布版本號,生成帶有版本號的靜態資源路徑,將其值發布到servletContext,servletContext可以通過${resourceeroot}引用其值。
接下來,您要調整配置以使用靜態資源邏輯路徑的版本。
< bean id ="rpe" class ="com.smart.web.ResourcePathExposer" init-method ="init" />
< mvc:resources mapping ="#{rpe.resourceRoot}/**" location ="/"緩存-期間="31536000" />
將ResourcePatHexposer配置為1,并在init()中指定其初始化方法,以便在容器啟動時初始化ResourceRoot的值。由于它實現了 servletContextaWare 接口,因此 Spring 將在 bean 的初始化中注入 servletContext 引用。
2處,通過Spring EL表達式引用resourceRootHexposer的resourceerOot屬性值,生成動態靜態資源邏輯路徑。
最后調整在網頁中引用靜態資源的方式,如下代碼所示。
< script src ="<c:url value=" ${resourceRoot}/js/test.js" /> " type= " text / javascript">< / script >
由于引用的resourceroot值和#{rpe.resourceroot}引用的<mvc:resources />,可以正確訪問物理靜態資源。這樣,每次發布新版本后,客戶端會自動下載新的靜態資源,發布版本號發生變化。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習