Introduction
In this tutorial, I will show you how to create a simple crud operation using Springboot and React. For the backend side, I use Springboot and for the frontend side, I use React. We will also test the backend APIs using Postmen. After completing this blog you will complete CRUD operation that allows you to create, read, update, and delete the data with a smooth interaction between the frontend and backend. Let’s get started!
Prerequisites
- Basic knowledge of Java, Bootstrap, and Javascript.
- Java JDK for backend development.
- Node.js for running the React frontend.
- MYSQL for storing the data.
- VS Code for React development or any other code editor.
- IntelliJ IDEA for spring boot application development or any other IDE.
Create a Spring Boot Application for Back End
First of all, we need a project setup so please go to Spring Initializer and set up the project as per our requirements.
- Open IntelliJ and set up the project.
- Open the application.properties (or application.yml) file and add your MySQL configuration
spring.application.name=user
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/user
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
In this application.properties replace your database name, your username, and your password with your MySQL credentials.
Here below is the structure of the application.
src
├───main
│ ├───java
│ │ └───com
│ │ └───example
│ │ └───user
│ │ │ UserApplication.java
│ │ │
│ │ ├───controller
│ │ │ UserController.java
│ │ │
│ │ ├───exception
│ │ │ UserNotFoundAdvice.java
│ │ │ UserNotFoundException.java
│ │ │
│ │ ├───model
│ │ │ User.java
│ │ │
│ │ ├───repository
│ │ │ UserRepository.java
│ │ │
│ │ └───services
│ │ UserServices.java
│ │
│ └───resources
│ └───application.properties
Step 1 : Create the Entity Class
To define the data structure, create a package named model and add a class like Employee.
package com.example.user.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long userId;
private String firstName;
private String lastName;
private String email;
}
Step 2: Create the Repository Interface
To manage data persistence and retrieval in the database, create a package named repository and add an interface like EmployeeRepository.
package com.example.user.repository;
import com.example.user.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository {
}
Step 3: Create the the Service Layer
To write business logic, create a package named service and add a class like EmployeeService.
package com.example.user.services;
import com.example.user.exception.UserNotFoundException;
import com.example.user.model.User;
import com.example.user.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServices {
@Autowired
UserRepository userRepository;
public User createUser(User user){
return userRepository.save(user);
}
public User getUserById(Long id) {
return userRepository.findById(id).orElseThrow(()->new UserNotFoundException(id));
}
public List getAllUsers(){
return userRepository.findAll();
}
public User updateUser(Long id, User userDetails) {
return userRepository.findById(id).map(user -> {
user.setFirstName(userDetails.getFirstName());
user.setLastName(userDetails.getLastName());
user.setEmail(userDetails.getEmail());
return userRepository.save(user);
}).orElseThrow(() -> new UserNotFoundException(id));
}
public void deleteUser(Long id){
if(!userRepository.existsById(id)){
throw new UserNotFoundException(id);
}
userRepository.deleteById(id);
}
}
Step 4 : Define controller
To handle requests and responses create an endpoint in the controller, here I decelerate the user controller to handle the request.
package com.example.user.controller;
import com.example.user.model.User;
import com.example.user.services.UserServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/users")
@CrossOrigin("http://localhost:3000")
public class UserController {
@Autowired
UserServices userService;
@PostMapping
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}
@GetMapping("/{id}")
public User getUserById(@PathVariable("id") Long id) {
return userService.getUserById(id);
}
@GetMapping
public List getAllUsers() {
return userService.getAllUsers();
}
@PutMapping("/{id}")
public User updateUser(@PathVariable("id") Long id, @RequestBody User userDetails) {
return userService.updateUser(id, userDetails);
}
@DeleteMapping("/{id}")
public ResponseEntity deleteUser(@PathVariable("id") Long id) {
userService.deleteUser(id);
return ResponseEntity.status(HttpStatus.OK).body("deleted successfully.");
}
}
Step 5 : Create the Controller
To handle specific exceptions, create a package named exception and add a class like UserNotFoundException and UserNotFoundAdvice.
- UserNotFoundException
This class defines the custom exception for scenarios where a user is not found.
package com.example.user.exception;
public class UserNotFoundException extends RuntimeException{
public UserNotFoundException(Long id) {
super("Could not found user with id : "+id);
}
}
- UserNotFoundAdvice
This class provides advice to handle the UserNotFoundException. It uses the @ControllerAdvice and @ExceptionHandler annotations to return a structured error response.
package com.example.user.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class UserNotFoundAdvice {
@ResponseBody
@ExceptionHandler(UserNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public Map exceptionHandler(UserNotFoundException userNotFoundException){
Map errorMap = new HashMap<>();
errorMap.put("errorMessage",userNotFoundException.getMessage());
return errorMap;
}
}
Step 6 : Test APIs Using Postman
- Run the Spring Boot application.
- Open Postman and test the following endpoints :
- GET http://localhost:8080/users: Fetch all users.
- GET http://localhost:8080/users/{id}: Fetch user by id.
- POST http://localhost:8080/users/add: Add a new user.
- PUT http://localhost:8080/users/update/{id}: Edit in a existing user
- DELETE http://localhost:8080/users/delete/{id}: Delete a user.
This step completes the backend setup. Setting up the React front end will be covered in the next section. Let me know if you’d like details on that.
Create a React Project for Front End
Step 1 : Open Command Prompt and download node and npm to check version
Here is the command to check the version of node and npm
node –version
npm –version
Step 2 : Create a React Project
Here is the command to create a React project.
npm create-react-app fullstack-frontend
Step 3 : Open VS Code
- After creating the project, open VS Code and then open the project folder in it.
- Inside the src folder, create the following folders
- layout
- pages
- users
- Next, add files to these folders as follows:
In the layout folder, add a file named Navbar.js.
In the pages folder, add a file named Home.js.
In the users folder, add the following files:
- AddUser.js
- ViewUser.js
- EditUser.js
- Below is the folder structure
FULLSTACK-FRONTEND
├── node_modules
├── public
├── src
│ ├── layout
│ │ └── Navbar.js
│ ├── pages
│ │ └── Home.js
│ ├── users
│ ├── AddUser.js
│ ├── EditUser.js
│ └── ViewUser.js
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
├── reportWebVitals.js
├── setupTests.js
├── .gitignore
├── package-lock.json
├── package.json
└── README.md
Step 4 : Open the Terminal and run the following command
npm start
npm i bootstrap
npm i axios
npm i react-router-dom
- npm start
- This command starts the development server for your React application.
- It compiles the React project.
- It opens your default browser and redirects you to http://localhost:3000 (or another port if port 3000 is in use).
- It automatically reloads the application in the browser whenever you change the code.
- npm i bootstrap
- This command installs the Bootstrap library in our React project.
- It adds Bootstrap’s CSS and JavaScript functionality to our project, enabling styling and responsive design.
- After installation, we can import Bootstrap into our project.
- For example, in the App.js file, add the following line
import ‘../node_modules/bootstrap/dist/css/bootstrap.min.css’;
- npm i axios
- This command installs Axios, a popular library for making HTTP requests.
- It allows us to send API requests (GET, POST, PUT, DELETE, etc.) from the React front end to the back end.
- It simplifies working with REST APIs and handling responses.
- npm i react-router-dom
- This command installs React Router, a library for implementing routing in your React application.
- Enables navigation between different components/pages without reloading the browser.
- Provides components like <BrowserRouter>, <Route>, and <Link> to manage routing.
- Example: Switch between pages like Home, AddUser, or EditUser using URL paths.
Step 5 : In the App.js file
- Sets up the main structure of the React application.
- Uses BrowserRouter, Routes, and Route to define navigation paths for components like Home, AddUser, EditUser, and ViewUser.
- Includes the Navbar component to provide an according to navigation bar across the app.
import logo from './logo.svg';
import './App.css';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import Navbar from './layout/Navbar';
import Home from './pages/Home';
import {BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import AddUser from './users/AddUser';
import EditUser from './users/EditUser';
import ViewUser from './users/ViewUser';
function App() {
return (
}/>
}/>
}/>
} />
);
}
export default App;
Step 6 : In the Navbar.js file
- Creates a navigation bar using Bootstrap classes.
- Provides a link to the “Add User” page with a button styled as btn btn-outline-light.
- Uses Link from react-router-dom to enable seamless navigation without refreshing the page.
import React from 'react'
import { Link } from 'react-router-dom'
export default function Navbar() {
return (
)
}
Step 7 : In the Home.js file
- Displays a list of users fetched from the backend API using Axios.
- Implements a table to show user details like first name, last name, email, and actions.
- Includes options to view, edit, or delete a user.
- Handles API calls for retrieving and deleting users.
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { Link, useParams } from 'react-router-dom';
export default function Home() {
const [users, setUsers] = useState([]);
const { userId } = useParams()
useEffect(() => {
loadUsers();
}, []);
const loadUsers = async () => {
const result = await axios.get("http://localhost:8080/users");
setUsers(result.data);
};
const deleteUser = async (userId) => {
await axios.delete(`http://localhost:8080/users/${userId}`)
loadUsers()
}
return (
#
First Name
Last Name
Email
Action
{users.map((user, index) => (
// Explicitly return JSX inside the map
{index + 1}
{user.firstName}
{user.lastName}
{user.email}
View
Edit
))}
);
}
Step 8 : In the AddUser.js file
- Provides a form to add a new user with fields for first name, last name, and email.
- Uses the state to manage form input and Axios to send a POST request to the backend.
- Navigate back to the home page upon successful submission.
import axios from 'axios'
import React, { useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
export default function AddUser() {
let navigate=useNavigate()
const [user,setUser]=useState({
firstName:"",
lastName:"",
email:""
})
const{firstName,lastName,email}=user
const onInputChange=(e)=>{
setUser({...user,[e.target.name]:e.target.value})
}
const onSubmit=async (e)=>{
e.preventDefault();
await axios.post("http://localhost:8080/users",user);
navigate("/");
}
return (
Register User
)
}
Step 9 : In the ViewUser.js file
- Displays detailed information about a specific user, fetched using their user ID.
- Uses Axios to retrieve the user data from the backend.
- Provides a button to navigate back to the home page.
import React, { useEffect, useState } from 'react';
import { Link, useParams } from 'react-router-dom';
import axios from 'axios';
export default function ViewUser() {
const [user, setUser] = useState({});
const { userId } = useParams();
useEffect(() => {
loadUser();
}, []);
const loadUser = async () => {
const result = await axios.get(`http://localhost:8080/users/${userId}`);
setUser(result.data);
};
return (
User Details
Details of User Id: {userId}
-
First Name: {user.firstName}
-
Last Name: {user.lastName}
-
Email: {user.email}
Back to Home
);
}
Step 10 : In the EditUrer.js file
- Provides a form pre-filled with the details of the user to be edited, and fetched using their user ID.
- Uses the state to manage form input and Axios to send a PUT request to update the user in the backend.
- Navigate back to the home page after successful submission.
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import { Link, useNavigate, useParams } from 'react-router-dom';
export default function EditUser() {
let navigate = useNavigate();
const [user, setUser] = useState({
firstName: "",
lastName: "",
email: ""
});
const { firstName, lastName, email } = user;
const { userId } = useParams();
const onInputChange = (e) => {
setUser({ ...user, [e.target.name]: e.target.value });
};
useEffect(() => {
loadUser();
}, []);
const onSubmit = async (e) => {
e.preventDefault();
await axios.put(`http://localhost:8080/users/${userId}`, user);
navigate("/");
};
const loadUser = async () => {
const result = await axios.get(`http://localhost:8080/users/${userId}`);
setUser(result.data);
};
return (
Edit User
);
}
Final Output of Every Page
- To run this application, first start the Spring Boot application, and then run the npm start command in the terminal of VS Code. This will automatically redirect to the default page of the application, and the look of the page will appear as shown in the image below.
- After this, on the home page, we can view existing users, add a new user, or see a list of users. From the list, we can also edit, view, or delete a user. Let’s proceed to add a new user.
- In the Add User page, a registration form will open where we can either add a new user or cancel the operation. Once the user is added or the cancel button is clicked, it will automatically redirect to the home page. After this, we will proceed to view a user.
- By selecting View User, the application will display the data of the specific user. There will be an option to Back to Home, which will redirect us back to the home page. After this, we will proceed to edit an existing user.
- When we select Edit User, the Edit User screen will open, pre-filled with the user’s data. You can update the data, and once the changes are saved, the user information will be updated. Next, we will proceed to delete a user.
Once the delete action is performed, the user will be removed from the list. The page will update automatically, reflecting the deletion. After this, you can proceed with any other operations like adding, viewing, or editing users.
Conclusion
In this tutorial, we create a full-stack CRUD application using React for the frontend and Spring Boot for the backend. We managed a user database with operations like Add, View, Edit, and Delete. The user interface was created with React and Bootstrap-styled responsive components. We used Axios for smooth data exchange between the frontend and backend, and React Router for seamless page navigation. On the backend, Spring Boot handled user management logic with Spring Data JPA and a MySQL database. This project demonstrates the core concepts of building a full-stack application and provides practical experience with React, Bootstrap, Spring Boot, and MySQL. You can expand this application by adding features like authentication and user roles.