1.源码分析
- 创建一个新项目:springboot-03-web
- 创建一个controller,测试web环境是否搭建成功
package com.thhh.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @RequestMapping("/test01") public String test01(){ return "Hello springBoot-web"; } }
- 因为整个项目的结构是maven项目,所以存放静态资源我们应该首先想到放在resources文件夹下,打开这个文件夹我们可以发现,除了项目配置文件application之外,这个文件夹下面还有另外两个子文件夹
- 显然,我们的网页静态资源应该放在static文件下,templates文件夹用来存放模板引擎
- 但是我们需要注意,在springBoot项目中所有的配置都应经在自动配置类中写好了,所以为了理解springBoot项目对于web资源的加载问题,我们可以去分析一波源码
- 对于web项目,我们首先就应该去找我们熟悉的web自动配置类WebMvcAutoConfiguration
- 这个类有一个内部类WebMvcAutoConfigurationAdapter,这个类在我们分析自动装配的原理xxxProperties类的时候提到过,上一次讲的是它的注解@EnableConfigurationProperties里面的类WebMvcProperties,这一次需要查看WebMvcAutoConfigurationAdapter这个类中的一个方法: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)); } }
- 判断是否自定义的静态资源路径
if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); return; } isAddMappings()默认返回true,只要我们没有在application中通过spring.mvc.static-path-pattern="" 设置自定义的静态资源路径,这个方法就不会结束,如果设置了指定的静态资源路径,程序将会按照我们 设置的路径去加载静态资源
- 判断有没有使用webjars,WebJars就是一种静态资源管理机制,它把我们的静态资源打成jar包,统一管理, webjars官网. 在官网上我们几乎可以找到所有我们需要引用的静态资源打成的jar包,导入的时候直接像maven一样导入pom.xml即可
if (!registry.hasMappingForPattern("/webjars/**")) { customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/") .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); }
-
webjars这种静态资源管理方式我们其实在开发中使用的也不多,所以一般项目也会跳过第二层判断,进行最后一层判断
String staticPathPattern = this.mvcProperties.getStaticPathPattern(); if (!registry.hasMappingForPattern(staticPathPattern)) { customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern) .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())) .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); }
-
明显可以看出,最后一层判断静态路径,我们可以去看看静态路径是什么
private String staticPathPattern = "/**";
这表明静态路径就是请求所有的资源文件的时候就进行映射,映射的路径为this.resourceProperties.getStaticLocations()
-
查看this.resourceProperties.getStaticLocations()对应的映射路径
public String[] getStaticLocations() { return this.staticLocations; } ============================= /** * Locations of static resources. Defaults to classpath:[/META-INF/resources/, * /resources/, /static/, /public/]. */ private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS; ============================= private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" };
-
可见静态常量数组CLASSPATH_RESOURCE_LOCATIONS里存了4个路径
-
首先classpath表示的是maven项目的 src/main/ 作为当前路径,我们也都知道maven生产target文件夹的时候会去掉文件夹java和文件夹resources,所以上面4个文件路径可以直接定义在文件夹java和文件夹resources下面,按照maven项目资管,资源文件就存放在文件夹resources下面,所以我们可以在文件夹resources下面创建上面的4个文件夹路径
可见static文件夹已经在classpath下面了,它对应了数组中的"classpath:/static/",还有两个同级路径(“classpath:/resources/” 和 “classpath:/public/”),但是没有这个两个文件夹,另外一个两级目录也没有,简单,都创建出来
- 创建一个资源文件,比如js文件(命名为test.js,各个文件夹下的内容不同),然后在这4个地方都存放这个文件,然后直接去请求localhost:8080/test.js,看是哪一个文件被请求到了,以此区别4个资源文件夹的优先级
- 重启项目请求资源localhost:8080/test.js
- 删除 “classpath:/META-INF/resources/” 下的资源文件
- 删除 “classpath:/resources/” 下的资源文件
- 删除 “classpath:/static/” 下的资源文件
2.小结
- 在spring Boot项目存放静态资源的路径有3种:自定义、webjars、默认的资源路径
- 【webjars】localhost:8080/webjars/
- 【默认的资源路径】localhost:8080/
- 将会去 “classpath:/META-INF/resources/”、“classpath:/resources/”、“classpath:/static/”、“classpath:/public/” 4个目录下面找静态资源文件
- 4个文件夹访问优先级:“classpath:/META-INF/resources/” > “classpath:/resources/” > “classpath:/static/” > “classpath:/public/”
- 自动创建好的springBoot项目默认只有static文件夹,所以默认就是去static文件夹中找静态资源
- 【自定义】自定义之后上面两个全部失效