├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── loizenai │ │ └── springboot │ │ └── reactjs │ │ ├── Initializer.java │ │ ├── SpringBootCrudReactApplication.java │ │ ├── controller │ │ └── CustomerController.java │ │ ├── model │ │ └── Customer.java │ │ └── repository │ │ └── CustomerRepository.java └── resources │ └── application.properties └── test └── java └── com └── loizenai └── springboot └── reactjs └── SpringBootCrudReactApplicationTests.java /README.md: -------------------------------------------------------------------------------- 1 | # SpringBoot + React + PostgreSQL: SpringBoot React.js CRUD Example 2 | 3 | ![SpringBoot + React + PostgreSQL: SpringBoot React.js CRUD Example](https://loizenai.com/wp-content/uploads/2020/10/SpringBoot-React-PostgreSQL-Build-CRUD-Application-with-SpringBoot-React.js-Example.png) 4 | 5 | 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: 6 | 7 | – SpringBoot project produces CRUD RestAPIs with PostgreSQL database using the supporting of Spring Data JPA. 8 | – React.js project will consume the SpringBoot CRUD RestAPIs by Ajax then show up on Reactjs component’s views. 9 | 10 | List to do: 11 | 12 | – I draw a fullstack overview Diagram Architecture from React.js Frontend to PostgreSQL database through SpringBoot RestAPI backend. 13 | – Develop SpringBoot CRUD RestAPIs with the supporting of SpringWeb Framework. 14 | – Implement Reactjs CRUD application with Ajax fetching APIs to do CRUD request (Post/Get/Put/Delete) to SpringBoot Backend APIs. 15 | – 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. 16 | 17 | ## Overall Architecture System: Reactjs + SpringBoot + PostgreSQL 18 | 19 | ![Overall Architecture System: Reactjs + SpringBoot + PostgreSQL](https://loizenai.com/wp-content/uploads/2020/10/React.js-SpringBoot-PostgreSQL-Diagram-Architecture-1.png) 20 | 21 | - 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. 22 | - 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. 23 | 24 | ## SpringBoot PostgreSQL CRUD Design Application 25 | 26 | ![SpringBoot PostgreSQL CRUD Design Application](https://loizenai.com/wp-content/uploads/2020/10/SpringBoot-PostgreSQL-CRUD-RestAPI-Fullstack-Diagram-Architecture.png) 27 | 28 | 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. 29 | 30 | We build a SpringBoot project with 2 layers: 31 | – SpringJPA Repository is used to interact with PostgreSQL database by a set of CRUD operations. 32 | – 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. 33 | 34 | ## Reactjs CRUD Application Design 35 | 36 | ![Reactjs CRUD Application Design](https://loizenai.com/wp-content/uploads/2020/10/Reactjs-CRUD-RestAPI-Application-Frontend-Architecture-Diagram-2.png) 37 | 38 | – Reactjs CRUD Application is designed with 2 main layers: 39 | 40 | React.js components let you split the UI into independent, reusable pieces, and think about each piece in isolation. 41 | Ajax is used by Reactjs component to fetch (post/put/get/delete) data from remote restapi by http request 42 | 43 | Reactjs CRUD Application defines 5 components: 44 | 45 | - Home.js is used serve as the landing page for your app. 46 | - AppNavbar.js is used to establish a common UI feature between components. 47 | - CustomerList.js is used to show all customers in the web-page 48 | - CustomerEdit.js is used to modify the existed customer 49 | - App.js uses React Router to navigate between components. 50 | 51 | ## Integrative Project Goal 52 | 53 | ![Integrative Project Goal](https://loizenai.com/wp-content/uploads/2020/10/Project-Goal-Customer-List-3.png) 54 | 55 | 56 | Tutorial Link: [SpringBoot + React + PostgreSQL](https://loizenai.com/reactjs-springboot-crud-postgresql/) 57 | 58 | Reactjs + SpringBoot serial: 59 | 60 | Reactjs SpringBoot serial tutorials: 61 | - [How to Integrate Reactjs with SpringBoot Tutorial](https://loizenai.com/integrate-reactjs-springboot/) 62 | - [SpringBoot + React + MySQL: SpringBoot React.js CRUD Example](https://loizenai.com/springboot-react-mysql-crud-example/) 63 | - [SpringBoot + React + PostgreSQL: SpringBoot React.js CRUD Example](https://loizenai.com/reactjs-springboot-crud-postgresql/) 64 | 65 | Related posts: 66 | 67 | - [Angular 10 + Nodejs JWT Token Based Authentication with MongoDB Example – Express RestAPIs + JWT + BCryptjs + Sequelize](https://loizenai.com/angular-10-nodejs-jwt-authentication-MongoDB-examples-tutorials/) 68 | - [SpringBoot + Angular 9 + PostgreSQL CRUD Example – Architecture Diagram](https://loizenai.com/springboot-angular-9-postgresql-crud-example-architecture-diagram/) 69 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.3.4.RELEASE 9 | 10 | 11 | com.loizenai.springboot 12 | SpringBootCrudReact 13 | 1.00 14 | SpringBootCrudReact 15 | SpringBoot CRUD RestAPI with React.js Client 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-data-jpa 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | org.projectlombok 32 | lombok 33 | 1.18.10 34 | provided 35 | 36 | 37 | org.postgresql 38 | postgresql 39 | runtime 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-test 44 | test 45 | 46 | 47 | org.junit.vintage 48 | junit-vintage-engine 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-maven-plugin 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/main/java/com/loizenai/springboot/reactjs/Initializer.java: -------------------------------------------------------------------------------- 1 | package com.loizenai.springboot.reactjs; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | 6 | import org.springframework.boot.CommandLineRunner; 7 | import org.springframework.stereotype.Component; 8 | 9 | import com.loizenai.springboot.reactjs.model.Customer; 10 | import com.loizenai.springboot.reactjs.repository.CustomerRepository; 11 | 12 | @Component 13 | class Initializer implements CommandLineRunner { 14 | 15 | private final CustomerRepository repository; 16 | 17 | public Initializer(CustomerRepository repository) { 18 | this.repository = repository; 19 | } 20 | 21 | @Override 22 | public void run(String... strings) { 23 | 24 | ArrayList customers = new ArrayList( Arrays.asList( 25 | new Customer("Jack", "Smith", "374 William S Canning Blvd", 23), 26 | new Customer("Adam", "Johnson", "Fall River MA 2721. 121 Worcester Rd", 31), 27 | new Customer("Dana", "Bay", "Framingham MA 1701. 677 Timpany Blvd", 46)) ); 28 | 29 | System.out.println(customers); 30 | 31 | repository.saveAll(customers); 32 | 33 | repository.findAll().forEach(System.out::println); 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/com/loizenai/springboot/reactjs/SpringBootCrudReactApplication.java: -------------------------------------------------------------------------------- 1 | package com.loizenai.springboot.reactjs; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpringBootCrudReactApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpringBootCrudReactApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/loizenai/springboot/reactjs/controller/CustomerController.java: -------------------------------------------------------------------------------- 1 | package com.loizenai.springboot.reactjs.controller; 2 | 3 | import java.net.URI; 4 | import java.net.URISyntaxException; 5 | import java.util.Collection; 6 | import java.util.Optional; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.DeleteMapping; 13 | import org.springframework.web.bind.annotation.GetMapping; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.PutMapping; 17 | import org.springframework.web.bind.annotation.RequestBody; 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RestController; 20 | 21 | import com.loizenai.springboot.reactjs.model.Customer; 22 | import com.loizenai.springboot.reactjs.repository.CustomerRepository; 23 | 24 | @RestController 25 | @RequestMapping("/api") 26 | public class CustomerController { 27 | 28 | 29 | private final Logger log = LoggerFactory.getLogger(CustomerController.class); 30 | private CustomerRepository customerRepository; 31 | 32 | public CustomerController(CustomerRepository customerRepository) { 33 | this.customerRepository = customerRepository; 34 | } 35 | 36 | @GetMapping("/customers") 37 | Collection customers() { 38 | return customerRepository.findAll(); 39 | } 40 | 41 | @GetMapping("/customer/{id}") 42 | ResponseEntity getCustomer(@PathVariable Long id) { 43 | Optional customer = customerRepository.findById(id); 44 | return customer.map(response -> ResponseEntity.ok().body(response)) 45 | .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND)); 46 | } 47 | 48 | @PostMapping("/customer") 49 | ResponseEntity createCustomer(@RequestBody Customer customer) throws URISyntaxException { 50 | log.info("Request to create customer: {}", customer); 51 | Customer result = customerRepository.save(customer); 52 | return ResponseEntity.created(new URI("/api/group/" + result.getId())) 53 | .body(result); 54 | } 55 | 56 | @PutMapping("/customer") 57 | ResponseEntity updateGroup(@RequestBody Customer customer) { 58 | log.info("Request to update customer: {}", customer); 59 | Customer result = customerRepository.save(customer); 60 | return ResponseEntity.ok().body(result); 61 | } 62 | 63 | @DeleteMapping("/customer/{id}") 64 | public ResponseEntity deleteCustomer(@PathVariable Long id) { 65 | log.info("Request to delete customer: {}", id); 66 | customerRepository.deleteById(id); 67 | return ResponseEntity.ok().build(); 68 | } 69 | } -------------------------------------------------------------------------------- /src/main/java/com/loizenai/springboot/reactjs/model/Customer.java: -------------------------------------------------------------------------------- 1 | package com.loizenai.springboot.reactjs.model; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | import lombok.NonNull; 11 | import lombok.RequiredArgsConstructor; 12 | 13 | @Data 14 | @NoArgsConstructor 15 | @RequiredArgsConstructor 16 | @Entity 17 | @Table(name = "customer") 18 | public class Customer { 19 | 20 | @Id 21 | @GeneratedValue 22 | private Long id; 23 | 24 | @NonNull 25 | private String firstname; 26 | @NonNull 27 | private String lastname; 28 | private String address; 29 | private int age; 30 | private String copyright = "https://loizenai.com"; 31 | 32 | public String toString() { 33 | return String.format("id=%d, firstname='%s', lastname'%s', address=%s, age=%d", 34 | id, firstname, lastname, address, age); 35 | } 36 | 37 | public Customer(String firstname, String lastname, String address, int age) { 38 | this.firstname = firstname; 39 | this.lastname = lastname; 40 | this.address = address; 41 | this.age = age; 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/java/com/loizenai/springboot/reactjs/repository/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | package com.loizenai.springboot.reactjs.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | import com.loizenai.springboot.reactjs.model.Customer; 6 | 7 | public interface CustomerRepository extends JpaRepository { 8 | Customer findByFirstname(String firstname); 9 | } -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:mysql://localhost:3306/loizenaidb 2 | spring.datasource.username=root 3 | spring.datasource.password=12345 4 | spring.jpa.generate-ddl=true 5 | 6 | #drop & create table again, good for testing, comment this in production 7 | spring.jpa.hibernate.ddl-auto=create -------------------------------------------------------------------------------- /src/test/java/com/loizenai/springboot/reactjs/SpringBootCrudReactApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.loizenai.springboot.reactjs; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SpringBootCrudReactApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------