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.
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.
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.
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 @RestController
s
It really depends on your setup. Lets suppose you want something like:
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With