Spring Boot DAO Example - Data Access Object Pattern

In this tutorial, we will create a Spring Boot application that uses a DAO (Data Access Object) pattern. We perform CRUD operations with the MySQL database using the DAO pattern in the Spring boot project.

We will use the latest Spring Boot 3, Spring Data JPA (Hibernate), and MySQL 8+ Database.

DAO (Data Access Object) Pattern Overview

The DAO (Data Access Object) pattern is a design pattern that separates the data access logic from the business logic in an application. It provides a structured way to interact with a data storage system, such as a database, while abstracting the underlying implementation details. 

The main purpose of the DAO pattern is to create a dedicated layer that handles all the interactions with the data storage system. This layer encapsulates the low-level operations required to perform CRUD (Create, Read, Update, Delete) operations on data entities, hiding the complexity of the data access logic from the rest of the application. 

By using the DAO pattern, you can achieve separation of concerns and improve modularity and maintainability in your application.

The DAO pattern typically consists of the following components: 

  • Entity: Represents the data model or domain object that is persisted in the data storage system. 
  • DAO Interface: Defines the contract or interface that specifies the operations to be performed on the entity.
  • DAO Implementation: Provides the actual implementation of the DAO interface, handling the low-level data access operations. 
  • Service Layer: Acts as an intermediary between the DAO layer and the business logic components, coordinating the interactions between them.

Using DAO in Spring Boot Application

In Spring Boot, we can leverage Spring Data JPA, which provides a convenient way to implement the DAO pattern. Spring Data JPA automatically generates the implementation of the DAO interface based on conventions and provides a wide range of database operations out of the box, reducing the need for boilerplate code. 

Overall, the DAO pattern in Spring Boot enables you to abstract away the complexities of data access and focus on writing business logic in a clean and maintainable manner.

1. Create and Set up Spring Boot Project

First, let's start by setting up the project and adding the required dependencies. You can create a new Spring Boot project using your preferred IDE or build tools like Maven or Gradle. 

Make sure to include the following dependencies in your pom.xml:
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>com.mysql</groupId>
			<artifactId>mysql-connector-j</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

Next, let's create the necessary components for the DAO pattern

2. Configure MySQL Database

Here are the configuration properties used in a Spring Boot application to configure the database connection and Hibernate settings for a MySQL database.

spring.datasource.url=jdbc:mysql://localhost:3306/ems
spring.datasource.username=root
spring.datasource.password=Mysql@123

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update
  • spring.datasource.url: Specifies the JDBC URL for the MySQL database. 
  • spring.datasource.username: Sets the username for the database connection. 
  • spring.datasource.password: Sets the password for the database connection. 
  • spring.jpa.properties.hibernate.dialect: Specifies the Hibernate dialect to use for MySQL. It is set to org.hibernate.dialect.MySQLDialect, which is the dialect for MySQL databases.
  • spring.jpa.hibernate.ddl-auto: Determines how Hibernate handles the database schema creation and migration. In this case, it is set to update, which means Hibernate will automatically create or update the database schema based on the entity classes and the current schema state.

3. Department JPA Entity

Create a Department class representing the Department entity with an id, departmentName, and departmentDescription fields. Add appropriate getters and setters.

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "departments")
public class Department {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "department_name")
    private String departmentName;

    @Column(name = "department_description")
    private String departmentDescription;
}

4. DepartmentRepository

Create a DepartmentRepository interface that extends JpaRepository to perform CRUD operations on the Department entity.

import net.javaguides.ems.entity.Department;
import org.springframework.data.jpa.repository.JpaRepository;

public interface DepartmentRepository extends JpaRepository<Department, Long> {
}

Note that we are leveraging Spring Data JPA to implement the DAO pattern. Spring Data JPA automatically generates the implementation of the DAO interface based on conventions and provides a wide range of database operations out of the box, reducing the need for boilerplate code.

DAO pattern in Spring Boot enables you to abstract away the complexities of data access and focus on writing business logic in a clean and maintainable manner.

5. Create DTO, Mapper, and ResourceNotFoundException Classes

Let's create DTO (Data Transfer Object) to transfer data between the client and server.

DepartmentDto

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class DepartmentDto {
    private Long id;
    private String departmentName;
    private String departmentDescription;
}

DepartmentMapper

Let's create DepartmentMapper class to map the Department entity to DepartmentDto and vice versa.

import net.javaguides.ems.dto.DepartmentDto;
import net.javaguides.ems.entity.Department;

public class DepartmentMapper {

    // convert department jpa entity into department dto
    public static DepartmentDto mapToDepartmentDto(Department department){
        return new DepartmentDto(
                department.getId(),
                department.getDepartmentName(),
                department.getDepartmentDescription()
        );
    }

    // convert department dto into department jpa entity
    public static Department mapToDepartment(DepartmentDto departmentDto){
        return new Department(
                departmentDto.getId(),
                departmentDto.getDepartmentName(),
                departmentDto.getDepartmentDescription()
        );
    }
}

ResourceNotFoundException

Let's create a custom exception to handle the resource not found use-case.
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException{

    public ResourceNotFoundException(String message){
        super(message);
    }
}

6. Service Layer

Let's create a DepartmentService interface with the following CRUD methods:

