In this tutorial, we will learn how to use DTO (Data Transfer Object) pattern in Spring Boot application.
Martin Fowler describes the Data Transfer Object in his famous book Patterns of Enterprise Application Architecture. There, the main idea of DTOs is to reduce the number of remote calls that are expensive.In Java applications - we use JPA entity classes to represent tables in a relational database. Without DTOs, we'd have to expose the entire entities to a remote interface. This causes a strong coupling between an API and a persistence model.
By using a DTO to transfer just the required information, we loosen the coupling between the API and our model, allowing us to more easily maintain and scale the service.
YouTube Video
Technologies used
- Java 11
- Spring Boot
- Spring Data JPA (Hibernate)
- H2 in-memory database
- Maven
- Lombok
- Eclipse STS IDE
1. Create Spring Boot Project
We’ll use Spring initializr web tool to bootstrap our application.
Go to http://start.spring.io
Select Java in the language section.
Enter Artifact as spring-dto-tutorial
Add Spring Web, Lombok, Spring Data JPA, and H2 dependencies.
Click Generate to generate and download the project.
Once the project is generated, unzip it and import it into your favorite IDE.
2. Maven Dependencies
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>net.javaguides</groupId>
<artifactId>springboot-dto-tutorial</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-dto-tutorial</name>
<description>Demo project for Spring Boot and DTO</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<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.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.modelmapper/modelmapper -->
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.4.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
3. Model Layer
User JPA Entity
package net.javaguides.springboot.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String email;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
private String password;
@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "location_id")
private Location location;
}
Location JPA Entity
package net.javaguides.springboot.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "locations")
public class Location {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String place;
private String description;
private double longitude;
private double latitude;
}
4. Repository Layer
UserRepository
package net.javaguides.springboot.repository;
import net.javaguides.springboot.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
LocationRepository
package net.javaguides.springboot.repository;
import net.javaguides.springboot.model.Location;
import org.springframework.data.jpa.repository.JpaRepository;
public interface LocationRepository extends JpaRepository<Location, Long> {
}
5. DTO Layer
UserLocationDTO
package net.javaguides.springboot.dto;
import lombok.Data;
@Data
public class UserLocationDTO {
private long userId;
private String email;
private String place;
private double longitude;
private double latitude;
}
6. Service Layer
UserService
package net.javaguides.springboot.service;
import net.javaguides.springboot.dto.UserLocationDTO;
import net.javaguides.springboot.model.User;
import net.javaguides.springboot.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List<UserLocationDTO> getAllUsersLocation(){
return userRepository.findAll()
.stream()
.map(this::convertEntityToDto)
.collect(Collectors.toList());
}
private UserLocationDTO convertEntityToDto(User user){
UserLocationDTO userLocationDTO = new UserLocationDTO();
userLocationDTO.setUserId(user.getId());
userLocationDTO.setEmail(user.getEmail());
userLocationDTO.setPlace(user.getLocation().getPlace());
userLocationDTO.setLongitude(user.getLocation().getLongitude());
userLocationDTO.setLatitude(user.getLocation().getLatitude());
return userLocationDTO;
}
}
7. Controller Layer
UserController
package net.javaguides.springboot.controller;
import net.javaguides.springboot.dto.UserLocationDTO;
import net.javaguides.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users-location")
public List<UserLocationDTO> getAllUsersLocation(){
return userService.getAllUsersLocation();
}
}
8. Insert Data in DB
package net.javaguides.springboot;
import net.javaguides.springboot.model.Location;
import net.javaguides.springboot.model.User;
import net.javaguides.springboot.repository.LocationRepository;
import net.javaguides.springboot.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class SpringbootDtoTutorialApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(SpringbootDtoTutorialApplication.class, args);
}
@Autowired
private UserRepository userRepository;
@Autowired
private LocationRepository locationRepository;
@Override
public void run(String... args) throws Exception {
Location location = new Location();
location.setPlace("Pune");
location.setDescription("Pune is great place to live");
location.setLongitude(40.5);
location.setLatitude(30.6);
locationRepository.save(location);
User user1 = new User();
user1.setFirstName("Ramesh");
user1.setLastName("Fadatare");
user1.setEmail("ramesh@gmail.com");
user1.setPassword("secret");
user1.setLocation(location);
userRepository.save(user1);
User user2 = new User();
user2.setFirstName("John");
user2.setLastName("Cena");
user2.setEmail("john@gmail.com");
user2.setPassword("secret");
user2.setLocation(location);
userRepository.save(user2);
}
}
9. Run and Test Spring boot application
Just go to the root directory of the application and type the following command to run it -
$ mvn spring-boot:run
The application will start at Spring Boot’s default tomcat port 8080.
Hit below URL in browser to get response of the REST API:
http://localhost:8080/users-location
Conclusion
Free Spring Boot Tutorial - 5 Hours Full Course
Watch this course on YouTube at Spring Boot Tutorial | Fee 5 Hours Full Course