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...