Search code examples
javaangularspring-bootspring-mvc

Angular + Spring Boot: Forwarding all Angular routes to Angular and all API to the Spring Controllers


I have a Spring Boot app and an Angular app. I want to serve the Angular App from the Spring Boot App. I build the Angular App and moved all files, including the index.html file, into /resources/static/ and just to be sure also to resources/public/. I also put the index.html into resources/templates. I received 404 when calling any of the angular routes e.g. mywebsite.com/login

Then I added a controller to forward all requests to my Angular App:

@Controller
public class RedirectToAngularController {

  /**
  * Should redirect all routes to FrontEnd, but doesn't work.
  */
  @RequestMapping({"/", "/login", "/login/**"})
  public String redirectLogin() {
    log.info("Forwarding request to Angular (index.html)");
    return "forward:/index.html";
  }
}

IntelliJ gives me a warning for "forward:/index.html" that it can't find the URL:

warning

I still deployed my website and open it at myWebsite.com/login or myWebsite.com/confirm. Instead of my index.html file getting displayed I see forward:/index.html as a string in my browser. So it actually returns the string, not the file In the logs "Forwarding request to Angular (index.html)" appears, but then it says: Cannot find GET /index.html in the next line.

So I deleted that controller and instead tried to solve this with a ResourceHandler:

@Configuration
public class WebAdapterConfig implements WebMvcConfigurer {

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/**/*")
              .addResourceLocations("classpath:/static/")
              .resourceChain(true)
              .addResolver(new PathResourceResolver() {
                @Override
                protected Resource getResource(String resourcePath, Resource location) throws IOException {
                  Resource requestedResource = location.createRelative(resourcePath);

                  return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
                          : new ClassPathResource("/static/index.html");
                }
              });
    registry.setOrder(-1);
  }
}

This was described here: Springboot/Angular2 - How to handle HTML5 urls? and also here: https://keepgrowing.in/java/springboot/make-spring-boot-surrender-routing-control-to-angular/

But this redirects everything! I now get the index file when I open mywebsite.com/login as well as when I make a postman request to my api (e.g. GET mywebsite.com/api/users)

So I tried to narrow it down by replacing registry.addResourceHandler("/**/*") with registry.addResourceHandler("/login") or registry.addResourceHandler("/login/**", "/confirm"). But then only mywebsite.com/login/something and mywebsite.com/confirm retrun the index.html, but all other paths, including the URI for the api methods return 404!

A third approach was to add view controller:

@Configuration
public class WebAdapterConfig implements WebMvcConfigurer {

  @Override
  public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/login").setViewName("forward:/index.html");
    registry.addViewController("/login/**").setViewName("forward:/index.html");
    registry.addViewController("/confirm").setViewName("forward:/index.html");
  }
}

But then I always received 404 for all routes.

I also added spring web MVC to my dependencies, but this didn't seem to change anything.

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
}

p.s. I don't use tymeleaf as my files are coming from angular. Maybe that's why forward:/ doesn't work?


Solution

    1. Make sure no default path "/" is configured in your SpringBoot code/controller's
    2. Ensure you are not using @EnableWebMvc annotation anywhere in your app
    3. put all your UI files in the "../resources/public" folder (mainly your index.html shall be on this path)

    This should resolve your issue's in general :)

    SpringBoot automatically detects this and works well for all sorts of Single-page applications.