ResourceHandler与控制器中的通配符冲突

dzi*_*ysk 5 java spring spring-mvc spring-boot

我正在尝试保留所有/static/**以资源处理程序开头的路径.不幸的是,我有一些通配符来自/请求映射中的根路径.像这样的东西:

预习

我尝试了什么?

  • ResourceHandlerRegistry#setOrder:

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/resources/static/");
    
        registry.setOrder(1);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 各种版本的拦截器(有或没有顺序):

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new ResourcesInterceptor())
                .excludePathPatterns("/static/**")
                .order(2);
    }
    
    Run Code Online (Sandbox Code Playgroud)

这是一个半心半意的成功(如果我改变映射,它可能甚至不起作用/{profile}/{project}/**),因为:

/static/style/home.css      # works
/static/style/home.cssxxx   # 404, works
/static/style               # catched by controller, expected: 404
/static                     # catched by controller, expected: 404
Run Code Online (Sandbox Code Playgroud)

我发现了一些类似的问题,大多数都没有答案,或者有一些肮脏的解决方案,例如:

摘要:

  • 我不想使用正则表达式,因为它将来会很痛苦
  • 我也无法改变映射.我知道,这是最简单的方法,但我无法做到这一点.
  • 更改订单无效
  • 创建专用控制器仍然存在路径问题

我正在寻找一种简单的洗脱液,完全自动化,最好是配置.问题是:实现这一目标的正确方法什么?

小智 3

这个问题是由 Spring 处理用户请求的方式引起的。有多个HandlerMappings,它们按照指定的顺序执行。对我们来说最重要的是这两点:

  1. RequestMappingHandlerMappingWebMvcConfigurationSupport使用=0注册order(我们可以在源代码和文档中看到这一点)

    /**
     * Return a {@link RequestMappingHandlerMapping} ordered at 0 for mapping
     * requests to annotated controllers.
     */
    
    Run Code Online (Sandbox Code Playgroud)
  2. AbstractHandlerMappingResourceHandleRegistry以默认顺序实例化Integer.MAX_VALUE-1

    private int order = Ordered.LOWEST_PRECEDENCE - 1;
    
    Run Code Online (Sandbox Code Playgroud)

当您创建带有路径的RequestMapping/{profile}/{project}并尝试访问resource/static/somefile.css时,您发送的请求将被RequestMappingHandlerMapping抓取,并且不会到达ResourceHandlerRegistry创建的HandlerMapping。

解决此问题的一个简单方法是将order 设置为-1inaddResourceHandlers

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/static/**")
        .addResourceLocations("classpath:/resources/static/");

    registry.setOrder(-1);
}
Run Code Online (Sandbox Code Playgroud)

然后正确的 HandlerMapping 将提供静态文件,如果没有这样的文件,它将把执行传递给您的控制器。