Springboot2.x靜態(tài)資源配置
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
? 作者?|? 我出一條魚
來(lái)源 |? urlify.cn/fmIjQz
76套java從入門到精通實(shí)戰(zhàn)課程分享
一、靜態(tài)資源配置原理
Springboot 2.x 對(duì)于靜態(tài)資源的配置都是由?WebMvcAutoConfiguration 這個(gè)類完成的,我們這里選取 Springboot-2.3.7.RELEASE 這個(gè)版本來(lái)探究一下 Springboot 底層對(duì)于靜態(tài)資源是如何進(jìn)行配置的
首先來(lái)到?WebMvcAutoConfiguration 這個(gè)配置類,該類的聲明如下
//?配置中各個(gè)組件沒有依賴關(guān)系,為了加快效率,設(shè)置?proxyBeanMethods=false?,其默認(rèn)值是?true
@Configuration(proxyBeanMethods?=?false)
//?當(dāng)前是否是?Web?環(huán)境,并且類型是否是?SERVLET?類型的
@ConditionalOnWebApplication(type?=?Type.SERVLET)
//?系統(tǒng)中包含?Servlet、DispatcherServlet、WebMvcConfigurer?這幾個(gè)類
@ConditionalOnClass({Servlet.class,?DispatcherServlet.class,?WebMvcConfigurer.class})
//?容器中不包含?WebMvcConfigurationSupport?這個(gè)組件
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
//?自動(dòng)配置排序,數(shù)值越低,優(yōu)先級(jí)越高
@AutoConfigureOrder(-2147483638)
//?自動(dòng)配置在?DispatcherServletAutoConfiguration、TaskExecutionAutoConfiguration?、ValidationAutoConfiguration?之后
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class,?TaskExecutionAutoConfiguration.class,?ValidationAutoConfiguration.class})
public?class?WebMvcAutoConfiguration?{
????public?static?final?String?DEFAULT_PREFIX?=?"";
????public?static?final?String?DEFAULT_SUFFIX?=?"";
????private?static?final?String[]?SERVLET_LOCATIONS?=?new?String[]{"/"};
?
????public?WebMvcAutoConfiguration()?{
????}
?????
????....注冊(cè)各種組件
?????
}
如果?WebMvcAutoConfiguration 上的條件注解都滿足的情況下才會(huì)執(zhí)行該類里面的各種行為,在該類中我們可以發(fā)現(xiàn)存在一個(gè)靜態(tài)內(nèi)部類?WebMvcAutoConfigurationAdapter ,該類的具體聲明如下
//?配置中各個(gè)組件沒有依賴關(guān)系,為了加快效率,設(shè)置?proxyBeanMethods=false?,proxyBeanMethods?默認(rèn)值是?true
@Configuration(proxyBeanMethods?=?false)
//?向容器中注冊(cè)組件?EnableWebMvcConfiguration
@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
//?開啟?WebMvcProperties、ResourceProperties?類上的?@ConfigurationProperties?注解,并且將這兩個(gè)類注入?IOC?容器中
@EnableConfigurationProperties({WebMvcProperties.class,?ResourceProperties.class})
//?排序
@Order(0)
public?static?class?WebMvcAutoConfigurationAdapter?implements?WebMvcConfigurer?{
????private?static?final?Log?logger?=?LogFactory.getLog(WebMvcConfigurer.class);
????//?1、靜態(tài)資源配置類?---->?詳細(xì)見代碼塊一
????private?final?ResourceProperties?resourceProperties;
????final?WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer?resourceHandlerRegistrationCustomizer;
?
????public?void?addResourceHandlers(ResourceHandlerRegistry?registry)?{
????????//?2、如果配置了?spring.resources.add-mappings=false?,那么?Springboot?就不會(huì)對(duì)靜態(tài)資源和?webjars?進(jìn)行自動(dòng)配置
????????//?spring.resources.add-mappings?的默認(rèn)值是?true,它就是一個(gè)是否開啟?Springboot?對(duì)靜態(tài)資源配置的開關(guān),可以在
????????//?application.properties?中配置?debug=true?,然后就可以查看到?debug?級(jí)別的日志了
????????if?(!this.resourceProperties.isAddMappings())?{
????????????logger.debug("Default?resource?handling?disabled");
????????}?else?{
????????????//?3、獲取緩存時(shí)間
????????????Duration?cachePeriod?=?this.resourceProperties.getCache().getPeriod();
????????????//?4、獲取緩存控制對(duì)象
????????????CacheControl?cacheControl?=?this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
????????????//?5、webjars?的映射規(guī)則?/webjars/**?---->?classpath:/META-INF/resources/webjars/
????????????//?也就是比如我們?cè)L問?http://localhost:8080/webjars/aaa.js?,實(shí)際上就是訪問當(dāng)前項(xiàng)目類路徑下
????????????//?/META-INF/resources/webjars/aaa.js?這個(gè)資源
????????????if?(!registry.hasMappingForPattern("/webjars/**"))?{this.customizeResourceHandlerRegistration(
????????????????registry.addResourceHandler(new?String[]{"/webjars/**"})
????????????????.addResourceLocations(new?String[]{"classpath:/META-INF/resources/webjars/"})
????????????????.setCachePeriod(this.getSeconds(cachePeriod))
????????????????.setCacheControl(cacheControl));
????????????}
????????????//?6、staticPathPattern?默認(rèn)值是?/**?,也可以在?application.properties?中配置?spring.mvc.static-path-pattern?來(lái)修改?Springboot?默認(rèn)值
????????????String?staticPathPattern?=?this.mvcProperties.getStaticPathPattern();
????????????//?7、靜態(tài)資源映射規(guī)則
????????????if?(!registry.hasMappingForPattern(staticPathPattern))?{
????????????????this.customizeResourceHandlerRegistration(
????????????????registry.addResourceHandler(new?String[]{staticPathPattern})
????????????????//?8、靜態(tài)資源映射路徑?---->?詳細(xì)見代碼塊二
????????????????.addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations()))
????????????????.setCachePeriod(this.getSeconds(cachePeriod))
????????????????.setCacheControl(cacheControl));
????????????}
????????}
????}
}
代碼塊一、靜態(tài)資源配置類
//?1、將?application.properties?中?spring.resources?開頭的配置項(xiàng)與?ResourceProperties?類的屬性進(jìn)行綁定
//?如果該類中有屬性沒有匹配到值,則拋出異常
@ConfigurationProperties(prefix?=?"spring.resources",ignoreUnknownFields?=?false)
public?class?ResourceProperties?{
????//?2、Springboot?默認(rèn)的靜態(tài)資源路徑
????private?static?final?String[]?CLASSPATH_RESOURCE_LOCATIONS?=?new?String[]{
????????"classpath:/META-INF/resources/",
????????"classpath:/resources/",
????????"classpath:/static/",
????????"classpath:/public/"
????};
????private?String[]?staticLocations;
????private?boolean?addMappings;
????private?final?ResourceProperties.Chain?chain;
????private?final?ResourceProperties.Cache?cache;
?
????public?ResourceProperties()?{
????????//?2、Springboot?默認(rèn)的靜態(tài)資源路徑
????????this.staticLocations?=?CLASSPATH_RESOURCE_LOCATIONS;
????????//?3、addMappings?默認(rèn)值為?true,也就是?application.properties?中不配置
????????//?spring.resources.add-mappings?選項(xiàng),那么就使用?Springboot?的默認(rèn)值?true
????????this.addMappings?=?true;
????????this.chain?=?new?ResourceProperties.Chain();
????????this.cache?=?new?ResourceProperties.Cache();
????}
?
????public?String[]?getStaticLocations()?{
????????return?this.staticLocations;
????}
?????
????...........
?????
}
代碼塊二、
WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())
this.resourceProperties.getStaticLocations():獲取與 ResourceProperties 綁定的靜態(tài)資源路徑, Springboot 默認(rèn)的靜態(tài)資源路徑如下:
private?static?final?String[]?CLASSPATH_RESOURCE_LOCATIONS?=?new?String[]{
????"classpath:/META-INF/resources/",
????"classpath:/resources/",
????"classpath:/static/",
????"classpath:/public/"
}
如果我們手動(dòng)在 application.properties 中配置了?spring.resources.static-locations ,那么它會(huì)覆蓋 Springboot 的默認(rèn)值
?
二、總結(jié)
1、Springboot webjars 的默認(rèn)映射規(guī)則 /webjars/** ---->?classpath:/META-INF/resources/webjars/
2、Springboot 靜態(tài)資源的默認(rèn)映射規(guī)則 /** ----> { classpath:/META-INF/resources、classpath:/resources/、classpath:/static/、classpath:/public/?}
3、可以通過修改 application.properties 配置文件中的配置項(xiàng)來(lái)改變 Springboot 默認(rèn)的配置規(guī)則,或者手動(dòng)注冊(cè)組件的方式來(lái)額外增加配置規(guī)則(與默認(rèn)規(guī)則一同生效)
?
三、案例
1、webjars : 以依賴的方式引入 CSS、JS 等
登錄 webjars 官網(wǎng)
https://www.webjars.org/
選擇你需要的資源,這里以 js 為例

引入后的 webjars 依賴如下

由于 webjars 的映射規(guī)則是?/webjars/** ---->?classpath:/META-INF/resources/webjars/
如果我想訪問上圖中的 classpath:/META-INF/resources/webjars/jquery/3.5.1/jquery.js 這個(gè)資源
那么瀏覽器只需要訪問?http://localhost:8080/webjars/jquery/3.5.1/jquery.js 即可
?
2、靜態(tài)資源
Springboot 對(duì)靜態(tài)資源的默認(rèn)映射規(guī)則是?/** ----> { classpath:/META-INF/resources、classpath:/resources/、classpath:/static/、classpath:/public/?}
例如瀏覽器發(fā)起請(qǐng)求 http://localhost:8080/aaa.txt ,那么就會(huì)去?classpath:/META-INF/resources、classpath:/resources/、classpath:/static/、classpath:/public/ 這幾個(gè)目錄中尋找有沒有 aaa.txt 這個(gè)資源,如果有就返回結(jié)果,沒有顯示 404?
?
3、自定義對(duì)靜態(tài)資源的處理
方式一、修改 application.properties 配置文件的方式
注意:如果在配置文件中進(jìn)行如下配置,則 springboot 默認(rèn)配置將被覆蓋,原先默認(rèn)的靜態(tài)路徑訪問前綴 /** 和默認(rèn)的靜態(tài)資源文件目錄都將失效
#?該配置項(xiàng)的默認(rèn)值是?true,如果設(shè)置為?false?則代表關(guān)閉?Springboot?對(duì)?webjars?和靜態(tài)資源的配置
#?如果配置了該項(xiàng)的話,可以開啟?debug?日志級(jí)別,控制臺(tái)可以看到禁用了?Springboot?的默認(rèn)配置
spring.resources.add-mappings=false
#?開啟?debug?級(jí)別的日志信息
debug=true
?
#?修改靜態(tài)資源訪問前綴,配置了該選項(xiàng)之后,比如你想訪問靜態(tài)資源文件夾下的?aaa.txt,需要帶上?bluefatty?前綴
#?例如:http://localhost:8080/bluefatty/aaa.txt?就是訪問靜態(tài)資源文件夾下的?aaa.txt
#?配置了該配置項(xiàng)之后,Springboot?默認(rèn)的首頁(yè)訪問將失效
spring.mvc.static-path-pattern=/bluefatty/**
?
#?修改?Springboot?默認(rèn)的靜態(tài)資源文件夾,啟用了該配置之后?Springboot?默認(rèn)的靜態(tài)資源文件夾將失效
spring.resources.static-locations=classpath:/META-INF/resources02/,\
??????????????????????????????????classpath:/resources02/,\
??????????????????????????????????classpath:/static02/,\
??????????????????????????????????classpath:/public02/,\
??????????????????????????????????file:D://xiaomaomao/
方式二、代碼注冊(cè)的方式
注意:如果使用?WebMvcConfigurer 進(jìn)行自定義規(guī)則,那么原先 Springboot 默認(rèn)的配置和我們自定義的配置將一同起效
如果你不想使用配置文件,我們還可以通過代碼的方式來(lái)進(jìn)行自定義,具體步驟如下
自定義一個(gè)配置類 xxxWebMvcConfigurerAdapter?extends WebMvcConfigurerAdapter(或者實(shí)現(xiàn) WebMvcConfigurer ,其實(shí)是一個(gè)意思,因?yàn)?WebMvcConfigurerAdapter 實(shí)現(xiàn)了 WebMvcConfigurer 接口)
@Configuration
public?class?MyWebMvcConfigurerAdapter?extends?WebMvcConfigurerAdapter?{
????@Override
????public?void?addResourceHandlers(ResourceHandlerRegistry?registry){
????????registry.addResourceHandler("/**")
????????????????//?1、src/main/webapp/?路徑下
????????????????.addResourceLocations("resources/",?"static/",?"public/",
????????????????????????"META-INF/resources/")
????????????????//?2、src/main/resources/?路徑下
????????????????.addResourceLocations("classpath:resources/",?"classpath:static/",
????????????????????????"classpath:public/",?"classpath:META-INF/resources/")
????????????????//?3、絕對(duì)路徑
????????????????.addResourceLocations("file:D://xiaomaomao/");
????}
}
上面的配置有三種路徑方式 static/ (無(wú)前綴)、帶有 classpath 前綴、絕對(duì)路徑,這里來(lái)簡(jiǎn)單說明一下
1、無(wú)前綴 ----> "文檔根目錄"(一般指代 src/main/webapp 目錄),例如 localhost:8080/index.html 定位至 src/main/webapp/static/index.html
2、存在前綴 classpath -----> 類路徑(一般指代 src/main/resources 目錄)
3、存在前綴 file:// -----> 文件系統(tǒng)路徑("絕對(duì)路徑")
?
粉絲福利:Java從入門到入土學(xué)習(xí)路線圖
??????

??長(zhǎng)按上方微信二維碼?2 秒
感謝點(diǎn)贊支持下哈?
