Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configure react to be served on Spring boot app

Tags:

java

spring

So far, I've been writing a bunch of endpoints for my Spring boot app, with no html UI side. Now, I want to serve the HTML file and js files which contain react code.

When I visit http://localhost:8443 I get:

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sun Nov 19 11:54:01 PST 2017
There was an unexpected error (type=Not Found, status=404).
Not Found

What I did so far:

1.Added a web config class that extends WebMvcConfigurerAdapter:

@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    @Bean
    public ViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver bean = new InternalResourceViewResolver();
        bean.setPrefix("/resources/static/");
        bean.setSuffix(".html");
        return bean;
    }
}

2.Added a rest controller endpoint:

@RestController
public class HomeController {

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ModelAndView getdata() {
        ModelAndView model = new ModelAndView("index");
        return model;
    }
}

I have myproject/src/main/resources/static/index.html file in my project.

like image 886
Arian Avatar asked Nov 19 '17 19:11

Arian


People also ask

How do you deploy React app using serve?

Configure the deploy settings. Select a default branch to deploy (you can choose the master branch or any other branch) and ensure that the build command is npm run build and the publish directory is /build . Click Deploy site, and your React app will be deployed on Netlify's remote server.

How do I run a Spring boot and React on the same port?

So, here is a quick guide how to run a react frontend and a spring boot backend on the same port and how to package them as a single jar file. First, create a spring boot project with https://start.spring.io. Add the Web dependency. Set the groupid and artifactid to whatever you want.


3 Answers

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

like image 96
helospark Avatar answered Oct 09 '22 03:10

helospark


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

like image 33
varren Avatar answered Oct 09 '22 05:10

varren


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.

like image 36
Kaushal Shah Avatar answered Oct 09 '22 03:10

Kaushal Shah