我正在尝试为资源处理程序保留从/static/**
开始的所有路径。
不幸的是,我在请求映射中从根路径/
派生了一些通配符。像这样:
我尝试了什么?
ResourceHandlerRegistry#setOrder
:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/resources/static/");
registry.setOrder(1);
}
各种版本的拦截器(有无命令):
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ResourcesInterceptor())
.excludePathPatterns("/static/**")
.order(2);
}
那是一次三心二意的成功(如果我将映射更改为/{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
我发现了一些类似的问题,大多数没有答案或有一些肮脏的解决方案,例如:
static
path in every controller with wildcard by regex /static/**
的专用控制器摘要:
我正在寻找一种简单的解决方案,完全自动化,最好是从配置中选择。问题是:实现该目标的正确方法是什么?
答案 0 :(得分:3)
Kinda hacky,但是您可以在profile
映射中使用正则表达式来排除静态:
对于 /{profile}
:
@RequestMapping("/{profile:^(?:static.+|(?!static).*)$}")
对于 /{profile}/{project}
:
@RequestMapping("/{profile:^(?:static.+|(?!static).*)$}/{project}")
编辑:
啊,我只是看到您已经找到 regex 作为可能的解决方案,并且想知道(在其他解决方案中)这是否是正确的方法。
个人而言,我的首选解决方案是更改Controller的URI。我发现所有其他解决方案都有些相似和棘手:使用控制器在静态变量前面使用正则表达式作为配置文件URI ...
如果无法更改URI,我认为我会回退使用上述正则表达式。我发现它很明显。
答案 1 :(得分:2)
此问题是由于Spring处理用户请求的方式引起的。有多个HandlerMapping
,它们以指定的顺序执行。对我们来说最重要的是以下两个:
RequestMappingHandlerMapping
已在WebMvcConfigurationSupport
= 0的order
中注册(我们可以在源代码和文档中看到此信息)
/**
* Return a {@link RequestMappingHandlerMapping} ordered at 0 for mapping
* requests to annotated controllers.
*/
AbstractHandlerMapping
以ResourceHandleRegistry
实例化,默认顺序为Integer.MAX_VALUE-1
private int order = Ordered.LOWEST_PRECEDENCE - 1;
当您创建路径为/{profile}/{project}
的RequestMapping并尝试访问资源/static/somefile.css
时,您发送的请求将被RequestMappingHandlerMapping抓取,而不会达到ResourceHandlerRegistry创建的HandlerMapping。
此问题的一种简单解决方案是在-1
中将订单设置为addResourceHandlers
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/resources/static/");
registry.setOrder(-1);
}
然后适当的HandlerMapping将提供静态文件,如果没有此类文件,它将执行传递给控制器。
答案 2 :(得分:1)
我已经找到了基于自定义处理程序映射和伪控制器的有趣解决方案。
如果我们创建AbstractHandlerMapping
bean,如果Spring与其他Controller
不匹配,它将被调用:
@Bean
public AbstractHandlerMapping profileHandlerMapping(RequestMappingHandlerAdapter handlerAdapter) {
HandlerMethodArgumentResolverComposite argumentResolvers = new HandlerMethodArgumentResolverComposite();
argumentResolvers.addResolvers(handlerAdapter.getArgumentResolvers());
ProfileController profileHandlerMapping = new ProfileController(argumentResolvers);
profileHandlerMapping.setOrder(2);
return profileHandlerMapping;
}
伪控制器:
public class ProfileController extends AbstractHandlerMapping {
private final HandlerMethodArgumentResolverComposite argumentResolvers;
public ProfileController(HandlerMethodArgumentResolverComposite argumentResolvers) {
this.argumentResolvers = argumentResolvers;
}
@Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
InvocableHandlerMethod handlerMethod = new InvocableHandlerMethod(this, getClass().getMethod("profile", HttpServletRequest.class));
handlerMethod.setHandlerMethodArgumentResolvers(argumentResolvers);
return handlerMethod;
}
@ResponseBody
public String profile(HttpServletRequest request) {
return "Profile: " + request.getRequestURI();
}
}
优点:
缺点:
@PathVariable