Introduction
In this chapter, we will explore how to implement a one-to-many relationship in a Spring Boot application by building an Employee Management Project. We will create entities for Employee and Department, configure the one-to-many 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 Employee and Department Entities
- Configure One-to-Many Relationship
- Create Employee Repository
- Create Department Repository
- Create Service Layer
- EmployeeService
- EmployeeServiceImpl
- DepartmentService
- DepartmentServiceImpl
- Create EmployeeController
- Create DepartmentController
- 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:
employee-management - Name:
employee-management - Description:
Employee Management System with One-to-Many Mapping - Package name:
com.example.employeemanagement - 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:employeedb
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 Employee and Department Entities
Create the Employee Class
-
Create a New Package:
- In the
src/main/java/com/example/employeemanagementdirectory, create a new package namedmodel.
- In the
-
Create the
EmployeeClass:- Inside the
modelpackage, create a new class namedEmployee. - Add the following code to the
Employeeclass:
- Inside the
package com.example.employeemanagement.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String email;
@ManyToOne
private Department department;
// Constructors
public Employee() {}
public Employee(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 Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
}
Create the Department Class
- Create the
DepartmentClass:- Inside the
modelpackage, create a new class namedDepartment. - Add the following code to the
Departmentclass:
- Inside the
package com.example.employeemanagement.model;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import java.util.ArrayList;
import java.util.List;
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "department", cascade = CascadeType.ALL)
private List<Employee> employees = new ArrayList<>();
// Constructors
public Department() {}
public Department(String name) {
this.name = 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;
}
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
// Utility method to add employee
public void addEmployee(Employee employee) {
employees.add(employee);
employee.setDepartment(this);
}
}
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.@ManyToOne: Specifies a many-to-one relationship between theEmployeeandDepartmententities.@OneToMany: Specifies a one-to-many relationship between theDepartmentandEmployeeentities.@CascadeType.ALL: Specifies that all cascade types (persist, merge, remove, refresh, detach) should be applied.- Utility method:
addEmployeeis a utility method to add an employee to a department and set the department for the employee.
Create Employee Repository
Create the EmployeeRepository Interface
-
Create a New Package:
- In the
src/main/java/com/example/employeemanagementdirectory, create a new package namedrepository.
- In the
-
Create the
EmployeeRepositoryInterface:- Inside the
repositorypackage, create a new interface namedEmployeeRepository. - Add the following code to the
EmployeeRepositoryinterface:
- Inside the
package com.example.employeemanagement.repository;
import com.example.employeemanagement.model.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
Explanation
JpaRepository: TheEmployeeRepositoryinterface extendsJpaRepository, providing CRUD operations for theEmployeeentity. TheJpaRepositoryinterface includes methods likesave(),findById(),findAll(),deleteById(), etc.- Generics: The
JpaRepositoryinterface takes two parameters: the entity type (Employee) and the type of its primary key (Long).
Create Department Repository
Create the DepartmentRepository Interface
- Create the
DepartmentRepositoryInterface:- Inside the
repositorypackage, create a new interface namedDepartmentRepository. - Add the following code to the
DepartmentRepositoryinterface:
- Inside the
package com.example.employeemanagement.repository;
import com.example.employeemanagement.model.Department;
import org.springframework.data.jpa.repository.JpaRepository;
public interface Department
Repository extends JpaRepository<Department, Long> {
}
Explanation
JpaRepository: TheDepartmentRepositoryinterface extendsJpaRepository, providing CRUD operations for theDepartmententity. TheJpaRepositoryinterface includes methods likesave(),findById(),findAll(),deleteById(), etc.- Generics: The
JpaRepositoryinterface takes two parameters: the entity type (Department) and the type of its primary key (Long).
Create Service Layer
Create EmployeeService Interface
-
Create a New Package:
- In the
src/main/java/com/example/employeemanagementdirectory, create a new package namedservice.
- In the
-
Create the
EmployeeServiceInterface:- Inside the
servicepackage, create a new interface namedEmployeeService. - Add the following code to the
EmployeeServiceinterface:
- Inside the
package com.example.employeemanagement.service;
import com.example.employeemanagement.model.Employee;
import java.util.List;
public interface EmployeeService {
Employee saveEmployee(Employee employee);
Employee getEmployeeById(Long id);
List<Employee> getAllEmployees();
Employee updateEmployee(Long id, Employee employeeDetails);
void deleteEmployee(Long id);
}
Explanation
- Service Interface: Defines the contract for the service layer. It includes methods for saving, retrieving, updating, and deleting employees.
Create EmployeeServiceImpl Class
- Create the
EmployeeServiceImplClass:- Inside the
servicepackage, create a new class namedEmployeeServiceImpl. - Add the following code to the
EmployeeServiceImplclass:
- Inside the
package com.example.employeemanagement.service;
import com.example.employeemanagement.model.Employee;
import com.example.employeemanagement.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeRepository employeeRepository;
@Override
public Employee saveEmployee(Employee employee) {
return employeeRepository.save(employee);
}
@Override
public Employee getEmployeeById(Long id) {
return employeeRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Employee not found with id: " + id));
}
@Override
public List<Employee> getAllEmployees() {
return employeeRepository.findAll();
}
@Override
public Employee updateEmployee(Long id, Employee employeeDetails) {
Employee employee = employeeRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Employee not found with id: " + id));
employee.setFirstName(employeeDetails.getFirstName());
employee.setLastName(employeeDetails.getLastName());
employee.setEmail(employeeDetails.getEmail());
employee.setDepartment(employeeDetails.getDepartment());
return employeeRepository.save(employee);
}
@Override
public void deleteEmployee(Long id) {
Employee employee = employeeRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Employee not found with id: " + id));
employeeRepository.delete(employee);
}
}
Explanation
@Service: Indicates that this class is a service component in the Spring context.EmployeeRepository: TheEmployeeRepositoryinstance is injected into the service class to interact with the database.- Exception Handling: The
getEmployeeById,updateEmployee, anddeleteEmployeemethods throw aRuntimeExceptionif the employee is not found.
Create DepartmentService Interface
- Create the
DepartmentServiceInterface:- Inside the
servicepackage, create a new interface namedDepartmentService. - Add the following code to the
DepartmentServiceinterface:
- Inside the
package com.example.employeemanagement.service;
import com.example.employeemanagement.model.Department;
import java.util.List;
public interface DepartmentService {
Department saveDepartment(Department department);
Department getDepartmentById(Long id);
List<Department> getAllDepartments();
Department updateDepartment(Long id, Department departmentDetails);
void deleteDepartment(Long id);
}
Explanation
- Service Interface: Defines the contract for the service layer. It includes methods for saving, retrieving, updating, and deleting departments.
Create DepartmentServiceImpl Class
- Create the
DepartmentServiceImplClass:- Inside the
servicepackage, create a new class namedDepartmentServiceImpl. - Add the following code to the
DepartmentServiceImplclass:
- Inside the
package com.example.employeemanagement.service;
import com.example.employeemanagement.model.Department;
import com.example.employeemanagement.repository.DepartmentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DepartmentServiceImpl implements DepartmentService {
@Autowired
private DepartmentRepository departmentRepository;
@Override
public Department saveDepartment(Department department) {
return departmentRepository.save(department);
}
@Override
public Department getDepartmentById(Long id) {
return departmentRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Department not found with id: " + id));
}
@Override
public List<Department> getAllDepartments() {
return departmentRepository.findAll();
}
@Override
public Department updateDepartment(Long id, Department departmentDetails) {
Department department = departmentRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Department not found with id: " + id));
department.setName(departmentDetails.getName());
department.setEmployees(departmentDetails.getEmployees());
return departmentRepository.save(department);
}
@Override
public void deleteDepartment(Long id) {
Department department = departmentRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Department not found with id: " + id));
departmentRepository.delete(department);
}
}
Explanation
@Service: Indicates that this class is a service component in the Spring context.DepartmentRepository: TheDepartmentRepositoryinstance is injected into the service class to interact with the database.- Exception Handling: The
getDepartmentById,updateDepartment, anddeleteDepartmentmethods throw aRuntimeExceptionif the department is not found.
Create EmployeeController
Create the EmployeeController Class
-
Create a New Package:
- In the
src/main/java/com/example/employeemanagementdirectory, create a new package namedcontroller.
- In the
-
Create the
EmployeeControllerClass:- Inside the
controllerpackage, create a new class namedEmployeeController. - Add the following code to the
EmployeeControllerclass:
- Inside the
package com.example.employeemanagement.controller;
import com.example.employeemanagement.model.Employee;
import com.example.employeemanagement.service.EmployeeService;
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/employees")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@PostMapping
public ResponseEntity<Employee> saveEmployee(@RequestBody Employee employee) {
Employee savedEmployee = employeeService.saveEmployee(employee);
return new ResponseEntity<>(savedEmployee, HttpStatus.CREATED);
}
@GetMapping("/{id}")
public ResponseEntity<Employee> getEmployeeById(@PathVariable Long id) {
Employee employee = employeeService.getEmployeeById(id);
return new ResponseEntity<>(employee, HttpStatus.OK);
}
@GetMapping
public ResponseEntity<List<Employee>> getAllEmployees() {
List<Employee> employees = employeeService.getAllEmployees();
return new ResponseEntity<>(employees, HttpStatus.OK);
}
@PutMapping("/{id}")
public ResponseEntity<Employee> updateEmployee(@PathVariable Long id, @RequestBody Employee employeeDetails) {
Employee updatedEmployee = employeeService.updateEmployee(id, employeeDetails);
return new ResponseEntity<>(updatedEmployee, HttpStatus.OK);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteEmployee(@PathVariable Long id) {
employeeService.deleteEmployee(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}
Explanation
@RestController: Indicates that this class is a REST controller.@RequestMapping("/api/employees"): Maps HTTP requests to/api/employeesto methods in this controller.@PostMapping: Handles HTTP POST requests to save an employee.@GetMapping("/{id}"): Handles HTTP GET requests to retrieve an employee by ID.@GetMapping: Handles HTTP GET requests to retrieve all employees.@PutMapping("/{id}"): Handles HTTP PUT requests to update an employee’s details.@DeleteMapping("/{id}"): Handles HTTP DELETE requests to delete an employee by ID.
Create DepartmentController
Create the DepartmentController Class
- Create the
DepartmentControllerClass:- Inside the
controllerpackage, create a new class namedDepartmentController. - Add the following code to the
DepartmentControllerclass:
- Inside the
package com.example.employeemanagement.controller;
import com.example.employeemanagement
.model.Department;
import com.example.employeemanagement.service.DepartmentService;
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/departments")
public class DepartmentController {
@Autowired
private DepartmentService departmentService;
@PostMapping
public ResponseEntity<Department> saveDepartment(@RequestBody Department department) {
Department savedDepartment = departmentService.saveDepartment(department);
return new ResponseEntity<>(savedDepartment, HttpStatus.CREATED);
}
@GetMapping("/{id}")
public ResponseEntity<Department> getDepartmentById(@PathVariable Long id) {
Department department = departmentService.getDepartmentById(id);
return new ResponseEntity<>(department, HttpStatus.OK);
}
@GetMapping
public ResponseEntity<List<Department>> getAllDepartments() {
List<Department> departments = departmentService.getAllDepartments();
return new ResponseEntity<>(departments, HttpStatus.OK);
}
@PutMapping("/{id}")
public ResponseEntity<Department> updateDepartment(@PathVariable Long id, @RequestBody Department departmentDetails) {
Department updatedDepartment = departmentService.updateDepartment(id, departmentDetails);
return new ResponseEntity<>(updatedDepartment, HttpStatus.OK);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteDepartment(@PathVariable Long id) {
departmentService.deleteDepartment(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}
Explanation
@RestController: Indicates that this class is a REST controller.@RequestMapping("/api/departments"): Maps HTTP requests to/api/departmentsto methods in this controller.@PostMapping: Handles HTTP POST requests to save a department.@GetMapping("/{id}"): Handles HTTP GET requests to retrieve a department by ID.@GetMapping: Handles HTTP GET requests to retrieve all departments.@PutMapping("/{id}"): Handles HTTP PUT requests to update a department’s details.@DeleteMapping("/{id}"): Handles HTTP DELETE requests to delete a department by ID.
Test the Application
Run the Application
- Run the Application:
- In IntelliJ IDEA, run the
EmployeeManagementApplicationclass.
- In IntelliJ IDEA, run the
Access the Application
-
Open Web Browser:
- Open a web browser and go to
http://localhost:8080/api/employeesto manage employees. - Open a web browser and go to
http://localhost:8080/api/departmentsto manage departments.
- Open a web browser and go to
-
Verify the Application:
- Verify that you can perform CRUD operations on employees and departments, ensuring that the one-to-many relationship is correctly configured and functioning.
Conclusion
In this chapter, we built an Employee Management System project using Spring Boot with a one-to-many relationship between Employee and Department 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-many relationships in a Spring Boot application.