DepartmentService

import net.javaguides.ems.dto.DepartmentDto;

import java.util.List;

public interface DepartmentService {
    DepartmentDto createDepartment(DepartmentDto departmentDto);

    DepartmentDto getDepartmentById(Long departmentId);

    List<DepartmentDto> getAllDepartments();

    DepartmentDto updateDepartment(Long departmentId, DepartmentDto updatedDepartment);

    void deleteDepartment(Long departmentId);
}

DepartmentServiceImpl

Let's create DepartmentServiceImpl class that acts as an intermediary between the controller and the repository. It encapsulates business logic and provides methods to perform operations in departments.
import lombok.AllArgsConstructor;
import net.javaguides.ems.dto.DepartmentDto;
import net.javaguides.ems.entity.Department;
import net.javaguides.ems.exception.ResourceNotFoundException;
import net.javaguides.ems.mapper.DepartmentMapper;
import net.javaguides.ems.repository.DepartmentRepository;
import net.javaguides.ems.service.DepartmentService;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class DepartmentServiceImpl implements DepartmentService {

    private DepartmentRepository departmentRepository;

    @Override
    public DepartmentDto createDepartment(DepartmentDto departmentDto) {
        Department department = DepartmentMapper.mapToDepartment(departmentDto);
        Department savedDepartment = departmentRepository.save(department);
        return DepartmentMapper.mapToDepartmentDto(savedDepartment);
    }

    @Override
    public DepartmentDto getDepartmentById(Long departmentId) {
        Department department = departmentRepository.findById(departmentId).orElseThrow(
                () -> new ResourceNotFoundException("Department is not exists with a given id: " + departmentId)
        );
        return DepartmentMapper.mapToDepartmentDto(department);
    }

    @Override
    public List<DepartmentDto> getAllDepartments() {
        List<Department> departments = departmentRepository.findAll();
        return departments.stream().map((department) -> DepartmentMapper.mapToDepartmentDto(department))
                .collect(Collectors.toList());
    }

    @Override
    public DepartmentDto updateDepartment(Long departmentId, DepartmentDto updatedDepartment) {

        Department department = departmentRepository.findById(departmentId).orElseThrow(
                () -> new ResourceNotFoundException("Department is not exists with a given id:"+ departmentId)
        );

        department.setDepartmentName(updatedDepartment.getDepartmentName());
        department.setDepartmentDescription(updatedDepartment.getDepartmentDescription());

        Department savedDepartment = departmentRepository.save(department);

        return DepartmentMapper.mapToDepartmentDto(savedDepartment);
    }

    @Override
    public void deleteDepartment(Long departmentId) {
        departmentRepository.findById(departmentId).orElseThrow(
                () -> new ResourceNotFoundException("Department is not exists with a given id: " + departmentId)
        );

        departmentRepository.deleteById(departmentId);
    }
}

7. DepartmentController

Let's create a DepartmentController class that handles HTTP requests and delegates calls to the DepartmentServiceImpl class.

import lombok.AllArgsConstructor;
import net.javaguides.ems.dto.DepartmentDto;
import net.javaguides.ems.service.DepartmentService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@CrossOrigin("*")
@AllArgsConstructor
@RestController
@RequestMapping("/api/departments")
public class DepartmentController {

    private DepartmentService departmentService;

    // Build Create or Add Department REST API
    @PostMapping
    public ResponseEntity<DepartmentDto> createDepartment(@RequestBody DepartmentDto departmentDto){
        DepartmentDto department = departmentService.createDepartment(departmentDto);
        return new ResponseEntity<>(department, HttpStatus.CREATED);
    }

    // Build Get Department REST API
    @GetMapping("{id}")
    public ResponseEntity<DepartmentDto> getDepartmentById(@PathVariable("id") Long departmentId){
        DepartmentDto departmentDto = departmentService.getDepartmentById(departmentId);
        return ResponseEntity.ok(departmentDto);
    }

    // Build Get All Departments REST API
    @GetMapping
    public ResponseEntity<List<DepartmentDto>> getAllDepartments(){
        List<DepartmentDto> departments = departmentService.getAllDepartments();
        return ResponseEntity.ok(departments);
    }

    // Build Update Department REST API
    @PutMapping("{id}")
    public ResponseEntity<DepartmentDto> updateDepartment(@PathVariable("id") Long departmentId,
                                                          @RequestBody DepartmentDto updatedDepartment){
        DepartmentDto departmentDto = departmentService.updateDepartment(departmentId, updatedDepartment);
        return ResponseEntity.ok(departmentDto);
    }

    // Build Delete Department REST API
    @DeleteMapping("{id}")
    public ResponseEntity<String> deleteDepartment(@PathVariable("id") Long departmentId){
        departmentService.deleteDepartment(departmentId);
        return ResponseEntity.ok("Department deleted successfully!.");
    }

}

8. Test CRUD REST APIs using Postman Client

Add Department REST API:

Get Department REST API:

Get All Departments REST API:
Update Department REST API:
Delete Department REST API:

Conclusion

In this tutorial, we created a Spring Boot application that uses a DAO (Data Access Object) pattern. Basically, we performed CRUD operations with the MySQL database using the DAO pattern in the Spring boot project.

Comments