在本教程中,我们将学习如何在Spring Boot 应用程序中创建 DTO(数据传输对象)类,以及如何使用 ModelMapper 库将实体转换为 DTO,反之亦然。
数据传输对象设计模式是一种常用的设计模式。它基本上用于一次性将具有多个属性的数据从客户端传递到服务器,以避免多次调用远程服务器。
在用Java编写的RESTful API上使用DTO(以及在Spring Boot上)的另一个优点是,它们可以帮助隐藏域对象(JPA实体)的实现细节。如果我们不仔细处理可以通过哪些操作更改哪些属性,则通过终结点公开实体可能会成为安全问题。
让我们从介绍ModelMapper Java库开始,我们将使用它来将实体转换为DTO,反之亦然。
模型映射器库
ModelMapper 旨在通过根据约定自动确定一个对象模型如何映射到另一个对象模型,使对象映射变得容易,就像人类一样,同时提供一个简单的、重构安全的 API 来处理特定的用例。
在ModelMapper - Simple, Intelligent, Object Mapping. 阅读有关模型映射器库的更多信息。
我们将在pom中需要这种依赖.xml:
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.5</version>
</dependency>
第 1 步:将模型映射器库添加到 Pom.xml
我们将在pom中需要这种依赖.xml:
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.5</version>
</dependency>
步骤 2:定义 JPA 实体 - Post.java
让我们创建一个Post实体类并向其添加以下内容:
package net.javaguides.springboot.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;
}
步骤 3:定义 DTO 类 - PostDto.java
让我们创建PostDto类并向其添加以下内容:
package net.javaguides.springboot.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;
}
仅包含客户端所需的 DTO 类中的那些详细信息。实体和 DTO 字段看起来相同,但您将向客户端添加所需的字段。
步骤 4:存储库层
让我们创建一个PostRepository来与Post实体的数据库进行通信:
package com.springboot.blog.repository;
import com.springboot.blog.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PostRepository extends JpaRepository<Post, Long> {
}
第 5 步:服务层
在服务层中,我们将只使用Post实体,而不使用PostDto类:
PostService 接口
package net.javaguides.springboot.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);
}
PostServiceImpl Class
package net.javaguides.springboot.service.impl;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Service;
import net.javaguides.springboot.exception.ResourceNotFoundException;
import net.javaguides.springboot.model.Post;
import net.javaguides.springboot.repository.PostResository;
import net.javaguides.springboot.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;
}
}
请注意,我们不是在服务层中使用实体到 DTO,反之亦然。
步骤 6:将 ModelMapper 类配置为 Spring Bean
让我们将ModelMapper类配置为 Spring bean,以便我们可以将其注入到控制器类中:
package net.javaguides.springboot;
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);
}
}
步骤 7:控制器层
在下面的PostController类中,我们注入了ModelMapper类,并在不同的REST API中将其用于实体到DTO的转换,反之亦然:
package net.javaguides.springboot.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 net.javaguides.springboot.model.Post;
import net.javaguides.springboot.payload.ApiResponse;
import net.javaguides.springboot.payload.PostDto;
import net.javaguides.springboot.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);
}
}
我们在createPost()方法中使用ModelMapper将实体转换为DTO,反之亦然:
@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);
}
我们在更新Post() 方法中使用 ModelMapper 将实体转换为 DTO,反之亦然:
// 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);
}
我们在 getPostById() 方法中使用 ModelMapper 将实体转换为 DTO,反之亦然:
@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);
}
我们在getAllPosts()方法中使用ModelMapper将实体转换为DTO,反之亦然:
@GetMapping
public List<PostDto> getAllPosts() {
return postService.getAllPosts().stream().map(post -> modelMapper.map(post, PostDto.class))
.collect(Collectors.toList());
}
结论
本教程演示了如何在 Spring 引导 REST API 项目中执行从实体到 DTO 以及从 DTO 到实体的转换。我们使用了模型映射器库,而不是手动编写这些转换。
引用
- ModelMapper - Simple, Intelligent, Object Mapping.
- ModelMapper 3.0.1-SNAPSHOT API
版权归原作者 allway2 所有, 如有侵权,请联系我们删除。