Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to work with react routers and spring boot controller

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.

like image 482
Srikanth Gowda Avatar asked Dec 07 '17 07:12

Srikanth Gowda


3 Answers

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
like image 177
Chaholl Avatar answered Oct 20 '22 05:10

Chaholl


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

like image 10
Florin Grozea Avatar answered Oct 20 '22 06:10

Florin Grozea


  • 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";
    }

}

like image 3
Tristan Elliott Avatar answered Oct 20 '22 06:10

Tristan Elliott