springboot2版本无法加载静态资源问题解决
前言
在学习springboot的过程中,发现无法引用静态资源。我使用的是springboot2.2.1版本。
追溯源码,终于解决。并记录下解决思路。
默认加载路径
首先得知道springboot默认加载得资源路径是什么。
首先我们看WebMvcAutoConfiguration这个类。里面有一个方法叫做addResourceHandlers()
@Configuration(proxyBeanMethods=false)
@ConditionalOnWebApplication(type=Type.SERVLET)
@ConditionalOnClass({Servlet.class,DispatcherServlet.class,WebMvcConfigurer.class})
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE+10)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class,TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class})
publicclassWebMvcAutoConfiguration{
@Override
publicvoidaddResourceHandlers(ResourceHandlerRegistryregistry){
if(!this.resourceProperties.isAddMappings()){
logger.debug("Defaultresourcehandlingdisabled");
return;
}
DurationcachePeriod=this.resourceProperties.getCache().getPeriod();
CacheControlcacheControl=this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
//所有/webjars/**,都去classpath:/META-INF/resources/webjars/找资源
if(!registry.hasMappingForPattern("/webjars/**")){
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
//静态资源文件夹映射
StringstaticPathPattern=this.mvcProperties.getStaticPathPattern();
if(!registry.hasMappingForPattern(staticPathPattern)){
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
}
首先springboot会将我们classpath:/META-INF/resources/webjars/路径下的文件映射为/webjars/**
然后再一个if判断进行静态资源文件夹映射,首先判断我们是否以使用"/**"做映射
如果没有,则将"/**"访问当前项目的任何资源,都去(如下静态资源的文件夹)找映射
"classpath:/META‐INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" "/":当前项目的根路径
什么意思呢?举一个例子,就是说默认情况下我们假如我们调用http://localhost:8080/a.json
Springboot就会从上面得这几个路径下去找a.json这个文件。
问题所在
源码也是如同猜想得这样,那为什么我的代码中,直接访问静态资源却无法做映射呢?
我们再仔细看看WebMvcAutoConfiguration这个类。在其头上有一个这个注解:
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
卧槽,瞬间恍然大悟。在我得配置文件中:
@Configuration
publicclassMyMVCConfigextendsWebMvcConfigurationSupport{
...
}
继承了WebMvcConfigurationSupport这个类,使得springboot的自动装配失效了。因为@ConditionalOnMissingBean这个注解得作用就是,当容器中不存在这个类,如下得代码才有作用。
为什么会这样设计呢?
因为有时候我们得项目并不希望springboot给我们自动装配。希望完全由我们自己来配置自己来掌握。
要想达到这个效果,springboot给我们提供了一个更为简洁得方式。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public@interfaceEnableWebMvc{
}
@EnableWebMvc注解会导入DelegatingWebMvcConfiguration.clss
而DelegatingWebMvcConfiguration又继承了WebMvcConfigurationSupport
publicclassDelegatingWebMvcConfigurationextendsWebMvcConfigurationSupport{
所以当我们加上@EnableWebMvc也会有同样得效果且简洁。
自定义配置资源映射
springboot当然也支持我们个性化得指定映射路径,我总结了如下几个方式:
配置类
@Configuration
publicclassMyMVCConfigextendsWebMvcConfigurationSupport{
@Override
publicvoidaddResourceHandlers(ResourceHandlerRegistryregistry){
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
}
上面的意思就是:将所有/static下得文件全部映射到/static/**
配置项
在application.properties文件中加上如下配置项
spring.mvc.static-path-pattern=/** spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
spring.mvc.static-path-pattern=/**:表示所有的访问都经过静态资源路径;
spring.resources.static-locations:在这里配置静态资源路径。