SpringBoot+Thymeleaf靜態(tài)資源的映射規(guī)則說明
Spring Boot中靜態(tài)資源的映射規(guī)則
Spring Boot中靜態(tài)資源主要包括兩部分:1、webjars資源,2、自定義的其他html、css、js資源,下面分別介紹兩種資源的映射規(guī)則。
1)、webjars資源
WebJars是將web前端資源(js,css等)打成jar包文件,然后借助Maven工具,以jar包形式對web前端資源進(jìn)行統(tǒng)一依賴管理,保證這些Web資源版本唯一性。webjars導(dǎo)入對應(yīng)的xml代碼可以在webjars的官網(wǎng)進(jìn)行復(fù)制。

SpringBoot對webjars資源的映射規(guī)則在WebMvcAutoConfiguration.java包里面,代碼部分截圖如下所示:
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
Integer cachePeriod = this.resourceProperties.getCachePeriod();
if (!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(cachePeriod));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(this.resourceProperties.getStaticLocations()).setCachePeriod(cachePeriod));
}
}
}
由上述代碼可以看出,所有訪問項(xiàng)目根目錄下的webjars下的所有資源,都會被映射到classpath:/META-INF/resources/webjars/文件夾下,其中classpath是resources資源文件夾或類的根目錄。
而使用maven方式導(dǎo)入的webjars包的靜態(tài)資源(js、css)會自動放到classpath:/META-INF/resources/webjars/文件夾下,如下所示:

