通过idea快速搭建一个springboot项目:
springboot版本2.1.6
在网上看的资料,springboot静态资源访问如下:
"classpath:/META‐INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"
"/":当前项目的根路径
之后在测试访问静态资源的时候没有问题,通过代码配置的方式访问登录页面资源的时候出现了404。
在网上找了很多关于静态资源访问404的问题,貌似不是在application.yml(或properties)中配置访问路径,就是自己定义config类。
后来翻看源码发现,由于在代码配置的时候。继承了WebMvcConfigurationSupport这个类,导致整个资源访问失效,具体原因如下:
第一步:
确认springboot静态资源访问的位置,由于springboot自动加载配置,所以找到WebMvcAutoConfiguration这个配置类,里面有很多方法,
只需找到资源映射的方法:
public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); } else { Duration cachePeriod = this.resourceProperties.getCache().getPeriod(); CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
<!-- /webjars/** 访问的,资源映射规则-->
if (!registry.hasMappingForPattern("/webjars/**")) { this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).
addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl)); } <!-- 静态资源映射规则--> String staticPathPattern = this.mvcProperties.getStaticPathPattern(); if (!registry.hasMappingForPattern(staticPathPattern)) { this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).
addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).
setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl)); } } }
第一种webjars加载:所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找资源;
第二种静态资源映射:
staticPathPattern 点击查看源码:staticPathPattern = /**;
resourceProperties.getStaticLocations() 点击查看源码:
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"}; private String[] staticLocations; private boolean addMappings; private final ResourceProperties.Chain chain; private final ResourceProperties.Cache cache; public ResourceProperties() { this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS; this.addMappings = true; this.chain = new ResourceProperties.Chain(); this.cache = new ResourceProperties.Cache(); } public String[] getStaticLocations() { return this.staticLocations; }
通过以上源码看出,访问资源路径跟一开始测试时的一样,没问题,为何通过配置设置登录页面就无法访问静态资源了呢,反复查看WebMvcAutoConfiguration源码发现如下:
@Configuration @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class}) @ConditionalOnMissingBean({WebMvcConfigurationSupport.class}) @AutoConfigureOrder(-2147483638) @AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class}) public class WebMvcAutoConfiguration {=
@ConditionalOnClass 和 @ConditionalOnMissingBean 这两个注解的条件成立WebMvcAutoConfiguration才会自动加载,
在配置登录页的时候,正好继承了WebMvcConfigurationSupport类
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class}) 容器没有加载这个bean时自动加载WebMvcAutoConfiguration,
继承WebMvcAutoConfiguration的方式也可以,不过需要手动添加资源映射路径,WebMvcAutoConfiguration中的其他自动加载项也需要自己处理。
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class}) 容器加载这个bean时自动加载WebMvcAutoConfiguration
重新修改配置类 实现WebMvcConfigurer接口对登录页进行处理,静态资源访问正常。