一、靜態資源的加載
Spring Boot在引入了Web模塊後,就會在啓動的時候自動加載與Web有關的配置,所有的配置內容可在
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration中查看。下面要說的是有關靜態資源加載的邏輯。首先看一下這個類
org.springframework.boot.autoconfigure.web.ResourceProperties
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {
可以看到這個類是在加載配置文件中有關靜態資源的參數,比如緩存時間等。參數前綴是spring.resources
。
在WebMvcAutoConfiguration這個類中,可以找到addResourceHandlers這個資源映射方法:
@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();
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry
.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod))
.setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(
this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod))
.setCacheControl(cacheControl));
}
}
webjars 方式
在其中可以看到,所有包含有/webjars/**
的訪問路徑若沒有處理器處理的話都會去classpath:/META-INF/resources/webjars/
這個目錄下尋找資源。
Webjars官網。
WebJars是將Web前端js和CSS等資源打包成Java的Jar包,這樣在Web開發中我們可以藉助Maven對這些依賴庫進行管理,保證這些Web資源版本唯一性,比如jQuery、Bootstrap等。
我們在項目的pom文件引入jquery.jar:
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
可以展開看一下jquery-3.3.1.jar的資源結構:
可以看到,所有的資源都在classpath:/META-INF/resources/webjars/這個目錄下。我們啓動tomcat訪問一下
localhost:8080/webjars/jquery/3.3.1/jquery.js
看看能否訪問的到!
很順利的訪問出來了,說明上面說的所有包含有/webjars/**
的訪問路徑都會去classpath:/META-INF/resources/webjars/
這個目錄下尋找資源是沒錯的。
“/**”訪問任何資源
接着看一下這個方法的後半部分的代碼:
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(
this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod))
.setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
這段代碼得到的是"/**"
這個字符串,也就是說,你訪問的任何路徑若是沒有處理器來處理的話 ,默認會去這裏來找資源:this.resourceProperties.getStaticLocations()
,即:
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/" };
/**
* Locations of static resources. Defaults to classpath:[/META-INF/resources/,
* /resources/, /static/, /public/].
*/
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"
我們可以嘗試在項目類路徑下分別建立這些文件夾,並放入一些靜態資源以作訪問:
在瀏覽器中依次訪問:http://localhost:8080/111.png
,確實是可以訪問的到的。
二、歡迎頁的加載
在WebMvcAutoConfiguration這個類中,可以找到welcomePageHandlerMapping這個歡迎頁映射方法:
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(
ApplicationContext applicationContext) {
return new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext),
applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
}
static String[] getResourceLocations(String[] staticLocations) {
String[] locations = new String[staticLocations.length
+ SERVLET_LOCATIONS.length];
System.arraycopy(staticLocations, 0, locations, 0, staticLocations.length);
System.arraycopy(SERVLET_LOCATIONS, 0, locations, staticLocations.length,
SERVLET_LOCATIONS.length);
return locations;
}
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");
}
首先看一下getWelcomePage()
這個方法,其邏輯就是循環各個靜態資源路徑,在其後匹配上index.html,然後首先在哪個靜態資源路徑下找到了index.html就將此index.html返回。
我們可以在classpath:/static/這個目錄下新建一個index.html文件,然後直接訪問localhost:8080
,可以看到定位到了index.html文件。
三、應用圖標的加載 favicon.ico
在WebMvcAutoConfiguration這個類中,可以找到FaviconConfiguration這個圖標配置的內部類:
@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);
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);
}
}
邏輯和歡迎頁差不多,只要你將你的圖標置於靜態資源文件夾中,就會將你自己的favicon.ico這個圖標文件作爲應用程序的圖標。