Damian
Damian

Reputation: 121

Spring Boot SPA URL Rewrite

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:

  1. Serve static assets (js,images,css,html,etc) from URL path: /assets/
  2. Store these static assets in a filesystem directory and map to the above path
  3. For any static asset request not found return a 404
  4. Expose REST APIs from a set of named URL paths: /api/ and /anotherapi/ etc...
  5. 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...

Upvotes: 2

Views: 2588

Answers (1)

Damian
Damian

Reputation: 121

Answered here: Spring RequestMapping Regex to exclude string

Based on answer here: Spring @RequestMapping "Not Contains" Regex

Pattern that worked for excluding /assets/: value = {"/{path:(?!.*assets).+}/**"}

Upvotes: 1

Related Questions