1. 程式人生 > >springboot下靜態資源的處理

springboot下靜態資源的處理

在SpringBoot中有預設的靜態資原始檔相關配置,需要通過如下原始碼跟蹤: WebMvcAutoConfiguration-->configureResourceChain(method)-->ResourceProperties中配置了預設的靜態資源路徑:
其預設的優先順序:META/resources > resources > static > public  下面通過案例實踐驗證靜態資源的應用 章節要點: 1、傳統靜態資源引入; 2、WebJar使用; 3、版本管理; 4、靜態資源配置抽取; 5、WAR包常規容易部署; 1、傳統靜態資原始檔的引入: 1.1、在預設的路徑下新增jquery.js:
1.2、修改原jsp目錄下的home.jsp頁面: <%@ page contentType="text/html;charset=UTF-8" %> <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8" /> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> <title>JSP</title> <script type="text/javascript" src="/js/jquery/jquery-1.11.3.min.js"></script>
<script type="text/javascript"> $(document).ready(function() { var myDate = new Date(); $("#dateInput").val(myDate.toLocaleString()); }); function increase(){ var currentPage=$("#currentPage"); currentPage.val(Number(currentPage.val())+1); alert($("#currentPage").val()); } </script> </head> <body> <h1>Hello ${name} from JSP!</h1> <div>
<label id="showLab">進入頁面時間</label> <input type="text" id="dateInput" style="width: 200px"/> <input type="text" id="currentPage" style="width: 200px" value=1> <a href="#" onclick="increase()">增一</a> </div> </body> </html> 1.3、此時我們直接訪問請求頁面:
點選增一,執行js
系統預設配置驗證完成,能夠正常載入使用。 1.4、下面我們開始驗證自定義靜態資原始檔目錄實現,嘗試兩種不同的方案(1、仍然在classpath目錄下,新建非static目錄;2、在WEB-INF目錄下新建static/js目錄),根據之前的實踐,我們僅需在實現WebMvcConfigurerAdapter介面的配置類中新增addResourceHandlers方法即可(優先順序為先新增的高於後新增的)。 @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/mystatic/**").addResourceLocations("classpath:/mystatic/"); registry.addResourceHandler("/static/js/**").addResourceLocations("/WEB-INF/static/js/"); } 1.5、新增對應的靜態檔案目錄以及檔案:


如上目前在3個不同的路徑下均有對應的js檔案。 1.6、在頁面中新增js的載入:
1.7、我們發出請求檢視,通過F12檢視開發者模式下請求狀態:

3種不同的配置均能夠生效,均能夠找到目前檔案。 綜上: 1、可以發現通過重寫addResourceHandlers的方式新增靜態資源請求對映不會覆蓋系統原有預設對映,能夠疊加使用; 2、通過配置對應的請求規則,對映值不同的資原始檔目錄。但採用預設的資源路徑時,請求地址無需加入static,如上/js/jquery/jquery-1.11.3.min.js系統自動至預設的路徑(目前為classpath:/static/)下查詢,如果/static/js/jquery/jquery-1.11.3.min.js則預設情況下會在classpath:/static/路徑下繼續查詢static目錄,顯然是沒有的(當然本案例中已經將/static/js/**請求重新對映資源路徑)。 3、如果需要將系統預設的/**預設資源路徑更改,需要新增registry.addResourceHandler("/**").addResourceLocations("/WEB-INF/static/");即可,通常無需此設定。 2、在springboot中靜態資原始檔的引用,可以通過webjars載入,WebJars將我們常用的js打包成了jar包。WebJars:http://www.webjars.org/ 2.1、首先在POM檔案中新增相關依賴: <!-- webjar依賴 --> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>1.11.3</version> </dependency> 2.2、在頁面中新增js檔案的載入:
2.3、請求頁面檢視請求效果:

能夠如願正常載入訪問。 2.4、既然通過POM檔案可以直接指定載入的目標js庫的版本,那麼如果我們修改版本,是不是可以不需要手動修改引入js的版本路徑呢: 2.4.1、繼續新增相關依賴: <dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator</artifactId> </dependency> 2.4.2、新建一個控制器,如下: @Controller public class WebJarController { private final WebJarAssetLocator assetLocator = new WebJarAssetLocator(); @ResponseBody @RequestMapping("/webjarslocator/{webjar}/**") public ResponseEntity locateWebjarAsset(@PathVariable String webjar, HttpServletRequest request) { try { String mvcPrefix = "/webjarslocator/" + webjar + "/"; String mvcPath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); String fullPath = assetLocator.getFullPath(webjar, mvcPath.substring(mvcPrefix.length())); return new ResponseEntity(new ClassPathResource(fullPath), HttpStatus.OK); } catch (Exception e) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } } } 2.4.3、在頁面中新增引入: <script type="text/javascript" src="/webjarslocator/jquery/jquery.js"></script> 2.4.5、請求頁面驗證:


一切都很正常,僅僅在引入地址省去了版本路徑。 3、版本管理 在專案中,當我們資源內容發生變化時,由於瀏覽器快取,使用者本地的靜態資源還是舊的資源,為了防止這種情況導致的問題,我們可能會手動在請求url的時候加個版本號或者其他方式。 此時在springboot中,我們可以通過如下兩種方式解決此問題。 3.1、資源名-md5 方式: 3.1.1、在application.properties檔案中新增: spring.resources.chain.strategy.content.enabled=true spring.resources.chain.strategy.content.paths=/** 3.1.2、通過paths的設定,所有的請求將均被處理,轉換為相應的版本話地址,那麼我們在jsp頁面中引入的url需要簡單處理,首先新增 package com.shf.springboot.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.servlet.resource.ResourceUrlProvider; /** * 主要作用於版本話管理靜態資源 * @author song */ @ControllerAdvice public class ControllerConfig { @Autowired ResourceUrlProvider resourceUrlProvider; @ModelAttribute("urls") public ResourceUrlProvider urls() { return this.resourceUrlProvider; } } 然後引入js:
將上述論證的引入js的多種模式均驗證,驗證結果如下:
可以發現,僅預設請求的/**查詢classpath:static以及webjars兩種預設資源對映能夠實現MD5版本化,自定義的/static/js/**方式能夠正常載入,而採用通過webjarslocator資源定位的則無法獲取資原始檔。 3.2:採用版本號方式 3.2.1、在application.properties檔案中配置: #spring.resources.chain.strategy.content.enabled=true #spring.resources.chain.strategy.content.paths=/** spring.resources.chain.strategy.fixed.enabled=true spring.resources.chain.strategy.fixed.paths=/** spring.resources.chain.strategy.fixed.version=v1.0.0 3.2.2、再次請求驗證檢視驗證結果:
可以發現,效果與md5方式差不多,僅預設請求的/**查詢classpath:static以及webjars兩種預設資源對映能夠實現版本化。 綜上:當請求的地址為md5方式時,會嘗試url中的檔名中是否包含-,如果包含會去掉後面這部分,然後去對映的目錄(如/static/)查詢/js/common.js檔案,如果能找到就返回。 當請求的地址為版本號方式時,會在url中判斷是否存在/v1.0.0 ,如果存在,則先從URL中把 /v1.0.0 去掉,然後再去對映目錄查詢對應檔案,找到就返回。 4、3中描述的版本話管理,其實在專案實際使用中,對於引入的第三方js相對還比較穩定,不會常有變化。版本化管理不一定是硬性需求,同時我們js引入通常抽取為公共的jsp頁面,無需每個頁面新增,修改也比較容易: 4.1、新建一個head.jsp頁面:
<%@ page contentType="text/html;charset=UTF-8" %> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <script type="text/javascript" src="/mystatic/js/jquery/jquery-1.11.3.min.js"></script> <script type="text/javascript" src="/static/js/jquery/jquery-1.11.3.min.js"></script> <script type="text/javascript" src="/js/jquery/jquery-1.11.3.min.js"></script> <script type="text/javascript" src="/webjars/jquery/1.11.3/jquery.js"></script> <script type="text/javascript" src="/webjarslocator/jquery/jquery.js"></script> <script type="text/javascript" src="${urls.getForLookupPath('/js/jquery/jquery-1.11.3.min.js')}"></script> <script type="text/javascript" src="${urls.getForLookupPath('/static/js/jquery/jquery-1.11.3.min.js')}"></script> <script type="text/javascript" src="${urls.getForLookupPath('/webjarslocator/jquery/jquery.js')}"></script> 4.2、在home.jsp中include:
4.3、請求驗證,與上述效果一致:
5、打成war部署自定義容易驗證(jar模式啟動無需驗證,jar模式下無法讀取WEB-INF目錄):
此時部署非根路徑部署,需要調整為如下: 5.1、抽取一個公共jsp: <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <c:set var="ctx" value="${pageContext.request.contextPath}"/> 5.2、在home.jsp中新增include: <%@include file="/WEB-INF/jsp/include/taglib.jsp" %> 5.3、在head.jsp中修改原引入: <%@ page contentType="text/html;charset=UTF-8" %> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <script type="text/javascript" src="${ctx }/mystatic/js/jquery/jquery-1.11.3.min.js"></script> <script type="text/javascript" src="${ctx }/static/js/jquery/jquery-1.11.3.min.js"></script> <script type="text/javascript" src="${ctx }/js/jquery/jquery-1.11.3.min.js"></script> <script type="text/javascript" src="${ctx }/webjars/jquery/1.11.3/jquery.js"></script> <script type="text/javascript" src="${ctx }/webjarslocator/jquery/jquery.js"></script> <script type="text/javascript" src="${ctx }${urls.getForLookupPath('/js/jquery/jquery-1.11.3.min.js')}"></script> <script type="text/javascript" src="${ctx }${urls.getForLookupPath('/static/js/jquery/jquery-1.11.3.min.js')}"></script> <script type="text/javascript" src="${ctx }${urls.getForLookupPath('/webjarslocator/jquery/jquery.js')}"></script> <script type="text/javascript" src="${ctx }${urls.getForLookupPath('/webjars/jquery/1.11.3/jquery.js')}"></script> 5.4、此時我們現在開發環境啟動驗證:
5.5、部署war包驗證:
此時可以發現兩種環境下,JS的引入與之前的效果一致,僅webjarslocator無法正常載入。 總結 有這麼多方式來管理我們的資原始檔,然而在實際應用中雖然也都有可能用到(存在就有存在的道理嘛):  1. 我們使用第三方的庫時,建議使用webjars的方式,通過動態版本號(webjars-locator 的方式)來使用(因為第三方庫在專案開發中變動頻率很小,即便是變動也是版本號的修改)。  2. 我們使用自己存放在靜態資源對映目錄中的資源的時候,建議使用md5 資原始檔名的方式來使用(專案開發中一些css、js檔案會經常修改)。  3. 專案素材檔案建議放到 classpath:/static (或其他)目錄中,打包在專案中,通過CMS維護的一些圖片和資源,我們使用配置引用到具體的磁碟絕對路徑來使用。  4. 注意使用md5檔名方式的時候,Spring 是有快取機制的,也就是說,在服務不重啟的情況下,你去變動修改這些資原始檔,其檔名的md5值並不會改變,只有重啟服務再次訪問才會生效。如果需要每次都獲取實際檔案的md5值,需要重寫相關類來實現,我們不建議這樣做,因為一直去計算檔案md5值是需要效能代價的。