Tutorial: SpringBoot + React + PostgreSQL: Build CRUD Application with SpringBoot React.js Example
In the tutorial, I introduce how to build an “SpringBoot React.js CRUD PostgreSQL Example” project with the help of SpringData JPA for POST/GET/PUT/DELETE requests with step by step coding examples:
– SpringBoot project produces CRUD RestAPIs with PostgreSQL database using the supporting of Spring Data JPA.
– React.js project will consume the SpringBoot CRUD RestAPIs by Ajax then show up on Reactjs component’s views.
– I draw a fullstack overview Diagram Architecture from React.js Frontend to PostgreSQL database through SpringBoot RestAPI backend.
– Develop SpringBoot CRUD RestAPIs with the supporting of SpringWeb Framework.
– Implement Reactjs CRUD application with Ajax fetching APIs to do CRUD request (Post/Get/Put/Delete) to SpringBoot Backend APIs.
– I create a testsuite with a number of integrative testcases with CRUD RestAPI requests from Reactjs to do CRUD requests to SpringBoot RestAPIs Server and save/retrieve data to PostgreSQL database.
- Overview Diagram Architecture – SpringBoot React PostgreSQL (SpringBoot Reactjs CRUD Example)
- How to Integrate Reactjs with SpringBoot?
- SpringBoot PostgreSQL CRUD RestAPIs Example – Backend Development
- Reactjs CRUD Application Example – Frontend Development
- Reactjs CRUD Application Overview with SpringBoot RestAPIs
- How to build Reactjs Application?
- Setup Reactjs Application with Bootstrap
- Build Application Navigation Bar Component
- Create Reactjs Home Page Component
- Build Reactjs CustomerList Component
- Build Reactjs CustomerEdit Component
- Edit Reactjs App.js Component
- Add a Proxy Setting for calling RestAPIs
- Integrative Testing: Reactjs Application with SpringBoot CRUD RestAPIs + PostgreSQL
- Testcase 1: Reactjs Post request – Post data to PostgreSQL through SpringBoot RestAPI
- Testcase 2: Reactjs Put request – Put data to PostgreSQL through SpringBoot RestAPI
- Testcase 3: Reactjs Fetch request – Get All data from PostgreSQL through SpringBoot RestAPI
- Testcase 4: Reactjs Delete request – Delete an entity from PostgreSQL through SpringBoot RestAPI
- Further Reading
- Sourcecode
Overview Diagram Architecture – SpringBoot React PostgreSQL (SpringBoot Reactjs CRUD Example)
Overall Architecture System: Reactjs + SpringBoot + PostgreSQL

- We build a backend: SpringBoot CRUD Application with PostgreSQL that provides RestAPIs for POST/GET/PUT/DELETE data entities and store them in PostgreSQL database.
- We implement React.js CRUD Application that use Ajax to interact (call/receive requests) with SpringBoot CRUD application and display corresponding data in Reactjs Component.
SpringBoot PostgreSQL CRUD Design Application

I build a SpringBoot project that handle all Post/Get/Put/Delete requests from RestClient and do CRUD operations to PostgreSQL database to save/retrieve/update and delete entity from PostgreSQL and returns back to Restclient the corresponding messages.
We build a SpringBoot project with 2 layers:
– SpringJPA Repository is used to interact with PostgreSQL database by a set of CRUD operations.
– RestController layer is a web layer for SpringBoot project, it will directly handle all incomming requests and do the corressponding responses to the calling client.
Reactjs CRUD Application Design

– Reactjs CRUD Application is designed with 2 main layers:
- React.js components let you split the UI into independent, reusable pieces, and think about each piece in isolation.
- Ajax is used by Reactjs component to fetch (post/put/get/delete) data from remote restapi by http request
Reactjs CRUD Application defines 5 components:
Home.js
is used serve as the landing page for your app.AppNavbar.js
is used to establish a common UI feature between components.CustomerList.js
is used to show all customers in the web-pageCustomerEdit.js
is used to modify the existed customerApp.js
uses React Router to navigate between components.
Integrative Project Goal
Reactjs Home page:

Reactjs add data:

Reactjs List all data:

Reactjs update data:

Reactjs delete data:
-> Delete a customer Adam with id=2, after successfully, check the customer list again:

