I'm trying to build an SPA backend (static content server, api) with some additional features/controls that require a flexible URL rewrite/routing/handling. These requirements are proving difficult to achieve together, despite trying the approach in some similar answers I've read through on here.
What I need to do:
- Serve static assets (js,images,css,html,etc) from URL path: /assets/
- Store these static assets in a filesystem directory and map to the above path
- For any static asset request not found return a 404
- Expose REST APIs from a set of named URL paths: /api/ and /anotherapi/ etc...
- For all other requests outside of these URL paths, serve /index.htm to bootstrap the SPA
So far, I have the following...
For the REST APIs:
@RestController
@RequestMapping(value="/api/**")
public class StateAPIController {
@RequestMapping(value = {"/api/method1"}, method = RequestMethod.POST)
@ResponseBody
public String method1() {
return "method1...";
}
@RequestMapping(value = {"/api/method2"}, method = RequestMethod.POST)
@ResponseBody
public String method2() {
return "method2...";
}
}
(This works fine)
For rendering static files from a specific filesystem location and mapping "/" to "/index.htm":
@Configuration
@EnableWebMvc
public class AssetServerConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/")
.addResourceLocations("file:/some/path/index.htm");
registry
.addResourceHandler("/assets/**")
.addResourceLocations("file:/some/path/assets/");
}
@Bean
public ViewResolver viewResolver() {
UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
viewResolver.setViewClass(InternalResourceView.class);
return viewResolver;
}
}
(This works, but not sure if the best way to solve this)
To redirect/forward any other requests (outside of those reserved paths) to "/" (and therefore "/index.htm"):
@ControllerAdvice
@RequestMapping(value="/**")
public class AssetServerController {
@RequestMapping(value = {"/**/{path:[^\\.]*}", "/{path:^(?!/assets/).*}", "/{path:^(?!/api/).*}"}, method = RequestMethod.GET)
public String index() {
return "forward:/";
}
}
(This only partially works... and the main issue I need help with)
So, here, I need to exclude a list of paths (/assets/ & /api/), but this is proving difficult to get right with the regex/AntPathMatcher filter in the RequestMapping, and has both false matches (showing index.htm when it shouldn't) and misses (showing 404s when it should show index.htm).
Due to the above, I also cannot correctly serve 404s when a resource is missing under one of the reserved paths (e.g. assets).
a) what is the best way to approach this? Have I got this completely wrong? Is there a better way?
b) how do I make the regex work, as it doesn't seem to follow normal regex rules, and examples I've seen so far don't achieve my goal...