Configure react to be served on Spring boot app

Spring Boot can automatically handle static files (by convention), just put all of your html, js, css, etc. files to src/main/resources/static, remove your ViewResolver and Controller for '/' and it will work, index.html will also be mapped to / by Spring Boot as well.

Besides this, you can of course make REST endpoints with the api prefix by just using the correct @RequestMapping on your @RestControllers


You need a @Controller that returns a ModelAndView

    @Controller
    public class HomeController {

        @RequestMapping(value = {"/", "/index.html"})
        public ModelAndView sellerHome(HttpServletRequest request, 
                                       HttpServletResponse response) {
             return new ModelAndView("../static/index");
        }

    }

You can then access http://localhost:8443 and should see your index page given that you configured the port correctly.


It really depends on your setup. Lets suppose you want something like: enter image description here

Lets look at simple case: no thymeleaf templates or spring static files. Spring is uses for serving rest api and the rest is up to react. But you can use controllers at any request mapping url.

One option is to use ResourceResolver and configure it like this:

@Configuration
public class Config implements WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        ResourceResolver resolver = new ReactResourceResolver();
        registry.addResourceHandler("/**")
                .resourceChain(true)
                .addResolver(resolver);

        // Can try to play with
        // registry.addResourceHandler("/**")
        //        .addResourceLocations("classpath:/static/");
        // But this option can't map every path to index.html
        // Can try https://stackoverflow.com/a/42998817/1032167
        // to resolve this, but then you loose /api/** => rest
        // and to be honest it is some regex madness, so
        // it was easier for me to setup custom resource resolver


    }

    public class ReactResourceResolver implements ResourceResolver {
        // root dir of react files
        // example REACT_DIR/index.html
        private static final String REACT_DIR = "/static/";

        // this is directory inside REACT_DIR for react static files
        // example REACT_DIR/REACT_STATIC_DIR/js/
        // example REACT_DIR/REACT_STATIC_DIR/css/
        private static final String REACT_STATIC_DIR = "static";

        private Resource index = new ClassPathResource(REACT_DIR + "index.html");
        private List<String> rootStaticFiles = Arrays.asList("favicon.io",
                "asset-manifest.json", "manifest.json", "service-worker.js");

        @Override
        public Resource resolveResource(
            HttpServletRequest request, String requestPath,
            List<? extends Resource> locations, ResourceResolverChain chain) {

            return resolve(requestPath, locations);
        }

        @Override
        public String resolveUrlPath(
            String resourcePath, List<? extends Resource> locations,
            ResourceResolverChain chain) {

            Resource resolvedResource = resolve(resourcePath, locations);
            if (resolvedResource == null) {
                return null;
            }
            try {
                return resolvedResource.getURL().toString();
            } catch (IOException e) {
                return resolvedResource.getFilename();
            }
        }

        private Resource resolve(
            String requestPath, List<? extends Resource> locations) {

            if (requestPath == null) return null;

            if (rootStaticFiles.contains(requestPath)
                    || requestPath.startsWith(REACT_STATIC_DIR)) {
                return new ClassPathResource(REACT_DIR + requestPath);
            } else
                return index;
        }

    }
}

Here is full working demo for Spring 2.0.0.M4: https://github.com/varren/SpringBootReactExample


I had similar problem with a little bit different setup: Spring single page for every url route and subroute "/a/** => /a/index.html except /a/static/**".

And there is also an option to use regex Spring catch all route for index.html to kinda partially solve the problem, but i had no luck with this approach

Tags:

Java

Spring