how to work with react routers and spring boot controller
Asked Answered
B

5

20

here is my index.js file

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom'
import App from './components/App';

ReactDOM.render((
             <BrowserRouter>
                <App />
             </BrowserRouter>
             ), document.getElementById('root')
            );

and this is App.js

import React, { Component } from 'react';
import Main from './Main';

class App extends Component {
render() {
return (
      <div>
        <Main />
      </div>
  );
 }
}

export default App;

and this is my Main.js file

import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import Home from './Home';
import AdminHome from './AdminHome';

class Main extends Component {
render() {
return (
        <Switch>
          <Route exact path='/admin' component={AdminHome}/>
          <Route exact path='/' component={Home}/>
        </Switch>
  );
 }
}

export default Main;

router not routing to /admin but it is routing to / , when i run the app and hit url 'localhost:8080/admin' it says white label error.

i am fully confused how to work with react routers and controllers, can anyone suggest me a way.

i achieved routing just by returning index.html for every requests in my spring boot controller.

Bonacci answered 7/12, 2017 at 7:42 Comment(2)
integrating react in spring boot app i personally felt difficult.so i just separated the projects, and if i need any data from from backend to work with i just ask spring boot by rest(ajax,axios,fetch) using any of these functionsBonacci
I guess you should wrap your Switch with <Router></Router>Dunson
T
15

I use a filter to forward requests to index.html if it's not a static resource or not an api call.

Static resources are automatically served by spring boot if they are in /resources/static. I keep them in a specific folder /resources/static/rct for easy filtering. (I do not want headaches with regex)

index.html path to react app:

<script type="text/javascript" src="http://localhost:8080/rct/js/myreactapp.js"></script>

Now the filter RedirectToIndexFilter.java

@Component
public class RedirectToIndexFilter implements Filter {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;
        String requestURI = req.getRequestURI();

        if (requestURI.startsWith("/api")) {
            chain.doFilter(request, response);
            return;
        }

        if (requestURI.startsWith("/rct")) {
            chain.doFilter(request, response);
            return;
        }

        // all requests not api or static will be forwarded to index page. 
        request.getRequestDispatcher("/").forward(request, response);
    }

}

Controller to server index.html

@Controller
public class AppController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @GetMapping(value = {"/", ""})
    public String getIndex(HttpServletRequest request) {
        return "/rct/index.html";
    }

}

Controller to server api calls

@RestController
public class ProjectController {

    private final ProjectService projectService;

    public ProjectController(ProjectService projectService) {
        this.projectService = projectService;
    }

    @GetMapping("/api/v1/projects/{id}")
    public ProjectData getProject(@PathVariable Long id) {
        projectService.get(id);
        ...
    }

So any call that is not api or static is forwarded to index. By forwarding you keep the url as needed by react router but forward to index.html

Tribasic answered 12/10, 2018 at 9:23 Comment(0)
G
15

A simple approach that will send everything that isn't under api to your react app is to create an API controller that uses RegEx:

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ReactAppController {

    @RequestMapping(value = { "/", "/{x:[\\w\\-]+}", "/{x:^(?!api$).*$}/**/{y:[\\w\\-]+}" })
    public String getIndex(HttpServletRequest request) {
        return "/index.html";
    }

}

This controller simply redirects everything to index.html, allowing react and react-router to work its magic.

The RegEx works like this:

  • '/' - matches root
  • '/{x:[\\w\\-]+}' - matches everything up to the second \. Eg. \foo
  • '/{x:^(?!api$).*$}/**/{y:[\\w\\-]+}' - matches everything that doesn't start with api. Eg. \foo\bar?page=1
Grooms answered 4/5, 2020 at 9:52 Comment(2)
Hey, I tried your solution, and it works perfectly fine locally but I still have the same problem on Heroku.Anaximenes
Does no longer work in spring boot 3.2.2 - the api-regex is no longer accepted (No more pattern data allowed after {*...} or ** pattern element).Redpencil
W
8
  • Here is an updated version of the controller previously posted:
@Controller
public class ReactAppController {

    @RequestMapping(value = { "/", "/{x:[\\w\\-]+}", "/{x:^(?!api$).*$}/*/{y:[\\w\\-]+}","/error"  })
    public String getIndex(HttpServletRequest request) {
        return "/index.html";
    }

}

Whitehouse answered 10/4, 2022 at 16:42 Comment(1)
This version of the answer seems to work with the latest Springboot (2.7.8) and resolve the issue of being "unable to add anything after a * (wildcard)"Haphtarah
A
2

If you are already using routes, why not move to HashRouter instead of BrowserRouter.

Allix answered 23/6, 2022 at 13:4 Comment(0)
V
0

Under my controller folder:

import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class UiController {
    /*
      /xyz and /abc are the urls which is used in react routing
     */
    @RequestMapping(value = { "/", "/xyz","/abc","/error"  })
    public String getIndex(HttpServletRequest inRequest) {
        return "/index.html";
    }
}

//Dont forget to add ComponentScan in your Application class

Vachill answered 18/4, 2023 at 8:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.