Introduction
In this chapter, we will explore how to implement a one-to-one relationship in a Spring Boot application by building a User Management Project. We will create entities for User and Profile, configure the one-to-one relationship between them, and demonstrate how to perform CRUD operations.
Table of Contents
- Introduction
- Create and Setup Spring Boot Project in IntelliJ IDEA
- Configure H2 Database
- Create User and Profile Entities
- Configure One-to-One Relationship
- Create User Repository
- Create Profile Repository
- Create Service Layer
- UserService
- UserServiceImpl
- Create UserController
- Test the Application
- Conclusion
Create and Setup Spring Boot Project in IntelliJ IDEA
Create a New Spring Boot Project
- Open Spring Initializr:
- Go to Spring Initializr in your web browser.
- Configure Project Metadata:
- Project: Maven Project
- Language: Java
- Spring Boot: 3.2.0
- Group:
com.example - Artifact:
user-management - Name:
user-management - Description:
User Management System with One-to-One Mapping - Package name:
com.example.usermanagement - Packaging: Jar
- Java: 17 (or the latest version available)
- Add Dependencies:
- Spring Web
- Spring Data JPA
- H2 Database
- Generate the Project:
- Click “Generate” to download the project as a ZIP file.
- Import Project into IntelliJ IDEA:
- Open IntelliJ IDEA.
- Click on “Open” and navigate to the downloaded ZIP file.
- Extract the ZIP file and import the project.
Explanation
- Spring Initializr: A web-based tool provided by Spring to bootstrap a new Spring Boot project with dependencies and configurations.
- Group and Artifact: Define the project’s Maven coordinates.
- Dependencies: Adding dependencies ensures that the necessary libraries are included in the project for web development, JPA, and H2 database connectivity.
Configure H2 Database
Update application.properties
- Open
application.properties:- Navigate to
src/main/resources/application.properties.
- Navigate to
- Add H2 Database Configuration:
- Add the following properties to configure the H2 database connection:
spring.datasource.url=jdbc:h2:mem:userdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
Explanation
spring.datasource.url: The JDBC URL to connect to the H2 database in memory.spring.datasource.driverClassName: The driver class name for H2 database.spring.datasource.username: The username to connect to the H2 database.spring.datasource.password: The password to connect to the H2 database.spring.jpa.hibernate.ddl-auto: Specifies the Hibernate DDL mode. Setting it toupdateautomatically updates the database schema based on the entity mappings.spring.h2.console.enabled: Enables the H2 database console for easy access to the database through a web browser.spring.h2.console.path: Specifies the path to access the H2 console.
Create User and Profile Entities
Create the User Class
- Create a New Package:
- In the
src/main/java/com/example/usermanagementdirectory, create a new package namedmodel.
- In the
- Create the
UserClass:- Inside the
modelpackage, create a new class namedUser. - Add the following code to the
Userclass:
- Inside the
package com.example.usermanagement.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToOne;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
@OneToOne(mappedBy = "user")
private Profile profile;
// Constructors
public User() {}
public User(String username, String password) {
this.username = username;
this.password = password;
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Profile getProfile() {
return profile;
}
public void setProfile(Profile profile) {
this.profile = profile;
}
}
Create the Profile Class
- Create the
ProfileClass:- Inside the
modelpackage, create a new class namedProfile. - Add the following code to the
Profileclass:
- Inside the
package com.example.usermanagement.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
@Entity
public class Profile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String email;
@OneToOne
@JoinColumn(name = "user_id")
private User user;
// Constructors
public Profile() {}
public Profile(String firstName, String lastName, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Explanation
@Entity: Specifies that the class is an entity and is mapped to a database table.@Id: Specifies the primary key of the entity.@GeneratedValue: Specifies how the primary key should be generated.GenerationType.IDENTITYindicates that the primary key is auto-incremented.@OneToOne: Specifies a one-to-one relationship between theUserandProfileentities.@JoinColumn: Specifies the foreign key column in theProfiletable that references the primary key of theUsertable.
Create User Repository
Create the UserRepository Interface
- Create a New Package:
- In the
src/main/java/com/example/usermanagementdirectory, create a new package namedrepository.
- In the
- Create the
UserRepositoryInterface:- Inside the
repositorypackage, create a new interface namedUserRepository. - Add the following code to the
UserRepositoryinterface:
- Inside the
package com.example.usermanagement.repository;
import com.example.usermanagement.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
Explanation
JpaRepository: TheUserRepositoryinterface extendsJpaRepository, providing CRUD operations for theUserentity. TheJpaRepositoryinterface includes methods likesave(),findById(),findAll(),deleteById(), etc.- Generics: The
JpaRepositoryinterface takes two parameters: the entity type (User) and the type of its primary key (Long).
Create Profile Repository
Create the ProfileRepository Interface
- Create a New Package:
- In the
src/main/java/com/example/usermanagementdirectory, create a new package namedrepository.
- In the
- Create the
ProfileRepositoryInterface:- Inside the
repositorypackage, create a new interface namedProfileRepository. - Add the following code to the
ProfileRepositoryinterface:
- Inside the
package com.example.usermanagement.repository;
import com.example.usermanagement.model.Profile;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProfileRepository extends JpaRepository<Profile, Long> {
}
Explanation
JpaRepository: TheProfileRepositoryinterface extendsJpaRepository, providing CRUD operations for theProfileentity. TheJpaRepositoryinterface includes methods likeĀsave(),findById(),findAll(),deleteById(), etc.- Generics: The
JpaRepositoryinterface takes two parameters: the entity type (Profile) and the type of its primary key (Long).
Create Service Layer
Create UserService Interface
- Create a New Package:
- In the
src/main/java/com/example/usermanagementdirectory, create a new package namedservice.
- In the
- Create the
UserServiceInterface:- Inside the
servicepackage, create a new interface namedUserService. - Add the following code to the
UserServiceinterface:
- Inside the
package com.example.usermanagement.service;
import com.example.usermanagement.model.User;
import java.util.List;
public interface UserService {
User saveUser(User user);
User getUserById(Long id);
List<User> getAllUsers();
User updateUser(Long id, User userDetails);
void deleteUser(Long id);
}
Explanation
- Service Interface: Defines the contract for the service layer. It includes methods for saving, retrieving, updating, and deleting users.
Create UserServiceImpl Class
- Create the
UserServiceImplClass:- Inside the
servicepackage, create a new class namedUserServiceImpl. - Add the following code to the
UserServiceImplclass:
- Inside the
package com.example.usermanagement.service;
import com.example.usermanagement.model.User;
import com.example.usermanagement.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public User saveUser(User user) {
return userRepository.save(user);
}
@Override
public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found with id: " + id));
}
@Override
public List<User> getAllUsers() {
return userRepository.findAll();
}
@Override
public User updateUser(Long id, User userDetails) {
User user = userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found with id: " + id));
user.setUsername(userDetails.getUsername());
user.setPassword(userDetails.getPassword());
user.setProfile(userDetails.getProfile());
return userRepository.save(user);
}
@Override
public void deleteUser(Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found with id: " + id));
userRepository.delete(user);
}
}
Explanation
@Service: Indicates that this class is a service component in the Spring context.UserRepository: TheUserRepositoryinstance is injected into the service class to interact with the database.- Exception Handling: The
getUserById,updateUser, anddeleteUsermethods throw aRuntimeExceptionif the user is not found.
Create UserController
Create the UserController Class
- Create a New Package:
- In the
src/main/java/com/example/usermanagementdirectory, create a new package namedcontroller.
- In the
- Create the
UserControllerClass:- Inside the
controllerpackage, create a new class namedUserController. - Add the following code to the
UserControllerclass:
- Inside the
package com.example.usermanagement.controller;
import com.example.usermanagement.model.User;
import com.example.usermanagement.service.UserService;
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;
@PostMapping
public ResponseEntity<User> saveUser(@RequestBody User user) {
User savedUser = userService.saveUser(user);
return new ResponseEntity<>(savedUser, HttpStatus.CREATED);
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
User user = userService.getUserById(id);
return new ResponseEntity<>(user, HttpStatus.OK);
}
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
List<User> users = userService.getAllUsers();
return new ResponseEntity<>(users, HttpStatus.OK);
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User userDetails) {
User updatedUser = userService.updateUser(id, userDetails);
return new ResponseEntity<>(updatedUser, HttpStatus.OK);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}
Explanation
@RestController: Indicates that this class is a REST controller.@RequestMapping("/api/users"): Maps HTTP requests to/api/usersto methods in this controller.@PostMapping: Handles HTTP POST requests to save a user.@GetMapping("/{id}"): Handles HTTP GET requests to retrieve a user by ID.@GetMapping: Handles HTTP GET requests to retrieve all users.@PutMapping("/{id}"): Handles HTTP PUT requests to update a user’s details.@DeleteMapping("/{id}"): Handles HTTP DELETE requests to delete a user by ID.
Test the Application
Run the Application
- Run the Application:
- In IntelliJ IDEA, run the
UserManagementApplicationclass.
- In IntelliJ IDEA, run the
Access the Application
- Open Web Browser:
- Open a web browser and go to
http://localhost:8080/api/users.
- Open a web browser and go to
- Verify the Application:
- Verify that you can perform CRUD operations on users and their associated profiles.
Conclusion
In this chapter, we built a User Management System project using Spring Boot with a one-to-one relationship between User and Profile entities. We configured the H2 database, created entities and repositories, and demonstrated how to perform CRUD operations through a RESTful API. Each step was explained in detail to help you understand how to implement one-to-one relationships in a Spring Boot application.