springboot web开发静态资源的映射规则

前言

我们之间介绍过SpringBoot自动配置的原理,基本上是如下:

xxxxAutoConfiguration:帮我们给容器中自动配置组件;
xxxxProperties:配置类来封装配置文件的内容;
web开发中都在org.springframework.boot.autoconfigure.web包下
今天看的静态资源映射规则都在org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration类中配置

态资源的映射规则

官方给了几个默认位置

classpath:/META-INF/resources/ 
classpath:/resources/
classpath:/static/ 
classpath:/public/
/:当前项目的根路径

什么意思

就我们在上面五个目录下放静态资源(比如:a.js等),可以直接访问(http://localhost:8080/a.js),类似于以前web项目的webapp下;放到其他目录下无法被访问。

分析下源码

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration类中有
public void addResourceHandlers(ResourceHandlerRegistry registry) 这个方法是核心
但是这个方法是WebMvcAutoConfigurationg中的一个内部类(WebMvcAutoConfigurationAdapter )的方法:

封装配置属性的类:WebMvcProperties.class, ResourceProperties.class

 @Configuration(
        proxyBeanMethods = false
    )
    @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
    @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {

addResourceHandlers方法分析:

public void addResourceHandlers(ResourceHandlerRegistry registry) {
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
            } else {
                Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
                //对webjars文件的映射,比如jquery,easyui等这些js,没错js也可以达成jar的方式
                CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
                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(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                }

            }
        }

针对webjars 部分分析

 //对webjars文件的映射,比如jquery,easyui等这些js,没错js也可以达成jar的方式
                CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
                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));
                }

所有/webjars/**都从classpath:/META-INF/resources/webjars/路径下去找对应的静态资源。

什么是webjars?
就是以jar包的方式引入静态资源。

官网地址:http://www.webjars.org/。类似于maven仓库。

springboot web开发静态资源的映射规则_第1张图片

我们可以做个例子,将jquery引入到项目中

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>3.5.1</version>
</dependency>

项目依赖
springboot web开发静态资源的映射规则_第2张图片

会自动为我们引入jquery,要怎么使用呢?我们上面说过:
所有/webjars/*都从classpath:/META-INF/resources/webjars/路径下去找对应的静态资源。
所以我们启动项目,访问:http://localhost:8080/webjars/jquery/3.4.0/jquery.js即可。
这么说以后我们引用js框架都可以使用这种方式引用了

针对我们自己的静态资源进行的映射

//这部分是针对我们自己的静态资源进行的映射
                String staticPathPattern = this.mvcProperties.getStaticPathPattern();
                if (!registry.hasMappingForPattern(staticPathPattern)) {
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                }

String staticPathPattern = this.mvcProperties.getStaticPathPattern();
springboot web开发静态资源的映射规则_第3张图片
“/**” 访问当前项目的任何资源,都去(静态资源的文件夹)找映射

ResourceProperties
public String[] getStaticLocations() {
        return this.staticLocations;
    }

构造方法:
 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();
    }
WebMvcAutoConfiguration.getResourceLocations(new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"})
private static final String[] SERVLET_LOCATIONS = new String[]{"/"};
static String[] getResourceLocations(String[] staticLocations) {
        String[] locations = new String[staticLocations.length + SERVLET_LOCATIONS.length];
        System.arraycopy(staticLocations, 0, locations, 0, staticLocations.length);
        System.arraycopy(SERVLET_LOCATIONS, 0, locations, staticLocations.length, SERVLET_LOCATIONS.length);
        return locations;
    }
所以上述代码经过我的翻译后成为了如下样子:

registry.addResourceHandler("/**").addResourceLocations(
    "classpath:/META-INF/resources/", "classpath:/resources/",
            "classpath:/static/", "classpath:/public/", "/")
    // 设置缓存时间
    .setCachePeriod(cachePeriod));

WebMvcAutoConfiguration类自动为我们注册了如下目录为静态资源目录,也就是说直接可访问到资源的目录。

classpath:/META-INF/resources/ 
classpath:/resources/
classpath:/static/ 
classpath:/public/
/:当前项目的根路径

优先级从上到下。
所以,如果static里面有个index.html,public下面也有个index.html,则优先会加载static下面的index.html,因为优先级!
那我们就做个实验试试吧
分别放一个a.js
这里就自行实验吧

欢迎首页

欢迎页; 静态资源文件夹下的所有index.html页面;被"/**"映射;

@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;
        }
 private Optional<Resource> getWelcomePage() {
            String[] locations = WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations());
            return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
        }

        private Resource getIndexHtml(String location) {
            return this.resourceLoader.getResource(location + "index.html");
        }
classpath:/META-INF/resources/index.html
classpath:/resources/index.html
classpath:/static/index.html 
classpath:/public/index.html
/index.html

优先级从上到下。

所以,如果static里面有个index.html,public下面也有个index.html,则优先会加载static下面的index.html,因为优先级!

favicon.ico

所有的 **/favicon.ico 都是在静态资源文件下找
2.2.x 前的版本
在此之前版本下默认是有一个默认的 favicon.ico 文件的,也就是咱们常说的绿叶子图标,相关的代码在 WebMvcAutoConfiguration 这个配置类中
2.2.x 版本以后
关于图标文件的处理,较新的版本做过一些改动,所以在 WebMvcAutoConfiguration 这个配置类中已经找不到关于 icon 相关的内容了,我们去 Github 看一下其改动

这里不赘述了…有需要的 可以去百度或者github上自行学习吧
springboot web开发静态资源的映射规则_第4张图片
这就是2.3.2官方描述
大致的意思就是:
和其他的静态资源一样,springboot在配置的静态资源中查找favicon.ico,如果存在这样的一个文件,它会自动用作应用程序的收藏夹

你可能感兴趣的:(#,SpringBoot,spring,boot,前端,后端)