In this article, we explore how to create a full-stack application by integrating a React frontend with a Java Spring Boot backend. You'll learn the theory behind CRUD (Create, Read, Update, Delete) operations, how to set up an API in Spring Boot, and how to connect it to a React application using Axios. Step-by-step code examples are provided to demonstrate how to perform these operations, making this article an essential resource for developers looking to build efficient and scalable web applications.
Let’s break down the process of connecting a React frontend with Java Web API to perform CRUD operations. I'll provide both the theory and working code examples.
Theory
What is a CRUD Operation?
CRUD stands for Create, Read, Update, and Delete. These are the basic operations you can perform on data in a database.
- Create: Add a new record.
- Read: Retrieve existing records.
- Update: Modify an existing record.
- Delete: Remove a record.
Java Core Web API
A Java Core Web API allows you to expose your backend services via HTTP, making them accessible to clients like web applications, mobile apps, etc. The API endpoints correspond to the CRUD operations.
For example
- POST /api/items: Create a new item.
- GET /api/items: Retrieve all items.
- GET /api/items/{id}: Retrieve a specific item by ID.
- PUT /api/items/{id}: Update an existing item by ID.
- DELETE /api/items/{id}: Delete an item by ID.
React Frontend
React is a JavaScript library used to build user interfaces. It can interact with your API using HTTP requests (e.g., using fetch or Axios).
Spring Boot Setup
First, ensure you have a Spring Boot project set up. You can create a new Spring Boot project using Spring Initializr (https://start.spring.io/) with dependencies like Spring Web and Spring Data JPA.
Java Model
In your Java project, create an Item model.
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Java Repository
Create a repository interface for Item.
import org.springframework.data.jpa.repository.JpaRepository;
public interface ItemRepository extends JpaRepository<Item, Long> {
}
Java Controller
Create a controller to handle the CRUD operations.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/api/items")
public class ItemController {
@Autowired
private ItemRepository itemRepository;
@GetMapping
public List<Item> getItems() {
return itemRepository.findAll();
}
@GetMapping("/{id}")
public ResponseEntity<Item> getItem(@PathVariable Long id) {
Optional<Item> item = itemRepository.findById(id);
if (item.isPresent()) {
return ResponseEntity.ok(item.get());
} else {
return ResponseEntity.notFound().build();
}
}
@PostMapping
public Item createItem(@RequestBody Item item) {
return itemRepository.save(item);
}
@PutMapping("/{id}")
public ResponseEntity<Item> updateItem(@PathVariable Long id, @RequestBody Item itemDetails) {
Optional<Item> item = itemRepository.findById(id);
if (item.isPresent()) {
Item existingItem = item.get();
existingItem.setName(itemDetails.getName());
return ResponseEntity.ok(itemRepository.save(existingItem));
} else {
return ResponseEntity.notFound().build();
}
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteItem(@PathVariable Long id) {
Optional<Item> item = itemRepository.findById(id);
if (item.isPresent()) {
itemRepository.delete(item.get());
return ResponseEntity.noContent().build();
} else {
return ResponseEntity.notFound().build();
}
}
}
Database Configuration
In your application.properties or application.yml file, configure your database connection (e.g., using H2 for simplicity):
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
Running the Spring Boot Application
To run the Spring Boot application.
./mvnw spring-boot:run
React Frontend Setup
Setting Up React Project
npx create-react-app my-app
cd my-app
npm install axios
Creating an API Service in React
Create a file src/apiService.js.
import axios from 'axios';
const API_URL = 'http://localhost:8080/api/items';
export const getItems = async () => {
return await axios.get(API_URL);
};
export const getItemById = async (id) => {
return await axios.get(`${API_URL}/${id}`);
};
export const createItem = async (data) => {
return await axios.post(API_URL, data);
};
export const updateItem = async (id, data) => {
return await axios.put(`${API_URL}/${id}`, data);
};
export const deleteItem = async (id) => {
return await axios.delete(`${API_URL}/${id}`);
};
Implementing CRUD Operations in React
In src/App.js.
import React, { useState, useEffect } from 'react';
import { getItems, createItem, updateItem, deleteItem } from './apiService';
function App() {
const [items, setItems] = useState([]);
const [newItem, setNewItem] = useState('');
useEffect(() => {
loadItems();
}, []);
const loadItems = async () => {
const response = await getItems();
setItems(response.data);
};
const handleCreate = async () => {
if (newItem.trim()) {
await createItem({ name: newItem });
setNewItem('');
loadItems();
}
};
const handleUpdate = async (id) => {
const updatedName = prompt("Enter new name:");
if (updatedName) {
await updateItem(id, { name: updatedName });
loadItems();
}
};
const handleDelete = async (id) => {
if (window.confirm("Are you sure you want to delete this item?")) {
await deleteItem(id);
loadItems();
}
};
return (
<div>
<h1>Items</h1>
<ul>
{items.map(item => (
<li key={item.id}>
{item.name}
<button onClick={() => handleUpdate(item.id)}>Update</button>
<button onClick={() => handleDelete(item.id)}>Delete</button>
</li>
))}
</ul>
<input
type="text"
value={newItem}
onChange={(e) => setNewItem(e.target.value)}
placeholder="Enter new item name"
/>
<button onClick={handleCreate}>Add Item</button>
</div>
);
}
export default App;
Running the Application
Run the ASP.NET Core Web API.
Ensure your API is running on http://localhost:5000.
Run the React App.
npm start
The React app should now be running on http://localhost:3000.
Handling CORS (if necessary)
CORS Configuration
If you encounter CORS issues, make sure your Java API is configured to allow requests from your React app. In Spring Boot, you can configure CORS globally using a WebMvcConfigurer bean. Spring Boot automatically sets up the necessary routing and controller mappings.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*");
}
};
}
}
Testing
You can now perform all CRUD operations (Create, Read, Update, Delete) from the React frontend, and they should interact with the Java Web API.
This setup provides a full cycle of data operations from the frontend to the backend. Feel free to modify and expand on this foundation as per your requirements!
Conclusion
In this article, we’ve demonstrated how to build a full-stack application by integrating a React frontend with a Java Spring Boot backend to perform seamless CRUD operations. By following the steps outlined, you’ve learned how to,
- Set up a Spring Boot project to create a RESTful API.
- Implement CRUD operations in a Spring Boot controller.
- Connect your React frontend to the Spring Boot backend using Axios to manage data.
- Handle asynchronous requests and update the UI in real-time.
This powerful combination of React and Spring Boot provides a robust foundation for developing scalable and maintainable web applications. Whether you're managing simple data or building more complex applications, understanding how to perform CRUD operations across a frontend and backend is a crucial skill in full-stack development.
With this knowledge, you’re now equipped to expand your application further—perhaps by adding user authentication, enhancing your UI, or deploying your application to a production environment. The possibilities are endless, and this article is just the beginning of your journey into full-stack development with React and Spring Boot.
Happy coding!