Spring Boot with redirecting with single page angular2

angular, java, spring, spring-boot, spring-mvc

Solution

For every local REST request not starting with /api overwrite and redirect to default webapp/index.html. I plan to serve anything /api to the spring controllers.

Update 15/05/2017

Let me re-phrase your query for other readers. (Correct me, if misunderstood)

Background Using Spring Boot and Serving static resources from classpath

Requirement All `404` non api requests should be redirected to `index.html`.

NON API - means Requests in which URL doesn't start with `/api`. API - 404 should throw `404` as usual.

Sample Response `/api/something` - will throw `404` `/index.html` - will server index.html `/something` - will redirect to `index.html`

My Solution

Let the Spring MVC throw exceptions, if any handler is not available for the given resource.

Add following to `application.properties`

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

Add a `ControllerAdvice` as follows

@ControllerAdvice
public class RedirectOnResourceNotFoundException {

    @ExceptionHandler(value = NoHandlerFoundException.class)
    public Object handleStaticResourceNotFound(final NoHandlerFoundException ex, HttpServletRequest req, RedirectAttributes redirectAttributes) {
        if (req.getRequestURI().startsWith("/api"))
            return this.getApiResourceNotFoundBody(ex, req);
        else {
            redirectAttributes.addFlashAttribute("errorMessage", "My Custom error message");
            return "redirect:/index.html";
        }
    }

    private ResponseEntity<String> getApiResourceNotFoundBody(NoHandlerFoundException ex, HttpServletRequest req) {
        return new ResponseEntity<>("Not Found !!", HttpStatus.NOT_FOUND);
    }
}

You can customize the error message as you like.

Is there a way to prefix all controllers with api so that I do not have to write api every time.

For this, you can create a `BaseController` and set the RequestMapping path to `/api`

Example

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/api")
public abstract class BaseController {}

And extend this `BaseController` and make sure you do not annotate child class with `@RequestMapping`

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FirstTestController extends BaseController {
    @RequestMapping(path = "/something")
    public String sayHello() {
        return "Hello World !!";
    }

}

Previous Answer

You can create a `Filter` which redirects to `/index.html` if request path doesn't startsWith `/api`.

// CODE REMOVED. Check Edit History If you want.

Problem

I have a single page Angular app with Spring Boot. It looks like the following: ``` src main java controller HomeController CustomerController OtherController webapp js/angular-files.js index.html ``` Spring boot correctly defaults to webapp folder and serves index.html file. What I am looking to do is: For every local REST request not starting with `/api` overwrite and redirect to default webapp/index.html. I plan to serve anything `/api` to the spring controllers. Is there a way to prefix all controllers with API so that I do not have to write API every time? e.g. @RequestMapping("/api/home") can write shorthand in code @RequestMapping("/home") or ``` @RequestMapping("/api/other-controller/:id") can write shorthand @RequestMapping("/other-controller/:id") ``` I'm looking for every API request, e.g. 1) http://localhost:8080/api/home keep API with API and resolve to correct controller and return JSON, however if someone enters a URL like http:///localhost/some-url or http:///localhost/some-other/123/url then it will serve the index.html page and keep the URL. Alternative ways to do it: try adding #ErrorViewResolver: Springboot/Angular2 - How to handle HTML5 urls?

Original source

Related problems