Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hosting a single page application with spring boot

So I am trying to host a Single Page Application alongside a normal REST API with spring.

What this means is that all requests that goes to the normal /api/ endpoints should be handled by the respective controller and all other requests should be directed to the resources in the folder /static/built

I have gotten this to work by catching all NoHandlerFoundExceptions and redirecting to either the js file or the html file. And then used a WebMvcConfigurer to map the static content.

But this all seems like a hack to me, so is there a less hacky way of doing it?

like image 501
munHunger Avatar asked Jan 25 '19 07:01

munHunger


2 Answers

Managed to have React+ReactRouter app working by adding following mapping:

@Controller
public class RedirectController {

  @GetMapping(value = {"/{regex:\\w+}", "/**/{regex:\\w+}"})
  public String forward404() {
    return "forward:/";
  }

}

This was inspired by https://stackoverflow.com/a/42998817/991894

like image 76
Alex Avatar answered Sep 26 '22 16:09

Alex


The easiest way I get my SPAs to work with a Spring backend API is to have 2 different controllers: one for the root index page of the SPA and the other controller is used to manage various RESTful API endpoints:

Here are my two controllers:

MainController.java

@Controller
public class MainController {

    @RequestMapping(value = "/")
    public String index() {
        return "index";
    }
}

MonitoringController.java

@RestController
@RequestMapping(value = "api")
public class MonitoringEndpoints {

    @GetMapping(path = "/health", produces = "application/hal+json")
    public ResponseEntity<?> checkHealth() throws Exception {
        HealthBean healthBean = new HealthBean();
        healthBean.setStatus("UP");

        return ResponseEntity.ok(healthBean);
    }
}

Notice how the API endpoint controller utilizes the '@RestConroller' annotation while the main controller utilizes the '@Conroller' annotation. This is because of how Thymeleaf utilizes it's ViewResolver. See:

Spring Boot MVC, not returning my view

Now go ahead and place your index.html page at src/main/resources/templates/index.html because Spring by default looks for your html pages within this location.

My index.html pages looks like this:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <head lang="en">
        <meta charset="UTF-8"/>
        <title>EDP Monitoring Tool</title>
    </head>
    <body>
        <!-- Entry point to our ReactJS single page web application -->
        <div id="root"></div>

        <script type="text/javascript" src="built/bundle.js"></script>
    </body>
</html>

Not sure how you're wiring up your frontend, whether that is a ReactJS app or something but I believe this information would be helpful for you. Let me know if I can answer additional questions for you.

In addition, if you're using Webpack, you can set up the entry point of your JS files via the webpack.config.js file under the entry key so like so:

entry: ['./src/main/js/index.js']
like image 42
Brandon Avatar answered Sep 26 '22 16:09

Brandon