1.相关概念

  • Spring Boot 默认为我们提供了静态资源处理,使用 WebMvcAutoConfiguration 中的配置各种属性。
  • 建议使用Spring Boot的默认配置方式,如果需要特殊处理的再通过配置文件进行修改。
  • 如果想要自己完全控制WebMVC,就需要在@Configuration注解的配置类上增加@EnableWebMvc, 增加该注解以后WebMvcAutoConfiguration中配置就不会生效,你需要自己来配置需要的每一项(可以使用继承)。

2.静态资源目录

  • 默认只要静态资源放在类路径(resources)下:
    /static
    /public
    /resources
    /META-INF/resources
  • 浏览器访问: 当前项目根路径/ + 静态资源名

springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_java


springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_ide_02

springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_java_03


springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_静态资源_04


springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_ide_05


请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404页面。

我们在controller里写个测试方法来测试一下

springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_静态资源_06


springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_java_07


把controller里的方法注释后

springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_静态资源_08


springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_静态资源_09

也可以改变默认的静态资源路径,/static,/public,/resources, /META-INF/resources失效
application.properties

#静态资源路径
spring.resources.static-locations=classpath:/dir1/,classpath:/dir2/

springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_前端_10

springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_java_11


springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_spring boot_12

springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_静态资源_13

3.静态资源访问前缀

application.properties

#静态资源访问前缀, 就是浏览器网址路径加前缀
spring.mvc.static-path-pattern=/res/**

springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_前端_10


springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_java_15

4.欢迎页支持

就是网址上没有访问映射时, 会自动跳转到欢迎页,

静态资源路径下 index.html。

  • 可以配置静态资源路径
  • 但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默认访问

springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_spring boot_16

springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_java_17

5.自定义favicon

指网页标签上的小图标。

favicon.ico 放在静态资源目录下即可。

springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_前端_18

springboot配置静态资源占用线程嘛 springboot webapp静态资源配置_spring boot_19

6.源码分析

  • SpringBoot启动默认加载 xxxAutoConfiguration 类(自动配置类)
  • SpringMVC功能的自动配置类WebMvcAutoConfiguration生效
@AutoConfiguration(
    after = {DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class}
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
public class WebMvcAutoConfiguration {
    public static final String DEFAULT_PREFIX = "";
    public static final String DEFAULT_SUFFIX = "";
    public static final PathPatternParser pathPatternParser = new PathPatternParser();
    private static final String SERVLET_LOCATION = "/";

    public WebMvcAutoConfiguration() {
    }

给容器中配置的内容:

  • 配置文件的相关属性的绑定:WebMvcProperties == spring.mvc、WebProperties==spring.web
@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
    @EnableConfigurationProperties({WebMvcProperties.class, WebProperties.class})
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {
        private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
        private final Resources resourceProperties;
        private final WebMvcProperties mvcProperties;
        private final ListableBeanFactory beanFactory;
        private final ObjectProvider<HttpMessageConverters> messageConvertersProvider;
        private final ObjectProvider<DispatcherServletPath> dispatcherServletPath;
        private final ObjectProvider<ServletRegistrationBean<?>> servletRegistrations;
        private final WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
        private ServletContext servletContext;

配置类只有一个有参构造器

public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
            this.resourceProperties = webProperties.getResources();
            this.mvcProperties = mvcProperties;
            this.beanFactory = beanFactory;
            this.messageConvertersProvider = messageConvertersProvider;
            this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
            this.dispatcherServletPath = dispatcherServletPath;
            this.servletRegistrations = servletRegistrations;
            this.mvcProperties.checkConfiguration();
        }
  • ResourceProperties resourceProperties;获取和spring.resources绑定的所有的值的对象
  • WebMvcProperties mvcProperties 获取和spring.mvc绑定的所有的值的对象
  • ListableBeanFactory beanFactory Spring的beanFactory
  • HttpMessageConverters 找到所有的HttpMessageConverters
  • ResourceHandlerRegistrationCustomizer 找到 资源处理器的自定义器。
  • DispatcherServletPath
  • ServletRegistrationBean 给应用注册Servlet、Filter…

资源处理的默认规则

public void addResourceHandlers(ResourceHandlerRegistry registry) {
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
            } else {
                this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
                this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
                    registration.addResourceLocations(this.resourceProperties.getStaticLocations());
                    if (this.servletContext != null) {
                        ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
                        registration.addResourceLocations(new Resource[]{resource});
                    }

                });
            }
        }

根据上述代码,我们可以同过配置禁止所有静态资源规则。
application.properties

#禁用所有静态资源规则
spring.web.resources.add-mappings=false

静态资源处理规则:

public static class Resources {
        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 boolean customized;
        private final WebProperties.Resources.Chain chain;
        private final WebProperties.Resources.Cache cache;

欢迎页处理规则:

@Bean
        public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
            WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
            welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
            welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());
            return welcomePageHandlerMapping;
        }
WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders, ApplicationContext applicationContext, Resource welcomePage, String staticPathPattern) {
        if (welcomePage != null && "/**".equals(staticPathPattern)) {
            logger.info("Adding welcome page: " + welcomePage);
            this.setRootViewName("forward:index.html");
        } else if (this.welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {
            logger.info("Adding welcome page template: index");
            this.setRootViewName("index");
        }

    }