關於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 })
public class WebMvcAutoConfiguration {
                @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();
            
            //所有 /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));
            }
            
            //靜態資源文件夾映射
            String staticPathPattern = 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
public class MyMVCConfig extends WebMvcConfigurationSupport{
    ...
}

繼承了WebMvcConfigurationSupport這個類,使得springboot的自動裝配失效了。因爲@ConditionalOnMissingBean這個註解得作用就是,當容器中不存在這個類,如下得代碼纔有作用。

爲什麼會這樣設計呢?

因爲有時候我們得項目並不希望springboot給我們自動裝配。希望完全由我們自己來配置自己來掌握。

要想達到這個效果,springboot給我們提供了一個更爲簡潔得方式。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

@EnableWebMvc註解會導入DelegatingWebMvcConfiguration.clss
而DelegatingWebMvcConfiguration又繼承了WebMvcConfigurationSupport

public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

所以當我們加上@EnableWebMvc也會有同樣得效果且簡潔。

自定義配置資源映射

springboot當然也支持我們個性化得指定映射路徑,我總結了如下幾個方式:

配置類

@Configuration
public class MyMVCConfig extends WebMvcConfigurationSupport{

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {      
    
    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:在這裏配置靜態資源路徑。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章