Check PostgreSQL Database after do CRUD operations:

How to Integrate Reactjs with SpringBoot?
For starting to integrate Reactjs with SpringBoot project, I recommend you a previous post with detail steps to pratice:
How to Integrate Reactjs with SpringBoot Tutorial



SpringBoot PostgreSQL CRUD RestAPIs Example – Backend Development
Now it’s time for building the “SpringBoot PostgreSQL CRUD RestAPIs Example” project with a set of simple steps:
- Create SpringBoot project
- Configure PostgreSQL Database
- Define SpringData JPA Entity Model
- Define SpringBoot JPA Repository
- Implement SpringBoot Controller CRUD RestAPIs
Let’s go!
How to build SpringBoot PostgreSQL CRUD RestAPI project
Create SpringBoot PostgreSQL project
We use SpringToolSuite to create a simple SpringBoot project with below structure:

application.properties
is used to add the SpringBoot application’s configurations such as: database configuration (MongoDB, PostgreSQL, PostgreSQL), threadpool, Hibernate, JPA …repository
package is used to define a SpringBoot JPA repository to do CRUD operations with PostgreSQLcontroller
package is used to implement a SpringBoot RestAPI controller to handle all incomming requests (post/get/put/delete) and response to rest-client.model
package is used to define a JPA entity model that maps with the record’s format in PostgreSQL database
For handling the web-request and doing CRUD operations with PostgreSQL database, we need the supporting of 3 SpringBoot dependencies: spring-boot-starter-web
and spring-boot-starter-data-jpa
, postgresql
. So adding it to pom.xml
file:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
SpringBoot Configure PostgreSQL Database
To initialize a connection with PostgreSQL, we open the file application.properties
and add below configuration:
## PostgreSQL
spring.datasource.url=jdbc:postgresql://localhost:5432/loizenaidb
spring.datasource.username=postgres
spring.datasource.password=123
#drop & create table again, good for testing, comment this in production
spring.jpa.hibernate.ddl-auto=create
Define Spring JPA Entity Model
We create a Customer model class with 6 attributes:
- id
- firstname
- lastname
- address
- age
- copyright
– Coding:
package com.loizenai.springboot.reactjs.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@Data
@NoArgsConstructor
@RequiredArgsConstructor
@Entity
@Table(name = "customer")
public class Customer {
@Id
@GeneratedValue
private Long id;
@NonNull
private String firstname;
@NonNull
private String lastname;
private String address;
private int age;
private String copyright = "https://loizenai.com";
public String toString() {
return String.format("id=%d, firstname='%s', lastname'%s', address=%s, age=%d",
id, firstname, lastname, address, age);
}
public Customer(String firstname, String lastname, String address, int age) {
this.firstname = firstname;
this.lastname = lastname;
this.address = address;
this.age = age;
}
}
– javax.persistence.Id
specifies the primary key of an entity.
– javax.persistence.Entity
specifies that the class is an entity. This annotation is applied to the entity class.
Define SpringBoot JPA Repository
For doing CRUD operations with database, we define an interface CustomerRepository
that extends class JpaRepository:
package com.loizenai.springboot.reactjs.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.loizenai.springboot.reactjs.model.Customer;
public interface CustomerRepository extends JpaRepository<Customer, Long> {
Customer findByFirstname(String firstname);
}
Implement SpringBoot PostgreSQL CRUD RestAPIs
Related post: SpringBoot RestAPIs @GetMapping, @PostMapping, @DeleteMapping, @PutMapping, @PatchMapping
We use SpringWeb to implement 4 RestAPIs for Post/Get/Put/Delete requests as below list:
- SpringBoot Post request – we define a Post RestApi:
/api/customer
is used to save a single Customer data to PostgreSQL database. - SpringBoot Get request – we define a GET RestApi:
/api/customers
is used to retrieve all Customer data from PostgreSQL database. - SpringBoot Put request – we define a restapi
/api/customer
to update a Customer data from PostgreSQL via the request body’s data - SpringBoot Delete request – we define a Delete RestApi:
/api/customer/{id}
is used to delete a Customer document from PostgreSQL via a give id
package com.loizenai.springboot.reactjs.controller;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.loizenai.springboot.reactjs.model.Customer;
import com.loizenai.springboot.reactjs.repository.CustomerRepository;
@RestController
@RequestMapping("/api")
public class CustomerController {
private final Logger log = LoggerFactory.getLogger(CustomerController.class);
private CustomerRepository customerRepository;
public CustomerController(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
@GetMapping("/customers")
Collection<Customer> customers() {
return customerRepository.findAll();
}
@GetMapping("/customer/{id}")
ResponseEntity<?> getCustomer(@PathVariable Long id) {
Optional<Customer> customer = customerRepository.findById(id);
return customer.map(response -> ResponseEntity.ok().body(response))
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
@PostMapping("/customer")
ResponseEntity<Customer> createCustomer(@RequestBody Customer customer) throws URISyntaxException {
log.info("Request to create customer: {}", customer);
Customer result = customerRepository.save(customer);
return ResponseEntity.created(new URI("/api/group/" + result.getId()))
.body(result);
}
@PutMapping("/customer")
ResponseEntity<Customer> updateGroup(@RequestBody Customer customer) {
log.info("Request to update customer: {}", customer);
Customer result = customerRepository.save(customer);
return ResponseEntity.ok().body(result);
}
@DeleteMapping("/customer/{id}")
public ResponseEntity<?> deleteCustomer(@PathVariable Long id) {
log.info("Request to delete customer: {}", id);
customerRepository.deleteById(id);
return ResponseEntity.ok().build();
}
}
API Testing – SpringBoot PostgreSQL CRUD RestAPIs testsuite
PostgreSQL database:

– SpringBoot Get RestAPI – Get all customers from PostgreSQL:

– SpringBoot Post RestAPI – Post a Customer to PostgreSQL

– SpringBoot Put RestAPI – Update an existing Customer to PostgreSQL

– SpringBoot Delete RestAPI – Delete a Customer from PostgreSQL via id:

Reactjs CRUD Application Example – Frontend Development
Reactjs CRUD Application Overview with SpringBoot RestAPIs


For more details, we go back to the session: Reactjs CRUD Application Overview with SpringBoot RestAPIs
How to build Reactjs Application?
We build a Reactjs Application that fetchs data from PostgreSQL database through PostgreSQL RestAPI with 5 UI components. Step to do:
– Setup Reactjs Application
– Build Reactjs Navigation Bar component
– Build Reactjs Home page component
– Build Reactjs CustomerList Component
– Build Reactjs CustomerEdit Component
– Update Reactjs App.js Component with Router
Setup Reactjs Application with Bootstrap
Create React App is a command line utility that generates React projects for you. It’s a convenient tool because it also offers commands that will build and optimize your project for production.
The create-react-app
will set up everything you need to run a React application.
– Create a new project in the app directory with Yarn.
yarn create react-app app
Project Structure:

More details you can see at: Create Reactjs Project
After the app creation process completes, navigate into the app
directory and install Bootstrap, cookie support for React, React Router, and Reactstrap.
– Reactstrap: This library contains React Bootstrap 4 components that favor composition and control. The library does not depend on jQuery or Bootstrap javascript.
– React Router: Components are the heart of React’s powerful, declarative programming model. React Router is a collection of navigational components that compose declaratively with your application.
cd app
yarn add bootstrap@4.1.3 react-cookie@3.0.4 react-router-dom@4.3.1 reactstrap@6.5.0
Build Application Navigation Bar Component
import React, { Component } from 'react';
import { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap';
import { Link } from 'react-router-dom';
export default class AppNavbar extends Component {
constructor(props) {
super(props);
this.state = {isOpen: false};
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState({
isOpen: !this.state.isOpen
});
}
render() {
return <Navbar color="dark" dark expand="md">
<NavbarBrand tag={Link} to="/">Home</NavbarBrand>
<NavbarToggler onClick={this.toggle}/>
<Collapse isOpen={this.state.isOpen} navbar>
<Nav className="ml-auto" navbar>
<NavItem>
<NavLink
href="https://loizenai.com">loizenai.com</NavLink>
</NavItem>
<NavItem>
<NavLink href="https://github.com/loizenai">GitHub</NavLink>
</NavItem>
</Nav>
</Collapse>
</Navbar>;
}
}
Create Reactjs Home Page Component

import React, { Component } from 'react';
import './App.css';
import AppNavbar from './AppNavbar';
import { Link } from 'react-router-dom';
import { Button, Container } from 'reactstrap';
class Home extends Component {
render() {
return (
<div>
<AppNavbar/>
<Container fluid>
<Button color="link"><Link to="/customers">Manage Customer List</Link></Button>
</Container>
</div>
);
}
}
export default Home;
Build Reactjs CustomerList Component

– CustomerList Component will fetch a list of customers from SpringBoot RestAPI api/customers
and then shows all of them on a Bootstrap table.
– The CustomerList has 3 buttons:
- Add Customer & Edit are used to link to a url
/customers/new
that will map withCustomerEdit
component - Delete button is used to remove a Customer entity from PostgreSQL data based on a given
id
through an async functionremove(id)
that will do a fetch request with DELETE method to SpringBoot RestAPI.
Detail coding:
import React, { Component } from 'react';
import { Button, ButtonGroup, Container, Table } from 'reactstrap';
import AppNavbar from './AppNavbar';
import { Link } from 'react-router-dom';
class CustomerList extends Component {
constructor(props) {
super(props);
this.state = {customers: [], isLoading: true};
this.remove = this.remove.bind(this);
}
componentDidMount() {
this.setState({isLoading: true});
fetch('api/customers')
.then(response => response.json())
.then(data => this.setState({customers: data, isLoading: false}));
}
async remove(id) {
await fetch(`/api/customer/${id}`, {
method: 'DELETE',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then(() => {
let updatedCustomers = [...this.state.customers].filter(i => i.id !== id);
this.setState({customers: updatedCustomers});
});
}
render() {
const {customers, isLoading} = this.state;
if (isLoading) {
return <p>Loading...</p>;
}
const customerList = customers.map(customer => {
return <tr key={customer.id}>
<td style={{whiteSpace: 'nowrap'}}>{customer.firstname}</td>
<td>{customer.lastname}</td>
<td>{customer.age}</td>
<td>{customer.address}</td>
<td><a href={customer.copyright}>{customer.copyright}</a></td>
<td>
<ButtonGroup>
<Button size="sm" color="primary" tag={Link} to={"/customers/" + customer.id}>Edit</Button>
<Button size="sm" color="danger" onClick={() => this.remove(customer.id)}>Delete</Button>
</ButtonGroup>
</td>
</tr>
});
return (
<div>
<AppNavbar/>
<Container fluid>
<div className="float-right">
<Button color="success" tag={Link} to="/customers/new">Add Customer</Button>
</div>
<h3>Customer List</h3>
<Table className="mt-4">
<thead>
<tr>
<th width="20%">Firstname</th>
<th width="20%">Lastname</th>
<th width="10%">Age</th>
<th>Address</th>
<th>Copyrightby</th>
<th width="10%">Actions</th>
</tr>
</thead>
<tbody>
{customerList}
</tbody>
</Table>
</Container>
</div>
);
}
}
export default CustomerList;
Build Reactjs CustomerEdit Component

We create a React Form to Put/Post data to PostgreSQL database through SpringBoot RestAPI by using a fetch (PUT/POST) function:
async handleSubmit(event) {
event.preventDefault();
const {item} = this.state;
await fetch('/api/customer', {
method: (item.id) ? 'PUT' : 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(item),
});
this.props.history.push('/customers');
}
After form submition, React Application will come back to a CustomerList component by using a coding-line:
this.props.history.push('/customers');
– Full coding:
import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
import { Button, Container, Form, FormGroup, Input, Label } from 'reactstrap';
import AppNavbar from './AppNavbar';
class CustomerEdit extends Component {
emptyCustomer = {
firstname: '',
lastname: '',
age: '',
address: '',
copyrigtby: ''
};
constructor(props) {
super(props);
this.state = {
item: this.emptyCustomer
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
async componentDidMount() {
if (this.props.match.params.id !== 'new') {
const customer = await (await fetch(`/api/customer/${this.props.match.params.id}`)).json();
this.setState({item: customer});
}
}
handleChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
let item = {...this.state.item};
item[name] = value;
this.setState({item});
}
async handleSubmit(event) {
event.preventDefault();
const {item} = this.state;
await fetch('/api/customer', {
method: (item.id) ? 'PUT' : 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(item),
});
this.props.history.push('/customers');
}
render() {
const {item} = this.state;
const title = <h2>{item.id ? 'Edit Customer' : 'Add Customer'}</h2>;
return <div>
<AppNavbar/>
<Container>
{title}
<Form onSubmit={this.handleSubmit}>
<FormGroup>
<Label for="firstname">Firstname</Label>
<Input type="text" name="firstname" id="firstname" value={item.firstname || ''}
onChange={this.handleChange} autoComplete="firstname"/>
</FormGroup>
<FormGroup>
<Label for="lastname">Lastname</Label>
<Input type="text" name="lastname" id="lastname" value={item.lastname || ''}
onChange={this.handleChange} autoComplete="lastname"/>
</FormGroup>
<FormGroup>
<Label for="age">Age</Label>
<Input type="text" name="age" id="age" value={item.age || ''}
onChange={this.handleChange} autoComplete="age"/>
</FormGroup>
<FormGroup>
<Label for="address">Address</Label>
<Input type="text" name="address" id="address" value={item.address || ''}
onChange={this.handleChange} autoComplete="address"/>
</FormGroup>
<FormGroup>
<Button color="primary" type="submit">Save</Button>{' '}
<Button color="secondary" tag={Link} to="/customers">Cancel</Button>
</FormGroup>
</Form>
</Container>
</div>
}
}
export default withRouter(CustomerEdit);
Edit Reactjs App.js Component
App.js
uses React Router to navigate between components.
- path “/” is mapped with Home component
- path “/customers” is mapped with CustomerList component
- path “customers/:id” is mapped with CustomerEdit component
import React, { Component } from 'react';
import './App.css';
import Home from './Home';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import CustomerList from './CustomerList';
import CustomerEdit from './CustomerEdit';
class App extends Component {
render() {
return (
<Router>
<Switch>
<Route path='/' exact={true} component={Home}/>
<Route path='/customers' exact={true} component={CustomerList}/>
<Route path='/customers/:id' component={CustomerEdit}/>
</Switch>
</Router>
)
}
}
export default App;
Add a Proxy Setting for calling RestAPIs
To proxy from /api
to http://localhost:8080/api
, add a proxy setting to app/package.json
.
"scripts": {...},
"proxy": "http://localhost:8080",
Integrative Testing: Reactjs Application with SpringBoot CRUD RestAPIs + PostgreSQL
– Run SpringBoot project, check PostgreSQL database:

– Start Reactjs Application by cmd: yarn start
.

Testcase 1: Reactjs Post request – Post data to PostgreSQL through SpringBoot RestAPI

Testcase 2: Reactjs Put request – Put data to PostgreSQL through SpringBoot RestAPI

Testcase 3: Reactjs Fetch request – Get All data from PostgreSQL through SpringBoot RestAPI

Testcase 4: Reactjs Delete request – Delete an entity from PostgreSQL through SpringBoot RestAPI
– Delete a Customer “Adam” with id=2:

– Check PostgreSQL database after doing all CRUD operations:

Further Reading
Sourcecode
– Full Sourcecode: React.js + SpringBoot + PostgreSQL
1. Reactjs
React.js-SpringBoot-PostgreSQL-CRUD-Example
2. SpringBoot RestAPI
SpringBoot-Reactjs-PostgreSQL-CRUD-Example
– Github Sourcecode:
1. Reactjs.
2. SpringBoot RestAPI:
SpringBoot Reactjs CRUD PostgreSQL RestAPI – Github
Thks
Helpful!
Thank pro!
Very helpful
So very good man!
So nice sir ! Thank you
Thank sir! realy cleary and detail ! LOve the code
From Japan! Thank so much sir
I need more tut for my assignment about react! Please post sir
Great post man
I’m fan of your site! Great tut with details step for every level! So goood
Thank you from USA ! Keep do it pro .
Hello man! Please help me – i need you to teach more via What APPs
Thank you – so nice and helpful tut
The Rock – Keep do it! Waiting you every day
The best tutorial! Thank man