1. 核心概念对比
| 维度 | DTO(Data Transfer Object) | 实体类(Entity) |
|---|---|---|
| 定义 | 用于在不同层或系统之间传输数据的载体 | 表示业务领域中的概念或数据库中的表结构 |
| 关注点 | 数据的传输格式和展示需求 | 业务逻辑和数据持久化 |
| 生命周期 | 请求处理过程中临时存在 | 长期存在于业务逻辑和数据库中 |
| 关系 | 通常由实体类转换而来,可能包含多个实体的部分数据 |
通常对应数据库中的一张表,与数据库记录一一对应 |
2. 设计目的差异
DTO 的核心目的
- 隔离内部结构:避免向外部暴露实体类的敏感字段(如密码、内部 ID)。
- 适配外部需求:根据前端或第三方系统的需要定制数据格式(如日期格式化、字段重命名)。
- 简化传输:只包含必要的数据,减少网络传输或缓存的开销。
示例:
用户实体包含密码字段,但 DTO 中排除该字段:
// 实体类
public class User {
private Long id;
private String username;
private String password; // 敏感字段
private LocalDateTime createTime;
}
// DTO
public class UserDTO {
private String username;
private String createTimeStr; // 格式化后的日期字符串
}
实体类的核心目的
- 数据持久化:通过 ORM(如 Hibernate、MyBatis)与数据库表映射。
- 业务逻辑封装:包含与实体相关的业务方法(如
calculateTotalPrice())。 - 保持数据完整性:通过实体类的约束(如
@NotNull、@Unique)确保数据一致性。
3. 技术特征对比
| 特征 | DTO | 实体类 |
|---|---|---|
| 字段 | 按需定义,可能与实体类字段不完全匹配 | 通常与数据库表字段一一对应 |
| 注解 | 常用校验注解(如@NotNull、@Size) | 常用 ORM 注解(如@Entity、@Column) |
| 方法 | 只有 getter/setter,可能有少量数据处理方法 | 可能包含业务方法(如状态转换、计算逻辑) |
| 层次 | 主要用于表示层(如 Controller)和服务层之间 | 主要用于数据访问层(DAO/Repository)和服务层 |
| 示例场景 | REST API 返回值、微服务间数据传递 | 数据库查询、插入操作 |
4. 使用场景对比
| 场景 | DTO | 实体类 |
|---|---|---|
| 前端数据展示 | 返回给前端的 JSON 数据结构 | 不直接对外暴露 |
| 敏感信息过滤 | 排除密码、身份证号等敏感字段 | 包含完整数据 |
| 复杂数据结构 | 组合多个实体的数据(如订单详情) | 单表数据操作 |
| 缓存数据 | 序列化为 JSON 存储在 Redis 中 | 通常不直接缓存(需额外处理) |
| 批量数据导入 / 导出 | 封装导入导出的数据 | 用于数据库操作 |
5. 转换关系
- 实体类 → DTO:通过转换工具(如 MapStruct、ModelMapper)或手动转换,从实体类提取部分数据。
- DTO → 实体类:在创建或更新业务对象时,将 DTO 数据映射到实体类。
示例流程:
- Controller 接收
UserDTO参数。 - Service 将
UserDTO转换为User实体。 - Repository 将
User实体保存到数据库。 - 查询时,Repository 返回
User实体,Service 转换为UserDTO返回给前端。
6. 最佳实践建议
- 明确职责:DTO 专注数据传输,实体类专注业务和持久化。
- 避免混用:不要让 DTO 承担业务逻辑,也不要用实体类直接对外提供数据。
- 使用工具转换:复杂场景下推荐使用 MapStruct 自动生成转换代码。
- 命名区分:DTO 使用
XXXDTO后缀,实体类使用业务名称(如User、Order)。 - 校验分离:在 DTO 中添加校验注解,实体类专注数据库约束。
总结
DTO 和实体类的分离是关注点分离原则的体现:
- DTO:解决数据传输和展示的问题,适配外部需求。
- 实体类:解决业务逻辑和数据持久化的问题,维护领域模型的完整性。
合理使用两者可以提高系统的可维护性、安全性和灵活性。
1142

被折叠的 条评论
为什么被折叠?



