侧边栏壁纸
博主头像
张种恩的技术小栈博主等级

行动起来,活在当下

  • 累计撰写 748 篇文章
  • 累计创建 65 个标签
  • 累计收到 39 条评论

目 录CONTENT

文章目录

SpringBoot(12)之资源映射

zze
zze
2018-02-27 / 0 评论 / 0 点赞 / 291 阅读 / 8247 字

静态资源映射

源码分析

查看 SpringMVC 的自动配置类,里面有一个配置静态资源映射的方法:

// org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#addResourceHandlers
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    if (!this.resourceProperties.isAddMappings()) {
        logger.debug("Default resource handling disabled");
        return;
    }
    Integer cachePeriod = this.resourceProperties.getCachePeriod();
    // <1 - begin>
    if (!registry.hasMappingForPattern("/webjars/**")) {
        // 将路径为 "/webjars/**" 匹配到的资源在 "classpath:/META-INF/resources/webjars/"
        customizeResourceHandlerRegistration(registry
                .addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/")
                .setCachePeriod(cachePeriod));
    }
    // <1 - end>
    // <2 - begin>
    // 从配置中获取静态路由规则
    String staticPathPattern = this.mvcProperties.getStaticPathPattern();
    if (!registry.hasMappingForPattern(staticPathPattern)) {
        // 将路径为 staticPathPattern 匹配到的资源在 this.resourceProperties.getStaticLocations()
        customizeResourceHandlerRegistration(
                registry.addResourceHandler(staticPathPattern)
                        .addResourceLocations(
                                this.resourceProperties.getStaticLocations())
                        .setCachePeriod(cachePeriod));
    }
    // <2 - end>
}

看到 <1> 块,有一个默认配置,将能匹配 /webjars/** 路径的请求映射到 classpath:/META-INF/resources/webjars/ 中。

接着在 <2> 块又将 this.mvcProperties.getStaticPathPattern() 变量对应值的路径映射 this.resourceProperties.getStaticLocations() 对应值的目录下。

this.mvcProperties 对应的配置类为 org.springframework.boot.autoconfigure.web.WebMvcProperties,可以看到 this.mvcProperties.getStaticPathPattern() 对应的值为 /**

this.resourceProperties 对应的配置类为 org.springframework.boot.autoconfigure.web.ResourceProperties,可以看到 this.resourceProperties.getStaticLocations() 对应的值为 {"classpath:/META-INF/resources/", "classpath:/resources/","classpath:/static/", "classpath:/public/"}

<2> 块就是将能匹配 /** 的请求路径映射到项目路径下 classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/ 中。

结论

请求路径如果匹配 /webjars/** 规则,那么 SpringBoot 就会去 classpath:/META-INF/resources/webjars/ 目录下寻找对应资源。

请求路径如果匹配 /** 规则(即任意请求路径),那么 SpringBoot 就会去 classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/ 目录下寻找对应资源。

欢迎页

源码分析

依旧是 SpringMVC 配置类中,有一个注册欢迎页映射 bean 的方法:

// org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#welcomePageHandlerMapping
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(
        ResourceProperties resourceProperties) {
    return new WelcomePageHandlerMapping(resourceProperties.getWelcomePage(),
            this.mvcProperties.getStaticPathPattern());
}

查看 resourceProperties.getWelcomePage() 方法:

// org.springframework.boot.autoconfigure.web.ResourceProperties#getWelcomePage
public Resource getWelcomePage() {
    for (String location : getStaticWelcomePageLocations()) {
        Resource resource = this.resourceLoader.getResource(location);
        try {
            if (resource.exists()) {
                resource.getURL();
                return resource;
            }
        }
        catch (Exception ex) {
            // Ignore
        }
    }
    return null;
}

接着查看 getStaticWelcomePageLocations() 方法:

// org.springframework.boot.autoconfigure.web.ResourceProperties#getStaticWelcomePageLocations
private static final String[] SERVLET_RESOURCE_LOCATIONS = { "/" };

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
            "classpath:/META-INF/resources/", "classpath:/resources/",
            "classpath:/static/", "classpath:/public/" };

private static final String[] RESOURCE_LOCATIONS;

static {
    RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length
            + SERVLET_RESOURCE_LOCATIONS.length];
    System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, 0,
            SERVLET_RESOURCE_LOCATIONS.length);
    System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS,
            SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length);
}


private String[] staticLocations = RESOURCE_LOCATIONS;

private String[] getStaticWelcomePageLocations() {
    String[] result = new String[this.staticLocations.length];
    for (int i = 0; i < result.length; i++) {
        String location = this.staticLocations[i];
        if (!location.endsWith("/")) {
            location = location + "/";
        }
        result[i] = location + "index.html";
    }
    return result;
}

resourceProperties.getWelcomePage() 方法默认就是从静态资源目录下即 classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/ 目录中寻找名为 index.html 的资源。

结论

SpringBoot 中默认的欢迎页为 classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/ 目录下名为的 index.html 的页面。

站点图标

源码分析

在 SpringMVC 配置类中还有一个页面图标配置类:

// org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter.FaviconConfiguration
@Configuration
@ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true)  // 默认开启图标显示
public static class FaviconConfiguration {

    private final ResourceProperties resourceProperties;

    public FaviconConfiguration(ResourceProperties resourceProperties) {
        this.resourceProperties = resourceProperties;
    }

    @Bean
    public SimpleUrlHandlerMapping faviconHandlerMapping() {
        SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
        // <1>
        mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",
                faviconRequestHandler()));
        return mapping;
    }

    @Bean
    public ResourceHttpRequestHandler faviconRequestHandler() {
        ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
        // <2>
        requestHandler.setLocations(this.resourceProperties.getFaviconLocations());
        return requestHandler;
    }

}

faviconHandlerMapping 方法便是用来处理图标映射,在 <1> 处给匹配 **/favicon.ico 的请求路径指定了图标请求处理器 faviconRequestHandler() ,在 <2> 处设置了图标请求处理器寻找图标的目录为 this.resourceProperties.getFaviconLocations() ,查看该方法:

// org.springframework.boot.autoconfigure.web.ResourceProperties#getFaviconLocations
List<Resource> getFaviconLocations() {
    List<Resource> locations = new ArrayList<Resource>(
            this.staticLocations.length + 1);
    if (this.resourceLoader != null) {
        for (String location : this.staticLocations) {
            locations.add(this.resourceLoader.getResource(location));
        }
    }
    locations.add(new ClassPathResource("/"));
    return Collections.unmodifiableList(locations);
}

可以看到,该方法返回的是静态文件夹目录资源。

结论

在 SpringBoot 工程中的静态资源目录放置一个名为 favicon.ico 的网页图标,该图标就会被 SpringBoot 使用。

0

评论区