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 HandlerMapping
s 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