Spring Boot DTO Example – Convert từ Entity sang DTO
NỘI DUNG BÀI VIẾT
Trong bài hướng dẫn này, chúng ta sẽ học cách tạo 1 DTOs (Data Transfer Objects) class trong Spring Boot application và cách convert từ Entity sang DTO và ngược lại bằng thư viên ModelMapper.
Data Transfer Object Design Pattern là một design pattern được sử dụng thường xuyên. Về cơ bản thì nó được dùng để truyền data có nhiều attributes trong một lần truyền từ client đến server để tránh được nhiều request đến server.
Một lợi thế khác từ việc sử dụng DTO trên API RESTful được viết bằng Java (và trên Spring Boot), là có thể ẩn đi chi tiết các implementation của Object (JPA entity).
Việc để lộ các entity thông qua các điểm cuối có thể trở thành một vấn đề bảo mật. Nếu chúng ta không xử lý cẩn thận những thuộc tính thì có thể bị thay đổi bằng bất kỳ thao tác nào.
Hãy cùng bắt đầu với việc include thư viện ModelMapper, cái mà chúng ta sẽ sử dụng để convert từ Entity sang DTO và ngược lại.
ModelMapper Library
Mục tiêu của ModelMapper là làm cho việc mapping object đơn giản hơn. Bằng cách tự động define cách một object model map tới một object khác.
Đọc thêm về thư viện model mapper tại http://modelmapper.org/.
Thêm thư viện của ModelMapper vào pom.xml:
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.5</version>
</dependency>
Code language: HTML, XML (xml)
Step 1: Thêm ModelMapper Library vào pom.xml
Thêm thư viện của ModelMapper vào pom.xml:
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.5</version>
</dependency>
Code language: HTML, XML (xml)
Step 2: Define JPA Entity – Post.java
package com.hdd.model;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "posts", uniqueConstraints = {@UniqueConstraint(columnNames = {"title"})})
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "title")
private String title;
@Column(name = "description")
private String description;
@Column(name = "content")
private String content;
}
Code language: JavaScript (javascript)
Step 3: Define DTO Class – PostDto.java
Hãy tạo class PostDto như sau:
package com.hdd.payload;
import java.util.HashSet;
import java.util.Set;
import lombok.Data;
@Data
public class PostDto {
private long id;
private String title;
private String description;
private String content;
}
Code language: CSS (css)
Step 4: Service
PostService interface:
package com.hdd.service;
import java.util.List;
import net.javaguides.springboot.model.Post;
public interface PostService {
List<Post> getAllPosts();
Post createPost(Post post);
Post updatePost(long id, Post post);
void deletePost(long id);
Post getPostById(long id);
}
Code language: PHP (php)
PostServiceImpl Class:
package com.hdd.service.impl;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Service;
import com.hdd.exception.ResourceNotFoundException;
import com.hdd.model.Post;
import com.hdd.repository.PostResository;
import com.hdd.service.PostService;
@Service
public class PostServiceImpl implements PostService{
private final PostResository postRepository;
public PostServiceImpl(PostResository postRepository) {
super();
this.postRepository = postRepository;
}
@Override
public List<Post> getAllPosts() {
return postRepository.findAll();
}
@Override
public Post createPost(Post post) {
return postRepository.save(post);
}
@Override
public Post updatePost(long id, Post postRequest) {
Post post = postRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Post", "id", id));
post.setTitle(postRequest.getTitle());
post.setDescription(postRequest.getDescription());
post.setContent(postRequest.getContent());
return postRepository.save(post);
}
@Override
public void deletePost(long id) {
Post post = postRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Post", "id", id));
postRepository.delete(post);
}
@Override
public Post getPostById(long id) {
Optional<Post> result = postRepository.findById(id);
if(result.isPresent()) {
return result.get();
}else {
throw new ResourceNotFoundException("Post", "id", id);
}
// Post post = postRepository.findById(id)
// .orElseThrow(() -> new ResourceNotFoundException("Post", "id", id));
//return post;
}
}
Code language: PHP (php)
Step 5: Configure ModelMapper Class a Spring Bean
Hãy cấu hình ModelMapper như là một Spring Bean để chúng ta có thể inject vào controller:
package com.hdd;
import org.modelmapper.ModelMapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class SpringbootBlogApiApplication {
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
public static void main(String[] args) {
SpringApplication.run(SpringbootBlogApiApplication.class, args);
}
}
Code language: JavaScript (javascript)
Step 6: Controller Class
Trong Controller PostController, tôi đã inject ModelMapper và sử dụng các REST API khác nhau để convert từ Entity sang DTO và ngược lại:
package com.hdd.contoller;
import java.util.List;
import java.util.stream.Collectors;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.hdd.model.Post;
import com.hdd.payload.ApiResponse;
import com.hdd.payload.PostDto;
import com.hdd.service.PostService;
@RestController
@RequestMapping("/api/posts")
public class PostController {
@Autowired
private ModelMapper modelMapper;
private PostService postService;
public PostController(PostService postService) {
super();
this.postService = postService;
}
@GetMapping
public List<PostDto> getAllPosts() {
return postService.getAllPosts().stream().map(post -> modelMapper.map(post, PostDto.class))
.collect(Collectors.toList());
}
@GetMapping("/{id}")
public ResponseEntity<PostDto> getPostById(@PathVariable(name = "id") Long id) {
Post post = postService.getPostById(id);
// convert entity to DTO
PostDto postResponse = modelMapper.map(post, PostDto.class);
return ResponseEntity.ok().body(postResponse);
}
@PostMapping
public ResponseEntity<PostDto> createPost(@RequestBody PostDto postDto) {
// convert DTO to entity
Post postRequest = modelMapper.map(postDto, Post.class);
Post post = postService.createPost(postRequest);
// convert entity to DTO
PostDto postResponse = modelMapper.map(post, PostDto.class);
return new ResponseEntity<PostDto>(postResponse, HttpStatus.CREATED);
}
// change the request for DTO
// change the response for DTO
@PutMapping("/{id}")
public ResponseEntity<PostDto> updatePost(@PathVariable long id, @RequestBody PostDto postDto) {
// convert DTO to Entity
Post postRequest = modelMapper.map(postDto, Post.class);
Post post = postService.updatePost(id, postRequest);
// entity to DTO
PostDto postResponse = modelMapper.map(post, PostDto.class);
return ResponseEntity.ok().body(postResponse);
}
@DeleteMapping("/{id}")
public ResponseEntity<ApiResponse> deletePost(@PathVariable(name = "id") Long id) {
postService.deletePost(id);
ApiResponse apiResponse = new ApiResponse(Boolean.TRUE, "Post deleted successfully", HttpStatus.OK);
return new ResponseEntity<ApiResponse>(apiResponse, HttpStatus.OK);
}
}
Code language: JavaScript (javascript)
createPost():
Tổng hợp 200+ tài liệu, sách, bài thực hành, video hướng dẫn lập trình… từ cơ bản đến nâng cao
@PostMapping
public ResponseEntity<PostDto> createPost(@RequestBody PostDto postDto) {
// convert DTO to entity
Post postRequest = modelMapper.map(postDto, Post.class);
Post post = postService.createPost(postRequest);
// convert entity to DTO
PostDto postResponse = modelMapper.map(post, PostDto.class);
return new ResponseEntity<PostDto>(postResponse, HttpStatus.CREATED);
}
Code language: JavaScript (javascript)
updatePost():
// change the request for DTO
// change the response for DTO
@PutMapping("/{id}")
public ResponseEntity<PostDto> updatePost(@PathVariable long id, @RequestBody PostDto postDto) {
// convert DTO to Entity
Post postRequest = modelMapper.map(postDto, Post.class);
Post post = postService.updatePost(id, postRequest);
// entity to DTO
PostDto postResponse = modelMapper.map(post, PostDto.class);
return ResponseEntity.ok().body(postResponse);
}
Code language: JavaScript (javascript)
getPostById():
@GetMapping("/{id}")
public ResponseEntity<PostDto> getPostById(@PathVariable(name = "id") Long id) {
Post post = postService.getPostById(id);
// convert entity to DTO
PostDto postResponse = modelMapper.map(post, PostDto.class);
return ResponseEntity.ok().body(postResponse);
}
Code language: JavaScript (javascript)
Còn đây là method getAllPosts():
@GetMapping
public List<PostDto> getAllPosts() {
return postService.getAllPosts().stream().map(post -> modelMapper.map(post, PostDto.class))
.collect(Collectors.toList());
}
Code language: CSS (css)
Tổng kết
Hướng dẫn này đã chứng minh rằng cách convert từ Entity sang DTO và từ DTO sang Entity trong một Spring Boot application. Tôi đã sử dụng thư viện ModelMapper thay vì viết các conversion này bằng tay.
Chúc bạn thành công 😂
Các bài viết liên quan:
Leave a Reply