一、静态资源的映射规则
1.对哪些目录映射?
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
/:当前项目的根路径
意思是:我们在上面的五个目录下放静态资源文件(比如:jq.js等),可以直接访问(http://localhost:8080/jq.js),类似以前web项目的webapp下,放到其他目录无法被访问。
2.为什是这几个目录呢?
2.1看源码就知道
SpringBoot自动配置的WebMvcAutoConfirarution.java类:
@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));
}
}
ResourceProperties
@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/" };
...
}
总的来说:
WebMvcAutoConfiguration类自动为我们注册了如下目录为静态资源目录,也就是说直接可访问到资源的目录。
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
/:当前项目的根路径
优先级从上到下。
所以,如果static里面有个index.html,public下面也有个index.html,则优先会加载static下面的index.html,因为优先级!
看源码:
public class WebMvcAutoConfiguration {
//...
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(
ApplicationContext applicationContext) {
return new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext),
applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
}
private Optional getWelcomePage() {
// 遍历默认静态资源目录后面拼接个index.html的数组
// 比如:[/static/index.html, /public/index.html等等]
String[] locations = getResourceLocations(
this.resourceProperties.getStaticLocations());
return Arrays.stream(locations).map(this::getIndexHtml)
.filter(this::isReadable).findFirst();
}
// 下面这段代码通俗易懂,就是给默认静态资源目录后面拼接个index.html并返回,比如:/static/index.html
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;
}
翻译内容成如下映射规则:
return new WelcomePageHandlerMapping(
"classpath:/META-INF/resources/index.html",
"classpath:/resources/index.html",
"classpath:/static/index.html",
"classpath:/public/index.html",
"/index.html"
, "/**");
也就是WebMvcAutoConfiguration类自动为我们注册了如下文件为默认首页
classpath:/META-INF/resources/index.html
classpath:/resources/index.html
classpath:/static/index.html
classpath:/public/index.html
/index.html
优先级从上到下。
所以,如果static里面有个index.html,public下面也有个index.html,则优先会加载static下面的index.html,因为优先级!
如果使用了spring-boot-starter-thymeleaf,并且编写IndexController,那么就会访问templates下的index.html
org.springframework.boot
spring-boot-starter-thymeleaf
IndexController
@Controller
public class IndexController {
@RequestMapping({"", "/"})
public String index() {
return "index";
}
}
默认如果不添加spring-boot-starter-thymeleaf,也不添加IndexController,可以会到static下的index.html,添加了spring-boot-starter-thymeleaf,不编写IndexController,默认会跳到static/index.html,而不是templates/index.html