首页 > 解决方案 > Spring Boot 2.4 应用程序不使用自定义 WebMvcConfigurer#addResourceHandlers 解析静态内容

问题描述

我有一个带有 Spring MVC 的“典型”(接近初始化项目的启动项目)Spring Boot 2.4 应用程序,我想向静态文件添加缓存。为此,我提供了我自己的@Configuration实现WebMvcConfigurer. 但是无论我尝试什么,一旦我使用自己的配置,我总是会收到静态资源的 404 错误。

我的静态内容目录结构

src/main/resources/
|- static/
  |- res/
    |- css/
    |- js/
  |- images/
  |- favicon.ico

问题/问题 我认为我的误解在于如何ResourceHandlerRegistry#addResourceHandler一起ResourceHandlerRegistry#addResourceLocations工作。

我尝试以类似于默认资源解析(请参阅 参考资料org.springframework.boot.autoconfigure.web.WebProperties.Resources.CLASSPATH_RESOURCE_LOCATIONS)的方式执行此操作,并最终得到以下(不工作)代码:

@Configuration
public class CacheStaticResourcesConfiguration implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        registry
                .addResourceHandler("/favicon.ico", "/res/**", "/images/**")
                .addResourceLocations("classpath:/static")
                .setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS)
                        .noTransform()
                        .mustRevalidate());
    }
}

标签: spring-bootspring-mvc

解决方案


资源/类路径的解析确实令人困惑,我也花了一些时间来支持它。以下带有大量评论的示例有望阐明一切。

TL;博士:

 registry
     // Request URLs
     .addResourceHandler("/**" /*, ... */)
     // Path inside application (refers to src/main/resources directory)
     // TRAILING SLASH IS IMPORTANT
     .addResourceLocations("classpath:/static/")

Spring 将路径的可变部分从放入的模式附加addResourceHandler().addResourceLocations(). 例子:

// TRAILING SLASH IS IMPORTANT!
.addResourceLocations("classpath:/static/")
 =>
    addResourceHandler("/**")
    => GET /res/css/main.css
       => resolved as: "classpath:/static/res/css/main.css"
    
    BUT
    
    addResourceHandler("/res/**")
    => GET /res/css/main.css
          (spring only appends the ** to the value from
           addResourceLocations())
       => resolved as: "classpath:/static/css/main.css"

工作示例配置

import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.concurrent.TimeUnit;

@Configuration
public class CacheStaticResourcesConfiguration implements WebMvcConfigurer {

    /**
     * We provide a custom configuration which resolves URL-Requests to static files in the
     * classpath (src/main/resources directory).
     *
     * This overloads a default configuration retrieved at least partly from
     * {@link WebProperties.Resources#getStaticLocations()}.
     *
     * @param registry ResourceHandlerRegistry
     */
    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        /*
         * BE AWARE HERE:
         *
         * .addResourceHandler(): URL Paths
         * .addResourceLocations(): Paths in Classpath to look for file
         *   root "/" refers to src/main/resources
         *   For configuration example, see:
         *     org.springframework.boot.autoconfigure.web.WebProperties.Resources().getStaticLocations()
         *
         * .addResourceLocations("classpath:/static/")
         *   =>
         *      addResourceHandler("/**")
         *      => GET /res/css/main.css
         *         => resolved as: "classpath:/static/res/css/main.css"
         *      BUT
         *      addResourceHandler("/res/**")
         *      => GET /res/css/main.css
         *            (spring only appends the ** to the value from
         *             addResourceLocations())
         *         => resolved as: "classpath:/static/css/main.css"
         */

        registry
                .addResourceHandler("/favicon.ico")
                // trailing slash is important!
                .addResourceLocations("classpath:/static/")
                .setCacheControl(CacheControl.maxAge(1, TimeUnit.DAYS)
                        .noTransform()
                        .mustRevalidate());

        registry
                .addResourceHandler("/res/**")
                // trailing slash is important!
                .addResourceLocations("classpath:/static/res/")
                .setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS)
                        .noTransform()
                        .mustRevalidate());

        registry
                .addResourceHandler("/images/**")
                // trailing slash is important!
                .addResourceLocations("classpath:/static/images/")
                .setCacheControl(CacheControl.maxAge(7, TimeUnit.DAYS)
                        .noTransform()
                        .mustRevalidate());
    }
}

推荐阅读