I'm trying to reserve all paths starting with /static/** for a resource handler.
Unfortunately, I have some wildcards deriving out of the root path / in request mappings. Something like this:

What did I try?
ResourceHandlerRegistry#setOrder:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/resources/static/");
registry.setOrder(1);
}
Various versions of interceptor (with or without order):
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ResourcesInterceptor())
.excludePathPatterns("/static/**")
.order(2);
}
That is a half-hearted success (probably it won't even work if I change mapping to /{profile}/{project}/**), because:
/static/style/home.css # works
/static/style/home.cssxxx # 404, works
/static/style # catched by controller, expected: 404
/static # catched by controller, expected: 404
I've found some similar questions, mostly unanswered or with a little dirty solutions, like:
static path in every controller with wildcard by regex/static/** Summary:
I'm looking for a simple soulution, fully automated and preferably from the configuration. The question is: what's the proper way to achieve that?
This issue is caused beause of the way that Spring handles requests from users. There are several HandlerMappings and they are executed in a specified order. Most important for us are these two:
RequestMappingHandlerMapping registered in WebMvcConfigurationSupport with order=0 (we can see this in the source code and the documentation)
/**
* Return a {@link RequestMappingHandlerMapping} ordered at 0 for mapping
* requests to annotated controllers.
*/
AbstractHandlerMapping instantiated in ResourceHandleRegistry with default order Integer.MAX_VALUE-1
private int order = Ordered.LOWEST_PRECEDENCE - 1;
When you create a RequestMapping with path /{profile}/{project} and try to reach resource /static/somefile.css, the request you send is grabbed by the RequestMappingHandlerMapping and does not reach the HandlerMapping created by ResourceHandlerRegistry.
A simple solution for this issue is to set order to -1 in addResourceHandlers
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/resources/static/");
registry.setOrder(-1);
}
Then the proper HandlerMapping will serve static files, and if there is no such file, it will pass execution to your Controllers.
Kinda hacky, but you could use a regex in your profile mapping to exclude static:
For /{profile}:
@RequestMapping("/{profile:^(?:static.+|(?!static).*)$}")
For /{profile}/{project}:
@RequestMapping("/{profile:^(?:static.+|(?!static).*)$}/{project}")
EDIT:
Ah, I just saw that you already found regex as a possible solution and were wondering (among other solutions) if that was the proper way to do it.
Personally, my preferred solution would be to change the URI for the Controller. I find all other solutions to be somewhat similar and hacky: fronting static with a controller, using regex for profile URI...
I think I'd fallback on using the regex above if changing the URI isn't possible. I find it explicit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With