在Spring Boot项目中,将Entity、DTO、VO放在POJO
子模块中是一种常见的分层设计,它们各自承担不同的职责,通过一个通俗的例子来解释它们的作用:
POJO(Plain Old Java Object)是指普通的、简单的Java对象,只有属性和对应的setter和getter方法,不依赖于任何特定的框架、接口或父类。它的核心思想是保持代码的简洁性和可移植性,避免与特定技术绑定。
Entity、DTO、VO 都属于 POJO,它们是具有特定用途的POJO。下面详细讲解。
1. Entity(实体)
-
作用 :直接对应数据库表,用于ORM框架(如Hibernate)操作数据库。
-
特点:字段与数据库表严格一致,可能包含关联关系(如外键)。
-
示例 :
假设有一个用户表user
,包含字段:id
、username
、password
、email
、create_time
。
对应的Entity类如下:java@Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username; private String password; private String email; private LocalDateTime createTime; // Getters and Setters }
2. DTO(Data Transfer Object,数据传输对象)
-
作用 :在层间传递数据,一般用于前端传给后端的Controller层的数据,屏蔽敏感字段,或适配不同场景的输入。
-
特点:字段可能与Entity不同,例如排除敏感信息(如密码),或组合多个Entity的字段。
-
示例 :
用户注册时,前端可能只需要提交username
、password
、email
,不需要id
和create_time
。
对应的DTO类如下:javapublic class UserDTO { private String username; private String password; private String email; // Getters and Setters }
或者
java
@Data
public class EmployeeDTO implements Serializable{
private Long id;
private String username.
private String name,
private String phone,
private String sex,
private String idNumber,
}
使用场景:
- 前端向后端发出请求,里面传递的数据 ,使用DTO数据格式封装。
- Controller接收到
UserDTO
后,将其转换为User
实体,再交给Service层保存到数据库。 - 避免了直接暴露Entity结构,提升安全性(例如密码加密后再存储)。
3. VO(View Object,视图对象)
-
作用 :返回给前端的展示数据,定制化字段,适配前端需求。
-
特点:字段可能与Entity差异较大,例如排除敏感信息、格式化时间、组合多个数据源的结果。
-
示例 :
查询用户信息时,前端需要id
、username
、email
和格式化后的createTime
,但不需要password
。
对应的VO类如下:javapublic class UserVO { private Long id; private String username; private String email; private String formattedCreateTime; // 例如:2024-01-01 12:00:00 // Getters and Setters }
使用场景 :
- Service层查询到
User
实体后,将其转换为UserVO
,再通过Controller返回给前端。 - 避免暴露数据库细节,提升接口灵活性。
- Service层查询到
总结:三者的协作流程
- 用户注册 :
- 前端提交
UserDTO
→ Controller接收 → Service层将UserDTO
转为User
实体 → 存入数据库。
- 前端提交
- 查询用户信息 :
- Service层查询
User
实体 → 转为UserVO
→ Controller返回UserVO
给前端。
- Service层查询
备注:主流规范的做法应该是Controller接收到前端的DTO后,在Controller层将DTO转为Entity,再交给Service处理。在一些简单项目(不严格分层时),也可能会由Service层进行转换,这也是通常的做法。
关键区别
类型 | 用途 | 字段特点 | 生命周期 |
---|---|---|---|
Entity | 直接操作数据库 | 与数据库表严格一致 | 持久化层(数据库操作) |
DTO | 层间数据传输(如Controller ↔ Service) | 可能比Entity少字段,或增加校验逻辑 | 请求处理阶段 |
VO | 返回给前端的展示数据 | 定制化字段,适配前端需求 | 响应生成阶段 |
为什么分层?
- 安全性:避免将Entity直接暴露给前端(如隐藏密码)。
- 灵活性:Entity、DTO、VO可独立变化,互不影响(例如数据库字段变更只需调整Entity)。
- 解耦:各层职责清晰,Controller不依赖数据库结构,Service不依赖前端需求。