在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.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值是需要性能代價的。
