Building a User CRUD Application with Spring Boot and Docker
This article will guide you through building a user CRUD (Create, Read, Update, Delete) application using Spring Boot and Docker. This combination empowers developers to build robust and scalable applications quickly and efficiently.
Introduction
Spring Boot is a popular Java-based framework that simplifies web application development by providing auto-configuration and convention over configuration. Docker, on the other hand, is a containerization technology that enables you to package your application and its dependencies into a self-contained unit, making it easy to deploy and run on any platform.
Combining Spring Boot and Docker offers several benefits:
- Rapid Development: Spring Boot's auto-configuration and built-in features significantly reduce development time.
- Portability and Scalability: Docker allows you to deploy your application consistently across different environments without compatibility issues.
- Simplified Deployment: Docker containers can be easily deployed and managed on various platforms, including cloud providers and on-premises infrastructure.
- Improved Security: Docker containers isolate your application from the host system, enhancing security.
In this article, we will build a basic user CRUD application and package it in a Docker container. We will cover the following steps:
- Setting up the Project
- Creating the User Model
- Building the REST Controller
- Implementing Data Persistence
- Creating a Dockerfile
- Running and Testing the Application
Setting up the Project
We'll use Spring Initializr (https://start.spring.io/) to generate a basic Spring Boot project with the necessary dependencies:
-
Visit Spring Initializr and select the following options:
- Dependencies: Spring Web, Spring Data JPA, H2 Database
- Language: Java
- Packaging: Jar
- Generate the project and extract the zip file. You'll have a basic Spring Boot project structure ready to go.
Creating the User Model
We'll create a simple
User
entity to represent a user in our application:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String email;
// Constructors, getters, and setters
}
Building the REST Controller
Now, we'll create a REST controller to handle user-related requests:
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;
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public ResponseEntity
<list<user>
> getAllUsers() {
return ResponseEntity.ok(userService.getAllUsers());
}
@PostMapping
public ResponseEntity
<user>
createUser(@RequestBody User user) {
return ResponseEntity.status(HttpStatus.CREATED).body(userService.createUser(user));
}
@GetMapping("/{id}")
public ResponseEntity
<user>
getUserById(@PathVariable Long id) {
return ResponseEntity.ok(userService.getUserById(id));
}
@PutMapping("/{id}")
public ResponseEntity
<user>
updateUser(@PathVariable Long id, @RequestBody User user) {
return ResponseEntity.ok(userService.updateUser(id, user));
}
@DeleteMapping("/{id}")
public ResponseEntity
<void>
deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}
<h2>
Implementing Data Persistence
</h2>
<p>
We'll use Spring Data JPA to simplify data persistence. Create a
<code>
UserRepository
</code>
interface:
</p>
```java
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository
{
// No additional methods needed for basic CRUD operations
}
<p>
Then create a
<code>
UserService
</code>
class to manage user operations:
</p>
```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List
<user>
getAllUsers() {
return userRepository.findAll();
}
public User createUser(User user) {
return userRepository.save(user);
}
public User getUserById(Long id) {
Optional
<user>
user = userRepository.findById(id);
return user.orElseThrow(() -> new ResourceNotFoundException("User not found with id " + id));
}
public User updateUser(Long id, User user) {
Optional
<user>
existingUser = userRepository.findById(id);
if (existingUser.isPresent()) {
existingUser.get().setFirstName(user.getFirstName());
existingUser.get().setLastName(user.getLastName());
existingUser.get().setEmail(user.getEmail());
return userRepository.save(existingUser.get());
} else {
throw new ResourceNotFoundException("User not found with id " + id);
}
}
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}
<p>
We also need to create a
<code>
ResourceNotFoundException
</code>
class to handle user not found errors:
</p>
```java
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
<h2>
Creating a Dockerfile
</h2>
<p>
Now, let's create a
<code>
Dockerfile
</code>
to package our application into a container:
</p>
```dockerfile
FROM openjdk:11-jre-slim
COPY target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
<p>
Explanation:
</p>
<ul>
<li>
<code>
FROM openjdk:11-jre-slim
</code>
: This line specifies the base image for our container, which is a slimmed-down OpenJDK 11 JRE image.
</li>
<li>
<code>
COPY target/*.jar app.jar
</code>
: This line copies the compiled JAR file from the
<code>
target
</code>
directory of your Spring Boot project to the
<code>
app.jar
</code>
file inside the container.
</li>
<li>
<code>
ENTRYPOINT ["java", "-jar", "/app.jar"]
</code>
: This line defines the command to execute when the container starts, which is to run the JAR file using the
<code>
java
</code>
command.
</li>
</ul>
<h2>
Running and Testing the Application
</h2>
<p>
Now, we can build and run the Docker image:
</p>
<ol>
<li>
Build the Docker image:
<code>
docker build -t my-user-app .
</code>
</li>
<li>
Run the Docker image:
<code>
docker run -p 8080:8080 my-user-app
</code>
</li>
</ol>
<p>
Once the container is running, you can access the REST endpoints using a tool like Postman or curl. For example, to create a new user:
</p>
```
curl -X POST -H "Content-Type: application/json" -d '{"firstName": "John", "lastName": "Doe", "email": "john.doe@example.com"}' http://localhost:8080/api/users
<h2>
Conclusion
</h2>
<p>
This article has demonstrated how to build a simple user CRUD application using Spring Boot and Docker. We covered the essential steps involved in creating a RESTful API, implementing data persistence, and containerizing the application for easy deployment and scalability.
</p>
<p>
Here are some key takeaways:
</p>
<ul>
<li>
Spring Boot provides a framework for rapid web application development with auto-configuration and convention over configuration.
</li>
<li>
Docker enables packaging and running applications in isolated containers, ensuring portability and consistency.
</li>
<li>
By combining Spring Boot and Docker, you can build and deploy applications efficiently, ensuring scalability and portability.
</li>
</ul>
<p>
This is just a basic example. You can extend this application further by adding authentication, authorization, more complex data models, and other functionalities to suit your specific needs.
</p>
</user>
</user>
</user>
</user,>
</void>
</user>
</user>
</user>
</list<user>