springboot 2.X 在访问静态资源的的时候出现404的问题

时间:2021-03-27 22:06:24

通过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接口对登录页进行处理,静态资源访问正常。