MapStruct 对象转换工具【DDD 架构】

发布于:2025-03-04 ⋅ 阅读:(13) ⋅ 点赞:(0)

一、前言

上篇我们学习了 DDD 架构,从上到下依次是:用户接口层、应用层、领域层和基础层。
那么不同层的实体类是怎么定义的呢?
这些实体类之间又该如何互相转换?
请记住这两个问题。

本篇由你的栈☞
带你一探究竟。

二、对象模型

在软件开发中,DTO、BO、PO、VO 是常见的对象模型,用于在不同的层次和场景中传递和处理数据。

の......咳咳,实际上都是实体类,只是名字叫的花里胡哨,但是为了开发更规范,来?

1. DTO 数据传输对象

官方的回答(它的废话):用于在用户接口层传输数据的对象,避免直接暴露领域模型给外部,减少不必要的数据传输,只传递需要的字段。

说人话:在 Controller 用户接口层,将前端传过来的数据封装为DTO,对应的实体类的名字应为 XXXDTO。

public class UserDTO {
    private Long id;
    private String name;
    private String email;

    // Getters and Setters
}
@RestController
@RequestMapping("/users")
public class UserController {
    private UserService userService;

    // 接收前端传递的 DTO
    @PostMapping
    public ResponseEntity<String> createUser(@RequestBody UserDTO userDTO) {
        userService.createUser(userDTO);
        return ResponseEntity.ok("User created successfully");
    }
}

2. BO 业务对象

官方的回答(它的废话):封装了业务逻辑的对象,包含与业务相关的状态和行为。

说人话:在 应用层和领域层,将上一层传过来的数据封装为BO,对应的实体类的名字应为 XXXBO。

3. PO 持久化对象

官方的回答(它的废话):与数据库表直接映射的对象,字段与数据库表的列一一对应。

说人话:在DAO 基础层,将上一层传过来的数据封装为PO,对应的实体类的名字应为 XXXPO。

4. VO 值对象

官方的回答(它的废话):用于标识一个不可变的对象,一旦创建就不能修改,通常用于展示数据。

说人话:各层返回的数据都用 VO 包装,对应的实体类的名字应为 XXXVO。

@Service
public class UserService {
    // 模拟从数据库获取用户信息
    public UserVO getUserVO(Long userId) {
        // 假设从数据库查询到用户信息
        UserPO userPO = new UserPO(1L, "John Doe", "john.doe@example.com");

        // 将 PO 转换为 VO
        return new UserVO(userPO.getId(), userPO.getName(), userPO.getEmail());
    }
}
@RestController
@RequestMapping("/users")
public class UserController {
    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/{id}")
    public ResponseEntity<UserVO> getUser(@PathVariable Long id) {
        UserVO userVO = userService.getUserVO(id);
        return ResponseEntity.ok(userVO);
    }
}

三、MapStruct 对象转换

1. 工具介绍

在业务流程进行中,数据想要往下传递,首先得保证数据类型一致,那么不同的实体类之间就需要互相转换,如果不使用 MapStruct,我们的转换方法就是手动复制 DTO 数据到 BO,代码耦合度较高,且编码效率低。

MapStruct 是一个用于 Java Bean 映射的代码生成库。它通过注解自动生成对象转换代码,减少手动编写映射逻辑的工作量。

特点:
① 高效,生成的代码是原生的 Java 方法调用,性能接近手写代码;
② 类型安全,编译时生成代码,避免运行时错误;
③ 易用,通过简单的注解配置,即可实现复杂映射。

2. 代码演示

① 引入依赖

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version> <!-- 使用最新版本 -->
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.5.5.Final</version> <!-- 使用最新版本 -->
    <scope>provided</scope>
</dependency>

② 定义源对象和目标对象

//源对象
public class User {
    private Long id;
    private String name;
    private String email;

    // Getters and Setters
}
//目标对象
public class UserDTO {
    private Long id;
    private String name;
    private String email;

    // Getters and Setters
}

③ 定义映射接口

使用 @Mapper 注解定义一个映射接口,MapStruct 会自动生成实现类!

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface UserMapper {
    // 获取映射器实例
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    // 将 User 对象转换为 UserDTO 对象
    UserDTO toDTO(User user);

    // 将 UserDTO 对象转换为 User 对象
    User toEntity(UserDTO userDTO);
}

④ 使用映射器

public class Main {
    public static void main(String[] args) {
        // 创建 User 对象
        User user = new User();
        user.setId(1L);
        user.setName("John Doe");
        user.setEmail("john.doe@example.com");

        // 使用映射器将 User 转换为 UserDTO
        UserDTO userDTO = UserMapper.INSTANCE.toDTO(user);

        // 打印结果
        System.out.println(userDTO);
    }
}