在 Java 后端分层架构(Controller→Service→DAO/Repository)中,VO、BO、PO、DO、DTO 是最常用的 5 类数据载体,它们各司其职、边界清晰,核心区别在于所处层级、核心职责、数据范围与是否包含业务逻辑 。简单来说:DO/PO 对应数据库,BO 处理业务,DTO 负责跨层传输,VO 专供前端展示。
一、核心概念与通俗理解
1. DO(Domain Object):领域对象
-
全称:Domain Object
-
核心定位 :领域层 / 持久化层 ,与数据库表一一对应,是数据库表的 "代码镜像"。
-
通俗理解 :数据库里的一行数据,字段和表结构完全一致,只存数据、几乎无业务逻辑。
-
典型特征
- 字段名、类型与数据库表字段严格匹配
- 包含主键(id),无多余 / 组合字段
- 只有 getter/setter,无业务方法
-
示例(UserDO)
public class UserDO {
private Long id; // 数据库主键
private String username; // 用户名
private String password; // 密码(加密后)
private Integer gender; // 性别:0-未知,1-男,2-女
private Date createTime; // 创建时间
// getter/setter
}
2. PO(Persistent Object):持久化对象
-
全称:Persistent Object
-
核心定位 :与DO 完全等价 ,是早期持久化框架(如 Hibernate)的叫法,现在主流项目中DO 更常用。
-
通俗理解 :和 DO 是同一个东西,只是命名习惯不同,可视为 DO 的别名。
-
示例(UserPO,与 UserDO 结构完全一致)
public class UserPO {
private Long id;
private String username;
private String password;
private Integer gender;
private Date createTime;
// getter/setter
}
3. BO(Business Object):业务对象
-
全称:Business Object
-
核心定位 :业务逻辑层(Service) ,封装复杂业务规则与行为,是业务领域的核心实体。
-
通俗理解:处理业务逻辑的 "大脑",可组合多个 DO/PO,包含计算、校验、状态判断等业务方法。
-
典型特征
- 包含完整业务属性,可组合多个 DO
- 有业务方法(如计算、校验、状态转换)
- 不一定与数据库表一一对应,也不一定持久化
-
示例(OrderBO,订单业务对象)
public class OrderBO {
private Long orderId;
private String orderNo;
private BigDecimal totalAmount;
private List<OrderItemDO> items; // 组合多个DO
private Integer status;
private Date createTime;// 业务方法:计算订单总价 public void calculateTotal() { this.totalAmount = items.stream() .map(OrderItemDO::getSubtotal) .reduce(BigDecimal.ZERO, BigDecimal::add); } // 业务方法:判断订单是否可取消 public boolean canCancel() { return "待支付".equals(getStatusText()) && new Date().getTime() - this.createTime.getTime() < 3600000; // 1小时内 } // getter/setter}
4. DTO(Data Transfer Object):数据传输对象
-
全称:Data Transfer Object
-
核心定位 :跨层 / 跨服务传输(Controller↔Service、微服务间),是数据的 "快递包裹"。
-
通俗理解 :按需裁剪字段,只传需要的数据,隔离内部模型,避免暴露敏感信息。
-
典型特征
- 纯数据容器,无任何业务逻辑
- 字段是 DO/BO 的子集或组合,扁平化结构
- 适配序列化(JSON/XML),适合网络传输
-
示例(UserDTO,用户信息传输)
public class UserDTO {
private Long userId;
private String username;
private String genderText; // 性别文本:男/女/未知
private String createTimeStr; // 格式化时间:2026-04-18
// 无password等敏感字段
// getter/setter
}
. VO(View Object):视图对象
-
全称:View Object
-
核心定位 :展示层(Controller→前端) ,专为前端展示定制,是返回给前端的最终数据载体。
-
通俗理解:前端页面的 "专属数据模型",只包含展示需要的字段,做数据格式化、脱敏、组合。
-
典型特征
- 字段完全匹配前端页面需求,无多余字段
- 包含格式化数据(如时间、金额)、状态文本、组合字段
- 绝对不包含敏感信息(密码、身份证号等)
-
示例(UserVO,用户详情页展示)
public class UserVO {
private String username;
private String gender; // 直接返回"男",而非1/2
private String registerTime; // 2026-04-18 17:30:00
private Boolean isVip; // 组合字段:根据等级判断
// 无id、password等敏感/非展示字段
// getter/setter
}
二、五大对象核心对比表
| 对比维度 | DO(领域对象) | PO(持久化对象) | BO(业务对象) | DTO(数据传输对象) | VO(视图对象) |
|---|---|---|---|---|---|
| 全称 | Domain Object | Persistent Object | Business Object | Data Transfer Object | View Object |
| 核心职责 | 数据库表映射 | 同 DO(早期叫法) | 封装业务逻辑 | 跨层 / 跨服务数据传输 | 前端展示数据封装 |
| 所处层级 | 领域层 / 持久化层 | 领域层 / 持久化层 | 业务逻辑层(Service) | 应用层 / 接口层 | 展示层(Controller) |
| 数据映射 | 与数据库表一一对应 | 同 DO | 组合多个 DO/PO,不直接映射表 | DO/BO 的子集 / 组合,按需裁剪 | 完全匹配前端展示需求 |
| 业务逻辑 | 无(仅 getter/setter) | 无(仅 getter/setter) | 有(计算、校验、状态判断) | 无(纯数据容器) | 无(纯展示数据) |
| 敏感信息 | 可能包含(如 password) | 可能包含(如 password) | 可能包含 | 不包含 | 绝对不包含 |
| 典型场景 | DAO/Repository 操作 | DAO/Repository 操作 | Service 层业务处理 | Controller↔Service、微服务调用 | Controller 返回前端数据 |
三、分层流转与转换流程
在标准三层架构中,五大对象的流转路径清晰,层与层之间通过转换工具(如 MapStruct、BeanUtils)实现对象转换,避免直接暴露底层模型:
- 持久化层 :DAO/Repository 操作数据库,返回DO/PO
- 业务层 :Service 接收 DO/PO,封装为BO ,执行业务逻辑,处理后转为DTO返回给 Controller
- 展示层 :Controller 接收 DTO,转换为VO,返回给前端
完整流转示例(用户查询):
- 前端请求 → Controller 接收参数 → 调用 Service
- Service → 调用 DAO 查询 → 得到UserDO
- Service → 将 UserDO 封装为UserBO (无复杂逻辑时可省略)→ 转为UserDTO返回 Controller
- Controller → 将 UserDTO 转换为UserVO → 返回给前端
四、常见误区与最佳实践
1. 常见误区
- DO=PO=DTO=VO:混用所有对象,导致层间耦合、敏感信息泄露、前端数据冗余
- BO 无业务逻辑:BO 只存数据、无业务方法,失去业务对象的核心价值
- 直接用 DO/PO 返回前端:暴露数据库结构与敏感信息,存在安全风险
- 一个 DTO/VO 通吃所有场景:不同接口 / 页面需求不同,复用会导致字段冗余或缺失
2. 最佳实践
- 分层清晰,各司其职:DO/PO 管数据库,BO 管业务,DTO 管传输,VO 管展示
- 禁止跨层直接使用:层间必须转换,不将 DO/PO 直接传给 Controller 或前端
- DTO/VO 按需设计:一个接口 / 页面对应一个 DTO/VO,不追求复用导致冗余
- 使用工具类转换:用 MapStruct、BeanUtils 等工具简化对象转换,避免手动编码
- 敏感信息严格过滤:DTO/VO 中绝对不包含 password、身份证号、银行卡号等敏感数据
五、总结
VO、BO、PO、DO、DTO 是 Java 分层开发的基础数据模型,核心区别在于使用场景与职责:
- DO/PO:数据库的 "镜像",负责持久化
- BO:业务逻辑的 "大脑",负责处理业务
- DTO:数据的 "快递包裹",负责跨层传输
- VO:前端的 "专属模型",负责展示数据
理解并正确使用这 5 类对象,能让代码结构更清晰、层间解耦更彻底、安全性更高,是后端开发的必备技能。
