静态资源映射
源码分析
查看 SpringMVC 的自动配置类,里面有一个配置静态资源映射的方法:
// org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#addResourceHandlers
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Integer cachePeriod = this.resourceProperties.getCachePeriod();
// <1 - begin>
if (!registry.hasMappingForPattern("/webjars/**")) {
// 将路径为 "/webjars/**" 匹配到的资源在 "classpath:/META-INF/resources/webjars/"
customizeResourceHandlerRegistration(registry
.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(cachePeriod));
}
// <1 - end>
// <2 - begin>
// 从配置中获取静态路由规则
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
// 将路径为 staticPathPattern 匹配到的资源在 this.resourceProperties.getStaticLocations()
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(
this.resourceProperties.getStaticLocations())
.setCachePeriod(cachePeriod));
}
// <2 - end>
}
看到 <1>
块,有一个默认配置,将能匹配 /webjars/**
路径的请求映射到 classpath:/META-INF/resources/webjars/
中。
接着在 <2>
块又将 this.mvcProperties.getStaticPathPattern()
变量对应值的路径映射 this.resourceProperties.getStaticLocations()
对应值的目录下。
this.mvcProperties
对应的配置类为 org.springframework.boot.autoconfigure.web.WebMvcProperties
,可以看到 this.mvcProperties.getStaticPathPattern()
对应的值为 /**
。
this.resourceProperties
对应的配置类为 org.springframework.boot.autoconfigure.web.ResourceProperties
,可以看到 this.resourceProperties.getStaticLocations()
对应的值为 {"classpath:/META-INF/resources/", "classpath:/resources/","classpath:/static/", "classpath:/public/"}
。
即 <2>
块就是将能匹配 /**
的请求路径映射到项目路径下 classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/
中。
结论
请求路径如果匹配 /webjars/**
规则,那么 SpringBoot 就会去 classpath:/META-INF/resources/webjars/
目录下寻找对应资源。
请求路径如果匹配 /**
规则(即任意请求路径),那么 SpringBoot 就会去 classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/
目录下寻找对应资源。
欢迎页
源码分析
依旧是 SpringMVC 配置类中,有一个注册欢迎页映射 bean 的方法:
// org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#welcomePageHandlerMapping
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(
ResourceProperties resourceProperties) {
return new WelcomePageHandlerMapping(resourceProperties.getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
}
查看 resourceProperties.getWelcomePage()
方法:
// org.springframework.boot.autoconfigure.web.ResourceProperties#getWelcomePage
public Resource getWelcomePage() {
for (String location : getStaticWelcomePageLocations()) {
Resource resource = this.resourceLoader.getResource(location);
try {
if (resource.exists()) {
resource.getURL();
return resource;
}
}
catch (Exception ex) {
// Ignore
}
}
return null;
}
接着查看 getStaticWelcomePageLocations()
方法:
// org.springframework.boot.autoconfigure.web.ResourceProperties#getStaticWelcomePageLocations
private static final String[] SERVLET_RESOURCE_LOCATIONS = { "/" };
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/" };
private static final String[] RESOURCE_LOCATIONS;
static {
RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length
+ SERVLET_RESOURCE_LOCATIONS.length];
System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, 0,
SERVLET_RESOURCE_LOCATIONS.length);
System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS,
SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length);
}
private String[] staticLocations = RESOURCE_LOCATIONS;
private String[] getStaticWelcomePageLocations() {
String[] result = new String[this.staticLocations.length];
for (int i = 0; i < result.length; i++) {
String location = this.staticLocations[i];
if (!location.endsWith("/")) {
location = location + "/";
}
result[i] = location + "index.html";
}
return result;
}
即 resourceProperties.getWelcomePage()
方法默认就是从静态资源目录下即 classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/
目录中寻找名为 index.html
的资源。
结论
SpringBoot 中默认的欢迎页为 classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/
目录下名为的 index.html
的页面。
站点图标
源码分析
在 SpringMVC 配置类中还有一个页面图标配置类:
// org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter.FaviconConfiguration
@Configuration
@ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true) // 默认开启图标显示
public static class FaviconConfiguration {
private final ResourceProperties resourceProperties;
public FaviconConfiguration(ResourceProperties resourceProperties) {
this.resourceProperties = resourceProperties;
}
@Bean
public SimpleUrlHandlerMapping faviconHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
// <1>
mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",
faviconRequestHandler()));
return mapping;
}
@Bean
public ResourceHttpRequestHandler faviconRequestHandler() {
ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
// <2>
requestHandler.setLocations(this.resourceProperties.getFaviconLocations());
return requestHandler;
}
}
faviconHandlerMapping
方法便是用来处理图标映射,在 <1>
处给匹配 **/favicon.ico
的请求路径指定了图标请求处理器 faviconRequestHandler()
,在 <2>
处设置了图标请求处理器寻找图标的目录为 this.resourceProperties.getFaviconLocations()
,查看该方法:
// org.springframework.boot.autoconfigure.web.ResourceProperties#getFaviconLocations
List<Resource> getFaviconLocations() {
List<Resource> locations = new ArrayList<Resource>(
this.staticLocations.length + 1);
if (this.resourceLoader != null) {
for (String location : this.staticLocations) {
locations.add(this.resourceLoader.getResource(location));
}
}
locations.add(new ClassPathResource("/"));
return Collections.unmodifiableList(locations);
}
可以看到,该方法返回的是静态文件夹目录资源。
结论
在 SpringBoot 工程中的静态资源目录放置一个名为 favicon.ico
的网页图标,该图标就会被 SpringBoot 使用。
评论区