由圖可以看出dist中的靜態(tài)資源文件上層目錄為resources/webjars/**
因此在前端引用(此處用的是thymeleaf模板引擎)時可以用如下方式引用:直接從webjars目錄開始寫即可,上述靜態(tài)資源映射配置的實(shí)際效果即在自己寫的資源路徑前面加上classpath:/META-INF/resources前綴
<link th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="external nofollow" rel="stylesheet">
2)、自己添加的靜態(tài)資源文件
Spring Boot對自己添加的靜態(tài)資源文件的映射規(guī)則仍然在WebMvcAutoConfiguration.java文件中,實(shí)際配置是在ResourcesProperties.java資源文件中CLASSPATH_RESOURCE_LOCATIONS變量。
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
上述配置效果即所有的靜態(tài)資源的訪問除直接訪問/webjars/**路徑時,會在訪問路徑前加上上述配置中的任意一個字符串進(jìn)行查找,直到在相應(yīng)的文件下找到對應(yīng)的靜態(tài)資源。因此在編寫SpringBoot應(yīng)用時一般可以將靜態(tài)資源放置在resources資源目錄下的static或者public文件夾下,如下圖所示:

如上圖若想訪問layui.js可以如下引用靜態(tài)資源:
<script th:src="@{/layui/layui.js}"></script>
上述引用之后,SpringBoot會去CLASSPATH_RESOURCE_LOCATIONS變量指定的路徑下找layui/layui.js直到找到該文件位置。
CLASSPATH_RESOURCE_LOCATIONS的值可以直接在SpringBoot的配置文件application.properties或yml文件中進(jìn)行修改。
Thymeleaf模板引擎的映射規(guī)則
Thymeleaf模板引擎的映射規(guī)則如下所示
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8");
private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
上述代碼的實(shí)際效果是在使用模板引擎是會將請求路徑字符串的前面加上classpath:/templates/,后面加上html進(jìn)行資源請求。因此一般將需要模板引擎進(jìn)行渲染的html界面放在resources路徑下的templates文件夾下,并且在請求的路徑字符串中不需要加html后綴。
一個簡單的例子如下所示:
@RequestMapping("/success")
public String success(Map<String,Object> map){
// map=new HashMap<>(); 這個地方不能再new了
map.put("hello","hello");
return "success";
}
上述代碼返回所渲染的html界面即位于resources/templates文件夾下的success.html界面。該默認(rèn)設(shè)置頁可以直接在配置文件中通過spring.thymeleaf選項(xiàng)進(jìn)行修改。
SpringBoot對靜態(tài)資源的映射規(guī)則源碼學(xué)習(xí)筆記

WebMvcAuotConfiguration:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
//所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找資源;
//webjars:以jar包的方式引入靜態(tài)資源;
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
//"/**" 訪問當(dāng)前項(xiàng)目的任何資源,都去(靜態(tài)資源的文件夾)找映射
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
//靜態(tài)資源文件夾映射
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
resourceProperties
源碼:
//可以設(shè)置和靜態(tài)資源有關(guān)的參數(shù),緩存時間等
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {
getStaticPathPattern():
源碼:
private String staticPathPattern = "/**";
public String getStaticPathPattern() {
return this.staticPathPattern;
}
getStaticLocations()
源碼:
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
public String[] getStaticLocations() {
return this.staticLocations;
}
//配置歡迎頁映射
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(
ResourceProperties resourceProperties) {
//靜態(tài)資源文件夾下的所有index.html頁面;被"/**"映射;
return new WelcomePageHandlerMapping(resourceProperties.getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
}
private Optional<Resource> getWelcomePage() {
String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}
private Resource getIndexHtml(String location) {
return this.resourceLoader.getResource(location + "index.html");
}
getStaticPathPattern()
源碼:
private String staticPathPattern = "/**";
public String getStaticPathPattern() {
return this.staticPathPattern;
}
//配置喜歡的圖標(biāo)
@Configuration
@ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true)
public static class FaviconConfiguration implements ResourceLoaderAware {
private final ResourceProperties resourceProperties;
private ResourceLoader resourceLoader;
public FaviconConfiguration(ResourceProperties resourceProperties) {
this.resourceProperties = resourceProperties;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Bean
public SimpleUrlHandlerMapping faviconHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
//所有 **/favicon.ico 都是在靜態(tài)資源文件下找
mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", faviconRequestHandler()));
return mapping;
}
@Bean
public ResourceHttpRequestHandler faviconRequestHandler() {
ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
requestHandler.setLocations(resolveFaviconLocations());
return requestHandler;
}
private List<Resource> resolveFaviconLocations() {
String[] staticLocations = getResourceLocations(this.resourceProperties.getStaticLocations());
List<Resource> locations = new ArrayList<>(staticLocations.length + 1);
Arrays.stream(staticLocations).map(this.resourceLoader::getResource).forEach(locations::add);
locations.add(new ClassPathResource("/"));
return Collections.unmodifiableList(locations);
}
}
Thymeleaf使用
源碼:
//只要我們把HTML頁面放在classpath:/templates/,thymeleaf就能自動渲染;
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
}
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
java中如何實(shí)現(xiàn)對類的對象進(jìn)行排序
在本篇文章里小編給各位整理一篇關(guān)于java中如何實(shí)現(xiàn)對類的對象進(jìn)行排序知識點(diǎn)內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。2020-02-02
啟動SpringBoot報JavaMail加載錯誤的原因分析和解決
這篇文章給大家介紹了啟動SpringBoot報JavaMail加載錯誤的原因分析和解決,文中通過代碼示例給出了詳細(xì)的原因分析和解決方法,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-01-01
Java成員變量與局部變量(動力節(jié)點(diǎn)Java學(xué)院整理)
這篇文章主要介紹了Java成員變量與局部變量的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-04-04
解決Maven項(xiàng)目pom.xml導(dǎo)入了Junit包還是用不了@Test注解問題
在Maven項(xiàng)目中,如果在非test目錄下使用@Test注解,可能會因?yàn)閜om.xml中<scope>test</scope>的設(shè)置而無法使用,正確做法是將測試代碼放在src/test/java目錄下,或去除<scope>test</scope>限制,這樣可以確保Junit依賴正確加載并應(yīng)用于適當(dāng)?shù)拇a部分2024-10-10
Java實(shí)現(xiàn)添加,讀取和刪除Excel圖片的方法詳解
本文介紹在Java程序中如何添加圖片到excel表格,以及如何讀取、刪除excel表格中已有的圖片。文中的示例代碼講解詳細(xì),感興趣的可以學(xué)習(xí)一下2022-05-05
SpringBoot中@ComponentScan的使用詳解
這篇文章主要介紹了SpringBoot中@ComponentScan的使用詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
深入理解Java8新特性之Lambda表達(dá)式的基本語法和自定義函數(shù)式接口
Lambda 表達(dá)式,也可稱為閉包,它是推動 Java 8 發(fā)布的最重要新特性。Lambda 允許把函數(shù)作為一個方法的參數(shù)(函數(shù)作為參數(shù)傳遞進(jìn)方法中)。使用 Lambda 表達(dá)式可以使代碼變的更加簡潔緊湊2021-11-11

