Search code examples
springspring-mvcspring-bootsingle-page-application

SPA with Spring Boot - serve index.html for non-API requests


I'm currently working on a webpage that should use a single page React front-end. For the back-end, I'm using the spring boot framework.

All api calls shall use a url prefixed with /api and should be handled by the REST controllers.

All other urls should simply serve the index.html file. How would I achieve this with spring?


Solution

  • The easiest way to achieve what you want is to implement custom 404 handler.

    Add these params to your application.properties:

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

    First property removes all default static resource handling, second property disables Spring's default whitelabel page (by default Spring catches NoHandlerFoundException and serves standard whitelabel page)

    Add 404 handler to your application context:

    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.servlet.NoHandlerFoundException;
    import javax.servlet.http.HttpServletRequest;
    
    @ControllerAdvice
    public class PageNotFoundController {
        @ExceptionHandler(NoHandlerFoundException.class)
        public String handleError404() {
                return "redirect:/index.html";
        }
    }
    

    At the end you will need to add your custom view resolver for serving your static content (index.html in this case)

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.ViewResolver;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    import org.springframework.web.servlet.view.InternalResourceView;
    import org.springframework.web.servlet.view.UrlBasedViewResolver;
    
    @Configuration
    @EnableWebMvc
    public class WebConfig extends WebMvcConfigurerAdapter {
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/index.html").addResourceLocations("classpath:/static/index.html");
            super.addResourceHandlers(registry);
        }
    
        @Bean
        public ViewResolver viewResolver() {
            UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
            viewResolver.setViewClass(InternalResourceView.class);
            return viewResolver;
        }
    
    }
    

    Your index.html should be placed in /resources/static/ directory.