Skip to content

Example project showing how to build a Spring Boot App providing a GUI with ReactJS. Along with an overview article that illustrates the mechanisms of its building and deploying, please visit:

License

Notifications You must be signed in to change notification settings

ZhongyangMA/react-with-springboot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

react-with-springboot

Sample codes for integrating ReactJS application with Spring Boot, along with an overview article that illustrates the mechanisms of its building and deploying.

Please visit and leave your valuable comments: Integrating ReactJS with Spring Boot

Serving Static Web Contents with Spring Boot

Serving static web contents (such as image, css & js) is necessary when developing a web application. Spring Boot provides excellent supports for it. Its basic configurations can satisfy most of needs in developing, and the developers can also make some custom configurations based on it.

The Default Static Resource Mapping

By default, Spring Boot maps all visits of "/**", to these directories:

classpath:/static
classpath:/public
classpath:/resources
classpath:/META-INF/resources

Let's perform a little experiment. Create three directories static, public and resources under main/resources, then put a.png, b.png and c.png into static, public and resources respectively. Run the project, and visit:

http://localhost:8080/a.png
http://localhost:8080/b.png
http://localhost:8080/c.png

All images can be visited, which means Spring Boot looks for static resources in these directories by default.

By tracing the code we found that the default mapping was defined in WebMvcAutoConfiguration:

public void addResourceHandlers(ResourceHandlerRegistry registry) {
    if (!this.resourceProperties.isAddMappings()) {
        logger.debug("Default resource handling disabled");
    } else {
        Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
        CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
        if (!registry.hasMappingForPattern("/webjars/**")) {
            this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
        }
        // here is the default mapping defination
        String staticPathPattern = this.mvcProperties.getStaticPathPattern();
        if (!registry.hasMappingForPattern(staticPathPattern)) {
            this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
        }

    }
}

The staticPathPattern was defined in WebMvcProperties, its default value is "/**"; And the staticLocations was defined in ResourceProperties, its default value are: "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", which assigned by variable CLASSPATH_RESOURCE_LOCATIONS.

Customize the Mappings

We can also customize the mapping by implementing WebMvcConfigurer.

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // map "/static/**" to "classpath:/mystatic/"
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/mystatic/");
    }
}

Create new directory mystatic under main/resources, and put d.png in it. Run the project and visit:

http://localhost:8080/static/d.png

The image d.png can be visited in this url.

We can also config the mappings in application.properties:

# config the static resource path prefix, override default
spring.mvc.static-path-pattern=/mystatic/**
# config the static resource directories, override default
spring.resources.static-locations[0]=classpath:/mystatic
spring.resources.static-locations[1]=classpath:/public

Restart the project, the path below can be visited:

http://localhost:8080/mystatic/a.png

And this path can't be visited:

http://localhost:8080/a.png  // default prefix has been overridden

Resources under mystatic and public can be visited; But when visiting resources and static, a "404 not found" message will be returned, because this configuration overrides the default mappings.

Officially Supported Way to Create React App

First of all, we need to setup the developing environment for our laptop. What we need to install is the npm (Node Package Manager). Run the command below:

brew install node    # for macOS

After installation, run:

node -v
npm -v

If we get the versions of node and npm, the installation was successful.

Second, we need to install create-react-app globally via npm:

npm install -g create-react-app

The create-react-app is an officially supported way to create single-page React applications. It offers a modern build setup with no configuration.

Now, let's start building a react project called "react-tutorial-codes":

create-react-app react-tutorial-codes

After a few minutes, a new directory "react-tutorial-codes" was generated, the structure in it is:

node_modules        # folder, tools and dependencies
public              # folder, index.html and root elements
src                 # folder, javascript files
.gitignore
package.json        # information about project and outer dependencies
package-lock.json
README.md

Enter this directory and run this demo project:

cd react-tutorial-codes
npm start

Open your web browser, and goto: localhost:3000/, an official react demo page will be presented.

Integrating React with Spring Boot

Please note that the development build above is not optimized, to create a production build, run:

npm run build

Before we run this command, we need to change the homepage location to the current directory. Open package.json, and add "homepage": "." field to the end of it:

{
  "name": "react-tutorial-codes",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.5.0",
    "@testing-library/user-event": "^7.2.1",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-scripts": "3.4.3"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "homepage": "."
}

Then by running npm run build, a new folder "build" is generated in this project. Within it, the "index.html" is the entry of this react project.

To deploy this react project to a Spring Boot server, copy all things from "build" to Spring Boot's "main/resources/public" folder. Then start Spring Boot project, and visit localhost:8080/, the same official react demo page will appear.

The Sample Codes

react-tutorial-codes: https://github.com/ZhongyangMA/react-tutorial-codes This sample code requests backend API via "axios". Run npm run build, then copy all contents from "build" folder to "main/resources/public" folder in the Spring Boot project below.

react-deployment-samples: https://github.com/ZhongyangMA/react-with-springboot This is a Spring Boot project which provides several backend APIs for the React frontend. Start the project and visit localhost:8080/ to get frontend contents to your browser, then click the "Call Backend API" button in this demo page to request backend API localhost:8080/api/users.

Deploy Separately & CORS Problem

The React project can be deployed separately from backend servers. It can be hosted on a nginx server for instance.

Run commands below to install and setup nginx server:

brew install nginx      # for macOS
cd /usr/local/etc/nginx
vi nginx.conf           # set ip and port, for instance localhost:8088

Then copy all contents from React "build" folder to nginx's "/usr/local/var/www" folder, and start nginx server:

nginx

Visit localhost:8088 in your web browser, the same official react demo page will appear again.

But if you click the button "Call Backend API" now, you will get error message "Access to XMLHttpRequest at 'http://localhost:8080/api/users' from origin 'http://localhost:8088' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource".

CORS, Cross-Origin Resource Sharing, is a common problem when you are deploying your frontend app that the backend api is hosted on a different origin (different protocol, ip or port). It is a browser mechanism which enables controlled access to resources located outside of a given domain.

To add "Access-Control-Allow-Origin" header on the requested resource, we can simply put @CrossOrigin annotation before the Restful API in Spring Boot.

@RestController
@RequestMapping(value = "/api")
public class ApiController {
    // origins, whitelist of allowed origins, "*" means allow all
    // maxAge, age of cookie in second
    @CrossOrigin(origins = "*", maxAge = 3600)
    @RequestMapping(method = RequestMethod.GET, value = "/users")
    public List<User> getUsers() {
        // code omitted
        return list;
    }
}

The @CrossOrigin annotation can be added before methods and classes, you can specify a list of allowed origins, or use "*" symbol to allow all the cross-origin requests.

References

[1] Spring Boot 静态资源访问和配置全解析: https://blog.csdn.net/u010358168/article/details/81205116

[2] React Getting Started: https://www.w3schools.com/react/react_getstarted.asp

[3] Tutorial - Intro to React: https://reactjs.org/tutorial/tutorial.html

[4] Create React App Docs: https://create-react-app.dev/docs/getting-started

[5] Cross-origin resource sharing: https://portswigger.net/web-security/cors

[6] CORS with Spring: https://www.baeldung.com/spring-cors

About

Example project showing how to build a Spring Boot App providing a GUI with ReactJS. Along with an overview article that illustrates the mechanisms of its building and deploying, please visit:

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published