后端数据对象命名:VO、DO、PO 等的真实含义
后端数据对象命名:VO、DO、PO 等的真实含义
花洒!!!
2026年8月24日
后端架构Java分层
讲清 PO、DO、DTO、BO、VO、POJO、AO 七种数据对象的真实含义、所在分层与转换链路,附对照表与常见误区。
后端数据对象命名:VO、DO、PO 等的真实含义
VO、BO、PO、DTO、DO 满天飞,问你为什么这么设计又答不上来?这篇文章一次讲透。
为什么非要拆对象
- 分层架构各层职责不同:Controller 管展示、Service 管业务、Repository 管数据,各层需要的字段天然不一样。
- 数据安全:数据库对象直接返回,密码、内部字段全暴露;拆出 VO 才能过滤敏感信息。
- 可维护性:字段变化只影响对应层,不牵一发动全身。
逐个拆解真实含义
| 缩写 | 全称 | 所在层 | 真实含义 |
|---|---|---|---|
| PO | Persistent Object | 持久化层 | 与数据库表结构一一对应的持久化对象,由 ORM(MyBatis / Hibernate)管理生命周期,不含业务逻辑 |
| DO | Data Object | Repository / DAO 层 | 数据访问对象,与表结构对应,可在数据访问层带少量辅助方法(如 isActive()) |
| DTO | Data Transfer Object | 层间 / 服务间 | 数据传输对象,跨层、跨服务(RPC)传输数据,可聚合多个对象、可做格式转换 |
| BO | Business Object | Service 层 | 业务对象,封装业务逻辑(如 canLogin()、checkPassword()),是业务的核心抽象,常聚合多个 DO/PO |
| VO | Value Object | Controller / 展示层 | 视图对象,向前端返回的数据:格式友好、字段精选、不含敏感信息 |
| POJO | Plain Ordinary Java Object | 任意 | 普通 Java 对象,无框架约束的"裸"对象,是上面这些的总称/兜底 |
| AO | Application Object | Service 层 | 应用对象,阿里规约用语,在 Service 层接收、复用多个对象(阿里规约用 DO 而非 PO) |
几点容易混的:
- PO 与 DO:几乎同义,都是表结构映射。区别在语境——PO 强调 ORM 持久化实体(
@Entity),DO 强调数据访问层使用(Repository)。阿里规约统一叫 DO,不推荐 PO。 - DTO 与 VO:DTO 面向"传输"(可含密码等内部字段,服务间要传),VO 面向"展示"(必须干净)。同名多义时看语境。
- BO 是唯一带业务逻辑的:DO/PO 必须纯数据,业务方法只放 BO。
转换链路
典型链路:数据库 ⇄ DO(Repository)⇄ BO(Service)⇄ VO(Controller),入参则用 DTO。
public UserVO getUserById(Long id) {
UserDO userDO = userRepository.findById(id); // Repository 层
UserBO userBO = convertToBO(userDO); // Service 层做业务
return convertToVO(userBO); // 过滤敏感字段,格式化输出
}
转换工具:简单场景手写 setter;复杂场景用 MapStruct(@Mapping(target = "password", ignore = true) 顺手过滤敏感字段)。
常见误区
- 全层一个对象:Controller 直接返回
UserDO→ 密码外泄。各层对象必须分开。 - 对象随意横穿:Service 方法入参直接收 VO → 分层原则被破坏,入参用 DTO、出参用 VO。
- 过度设计:DO→BO→DTO→VO 连环转换只为多包一层 → 转换是必要的,但够用就好,别为转换而转换。
小结
记住一条主线:数据从数据库流向页面,每过一层换一次"衣服"——DO 对应表、BO 装业务、DTO 管传输、VO 给展示;PO 是 ORM 时代的 DO,POJO 是统称,AO 是阿里规约里的 Service 层聚合对象。拆分的目的永远是安全与解耦,不是炫技。
适用:Java 后端分层项目;不适用:脚本、无分层的小工具,强行套这套反而徒增样板代码。