今天在系统开发中忘记dto应该放在哪个目录下,所以查了下相关知识并记录。
1.DTO(Data Transfer Object)—— 数据传输对象
核心作用
- 数据封装:在前后端或系统模块之间传递结构化的数据(例如接口的请求参数、响应结果)。
- 解耦分层:避免直接暴露数据库实体(如 Entity 类)给外部接口,降低安全风险。
- 字段控制:选择性暴露或隐藏字段(如去除敏感信息、合并多个字段)。
常见场景
- 请求接收:Controller 层接收
Request DTO
(如注册请求的RegisterRequest
)。 - 响应返回:Controller 层返回
Response DTO
(如查询用户信息的UserProfileResponse
)。 - 服务间通信:微服务接口之间通过 DTO 交换数据。
代码示例:
// Request DTO(定义前端传入的数据结构)
public class RegisterRequest {
private String username;
private String password;
private String email;
}
// Response DTO(定义返回给前端的数据结构)
public class UserResponse {
private Long id;
private String username;
private String email;
}
2.Mapper(对象转换工具)
核心作用
- 对象转换:将一种类型的对象转换为另一种类型的对象(如
DTO → Entity
或Entity → DTO
)。 - 逻辑解耦:分离数据转换逻辑与业务逻辑,提高代码维护性。
实现方式
- 手动编写转换代码:直接通过
new
对象或Builder
方式逐个字段赋值。 - 工具自动转换:使用 MapStruct、ModelMapper、Dozer 等库简化转换过程。
常见场景
- Controller ↔ Service 层:将
DTO
转换为Entity
交给 Service 处理。 - Service ↔ Repository 层:将
Entity
转换为VO(View Object)
返回给前端。 - 不同模块交互:异构系统间的数据格式转换(如 JSON → XML)。
手动转换代码示例:
// UserMapper.java
public class UserMapper {
public static User convertToEntity(RegisterRequest dto) {
User user = new User();
user.setUsername(dto.getUsername());
user.setPassword(dto.getPassword());
user.setEmail(dto.getEmail());
return user;
}
public static UserResponse convertToResponse(User entity) {
return UserResponse.builder()
.id(entity.getId())
.username(entity.getUsername())
.email(entity.getEmail())
.build();
}
}
流程图:
3.主要区别总结:
4.使用场景
必须使用 DTO 的场景
- 接口需要接收或返回特定字段的组合(如隐藏敏感字段)。
- 要求定义明确的接口契约(即 API 文档化时需要稳定清晰的参数和响应结构)。
必须使用 Mapper 的场景
- 数据库实体(Entity)与接口层数据(DTO)结构不一致时。
- 多个字段需要映射,且转换逻辑重复且繁琐时。