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 toupdate
automatically 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/employeemanagement
directory, create a new package namedmodel
.
- In the
-
Create the
Employee
Class:- Inside the
model
package, create a new class namedEmployee
. - Add the following code to the
Employee
class:
- 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
Department
Class:- Inside the
model
package, create a new class namedDepartment
. - Add the following code to the
Department
class:
- 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.IDENTITY
indicates that the primary key is auto-incremented.@ManyToOne
: Specifies a many-to-one relationship between theEmployee
andDepartment
entities.@OneToMany
: Specifies a one-to-many relationship between theDepartment
andEmployee
entities.@CascadeType.ALL
: Specifies that all cascade types (persist, merge, remove, refresh, detach) should be applied.- Utility method:
addEmployee
is 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/employeemanagement
directory, create a new package namedrepository
.
- In the
-
Create the
EmployeeRepository
Interface:- Inside the
repository
package, create a new interface namedEmployeeRepository
. - Add the following code to the
EmployeeRepository
interface:
- 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
: TheEmployeeRepository
interface extendsJpaRepository
, providing CRUD operations for theEmployee
entity. TheJpaRepository
interface includes methods likesave()
,findById()
,findAll()
,deleteById()
, etc.- Generics: The
JpaRepository
interface takes two parameters: the entity type (Employee
) and the type of its primary key (Long
).
Create Department Repository
Create the DepartmentRepository
Interface
- Create the
DepartmentRepository
Interface:- Inside the
repository
package, create a new interface namedDepartmentRepository
. - Add the following code to the
DepartmentRepository
interface:
- 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
: TheDepartmentRepository
interface extendsJpaRepository
, providing CRUD operations for theDepartment
entity. TheJpaRepository
interface includes methods likesave()
,findById()
,findAll()
,deleteById()
, etc.- Generics: The
JpaRepository
interface 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/employeemanagement
directory, create a new package namedservice
.
- In the
-
Create the
EmployeeService
Interface:- Inside the
service
package, create a new interface namedEmployeeService
. - Add the following code to the
EmployeeService
interface:
- 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
EmployeeServiceImpl
Class:- Inside the
service
package, create a new class namedEmployeeServiceImpl
. - Add the following code to the
EmployeeServiceImpl
class:
- 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
: TheEmployeeRepository
instance is injected into the service class to interact with the database.- Exception Handling: The
getEmployeeById
,updateEmployee
, anddeleteEmployee
methods throw aRuntimeException
if the employee is not found.
Create DepartmentService Interface
- Create the
DepartmentService
Interface:- Inside the
service
package, create a new interface namedDepartmentService
. - Add the following code to the
DepartmentService
interface:
- 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
DepartmentServiceImpl
Class:- Inside the
service
package, create a new class namedDepartmentServiceImpl
. - Add the following code to the
DepartmentServiceImpl
class:
- 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
: TheDepartmentRepository
instance is injected into the service class to interact with the database.- Exception Handling: The
getDepartmentById
,updateDepartment
, anddeleteDepartment
methods throw aRuntimeException
if the department is not found.
Create EmployeeController
Create the EmployeeController
Class
-
Create a New Package:
- In the
src/main/java/com/example/employeemanagement
directory, create a new package namedcontroller
.
- In the
-
Create the
EmployeeController
Class:- Inside the
controller
package, create a new class namedEmployeeController
. - Add the following code to the
EmployeeController
class:
- 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/employees
to 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
DepartmentController
Class:- Inside the
controller
package, create a new class namedDepartmentController
. - Add the following code to the
DepartmentController
class:
- 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/departments
to 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
EmployeeManagementApplication
class.
- In IntelliJ IDEA, run the
Access the Application
-
Open Web Browser:
- Open a web browser and go to
http://localhost:8080/api/employees
to manage employees. - Open a web browser and go to
http://localhost:8080/api/departments
to 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.