Spring Boot2 系列教程(十一)Spring Boot 中的靜態資源配置
- 2019 年 10 月 17 日
- 筆記
當我們使用 SpringMVC 框架時,靜態資源會被攔截,需要添加額外配置,之前老有小夥伴在微信上問松哥 Spring Boot 中的靜態資源載入問題:「松哥,我的 HTML 頁面好像沒有樣式?」,今天我就通過一篇文章,來和大夥仔細聊一聊這個問題。
1. SSM 中的配置
要講 Spring Boot 中的問題,我們得先回到 SSM 環境搭建中,一般來說,我們可以通過 <mvc:resources />
節點來配置不攔截靜態資源,如下:
<mvc:resources mapping="/js/**" location="/js/"/> <mvc:resources mapping="/css/**" location="/css/"/> <mvc:resources mapping="/html/**" location="/html/"/>
由於這是一種Ant風格的路徑匹配符,/**
表示可以匹配任意層級的路徑,因此上面的程式碼也可以像下面這樣簡寫:
<mvc:resources mapping="/**" location="/"/>
這種配置是在 XML 中的配置,大家知道,SpringMVC 的配置除了在XML中配置,也可以在 Java 程式碼中配置,如果在 Java 程式碼中配置的話,我們只需要自定義一個類,繼承自 WebMvcConfigurationSupport 即可:
@Configuration @ComponentScan(basePackages = "org.javaboy.javassm") public class SpringMVCConfig extends WebMvcConfigurationSupport { @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**").addResourceLocations("/"); } }
重寫 WebMvcConfigurationSupport 類中的 addResourceHandlers 方法,在該方法中配置靜態資源位置即可,這裡的含義和上面 xml 配置的含義一致,因此無需多說。
這是我們傳統的解決方案,在 Spring Boot 中,其實配置方式和這個一脈相承,只是有一些自動化的配置了。
2. Spring Boot 中的配置
在 Spring Boot 中,如果我們是從 https://start.spring.io
這個網站上創建的項目,或者使用 IntelliJ IDEA 中的 Spring Boot 初始化工具創建的項目,默認都會存在 resources/static
目錄,很多小夥伴也知道靜態資源只要放到這個目錄下,就可以直接訪問,除了這裡還有沒有其他可以放靜態資源的位置呢?為什麼放在這裡就能直接訪問了呢?這就是本文要討論的問題了。
2.1 整體規劃
首先,在 Spring Boot 中,默認情況下,一共有 5 個位置可以放靜態資源,五個路徑分別是如下 5 個:
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
/
前四個目錄好理解,分別對應了 resources 目錄下不同的目錄,第 5 個 /
是啥意思呢?我們知道,在 Spring Boot 項目中,默認是沒有 webapp
這個目錄的,當然我們也可以自己添加(例如在需要使用JSP的時候),這裡第 5 個 /
其實就是表示 webapp 目錄中的靜態資源也不被攔截。如果同一個文件分別出現在五個目錄下,那麼優先順序也是按照上面列出的順序。
不過,雖然有 5 個存儲目錄,除了第 5 個用的比較少之外,其他四個,系統默認創建了 classpath:/static/
, 正常情況下,我們只需要將我們的靜態資源放到這個目錄下即可,也不需要額外去創建其他靜態資源目錄,例如我在 classpath:/static/
目錄下放了一張名為 1.png 的圖片,那麼我的訪問路徑是:
http://localhost:8080/1.png
這裡大家注意,請求地址中並不需要 static,如果加上了 static 反而多此一舉會報 404 錯誤。很多人會覺得奇怪,為什麼不需要添加 static 呢?資源明明放在 static 目錄下。其實這個效果很好實現,例如在 SSM 配置中,我們的靜態資源攔截配置如果是下面這樣:
<mvc:resources mapping="/**" location="/static/"/>
如果我們是這樣配置的話,請求地址如果是 http://localhost:8080/1.png
實際上系統會去 /static/1.png
目錄下查找相關的文件。
所以我們理所當然的猜測,在 Spring Boot 中可能也是類似的配置。
2.2 源碼解讀
胡適之先生說:「大膽猜想,小心求證」,我們這裡就通過源碼解讀來看看 Spring Boot 中的靜態資源到底是怎麼配置的。
首先我們在 WebMvcAutoConfiguration 類中看到了 SpringMVC 自動化配置的相關的內容,找到了靜態資源攔截的配置,如下:
可以看到這裡靜態資源的定義和我們前面提到的 Java 配置 SSM 中的配置非常相似,其中,this.mvcProperties.getStaticPathPattern() 方法對應的值是 /**
,this.resourceProperties.getStaticLocations() 方法返回了四個位置,分別是:
- classpath:/META-INF/resources/
- classpath:/resources/
- classpath:/static/
- classpath:/public/
然後在 getResourceLocations 方法中,又添加了 /
,因此這裡返回值一共有 5 個。其中, /
表示 webapp
目錄,即 webapp
中的靜態文件也可以直接訪問。靜態資源的匹配路徑按照定義路徑優先順序依次降低。因此這裡的配置和我們前面提到的如出一轍。這樣大夥就知道了為什麼 Spring Boot
中支援 5 個靜態資源位置,同時也明白了為什麼靜態資源請求路徑中不需要 /static
,因為在路徑映射中已經自動的添加上了 /static
了。
2.3 自定義配置
當然,這個是系統默認配置,如果我們並不想將資源放在系統默認的這五個位置上,也可以自定義靜態資源位置和映射,自定義的方式也有兩種,可以通過 application.properties 來定義,也可以在 Java 程式碼中來定義,下面分別來看。
2.3.1 application.properties
在配置文件中定義的方式比較簡單,如下:
spring.resources.static-locations=classpath:/ spring.mvc.static-path-pattern=/**
第一行配置表示定義資源位置,第二行配置表示定義請求 URL 規則。以上文的配置為例,如果我們這樣定義了,表示可以將靜態資源放在 resources 目錄下的任意地方,我們訪問的時候當然也需要寫完整的路徑,例如在 resources/static
目錄下有一張名為 1.png 的圖片,那麼訪問路徑就是 http://localhost:8080/static/1.png
,注意此時的 static
不能省略。
2.3.2 Java 程式碼定義
當然,在 Spring Boot 中我們也可以通過 Java 程式碼來自定義,方式和 Java 配置的 SSM 比較類似,如下:
@Configuration public class WebMVCConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**").addResourceLocations("classpath:/aaa/"); } }
這裡程式碼基本和前面一致,比較簡單,不再贅述。
3. 總結
這裡需要提醒大家的是,松哥見到有很多人用了 Thymeleaf 之後,會將靜態資源也放在 resources/templates 目錄下,注意,templates 目錄並不是靜態資源目錄,它是一個放頁面模板的位置(你看到的 Thymeleaf 模板雖然後綴為 .html,其實並不是靜態資源)。好了,通過上面的講解,相信大家對 Spring Boot 中靜態資源的位置有一個深刻了解了,應該不會再在項目中出錯了吧!
關注公眾號【江南一點雨】,專註於 Spring Boot+微服務以及前後端分離等全棧技術,定期影片教程分享,關注後回復 Java ,領取松哥為你精心準備的 Java 乾貨!