news 2026/6/23 21:12:12

别再被VO、BO、PO、DTO、DO绕晕!今天用一段代码把它们讲透

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
别再被VO、BO、PO、DTO、DO绕晕!今天用一段代码把它们讲透

一、先放结论

它们都是“为了隔离变化”而诞生的马甲

缩写英文全称中文直译出现位置核心目的
POPersistent Object持久化对象数据库 ↔ 代码一张表一行记录的直接映射
DODomain Object领域对象核心业务逻辑层充血模型,封装业务行为
BOBusiness Object业务对象应用/服务层聚合多个DO,面向用例编排
DTOData Transfer Object数据传输对象进程/服务间精简字段,抗网络延迟
VOView Object视图对象控制层 ↔ 前端展示友好,防敏感字段泄露

一句话总结:PO 管存储,DO 管业务,BO 管编排,DTO 管网络,VO 管界面。

下面上代码,咱们边喝奶茶边讲。


二、业务场景

用户下一单“芋泥波波奶茶”

需求:

  1. 用户选好规格(大杯、少冰、五分糖)。
  2. 点击“提交订单”,前端把数据发过来。
  3. 后端算价格、扣库存、落库,返回“订单创建成功”页面。

整条链路里,我们到底需要几个对象?


三、从数据库开始:PO

PO是Persistent Object的简写 PO 就是“一行数据一个对象”,字段名、类型和数据库保持一一对应,不改表就不改它。

kotlin

体验AI代码助手

代码解读

复制代码

// 表:t_order @Data @TableName("t_order") public class OrderPO { private Long id; // 主键 private Long userId; // 用户ID private Long productId; // 商品ID private String sku; // 规格JSON private BigDecimal price; // 原价 private BigDecimal payAmount; // 实付 private Integer status; // 订单状态 private LocalDateTime createTime; private LocalDateTime updateTime; }

注意:PO 里绝不能出现业务方法,它只是一个“数据库搬运工”。


四、核心业务:DO

DO 是“有血有肉的对象”,它把业务规则写成方法,让代码自己说话。

csharp

体验AI代码助手

代码解读

复制代码

// 领域对象:订单 public class OrderDO { ​ private Long id; private UserDO user; // 聚合根 private MilkTeaDO milkTea; // 商品 private SpecDO spec; // 规格 private Money price; // Money是值对象,防精度丢失 private OrderStatus status; ​ // 业务方法:计算最终价格 public Money calcFinalPrice() { // 会员折扣 Money discount = user.getVipDiscount(); // 商品促销 Money promotion = milkTea.getPromotion(spec); return price.minus(discount).minus(promotion); } ​ // 业务方法:下单前置校验 public void checkBeforeCreate() { if (!milkTea.hasStock(spec)) { throw new BizException("库存不足"); } } }

DO 可以引用别的 DO,形成聚合根。它不关心数据库,也不关心网络。


五、面向用例:BO

BO 是“场景大管家”,把多个 DO 攒成一个用例,常出现在 Service 层。

scss

体验AI代码助手

代码解读

复制代码

@Service public class OrderBO { ​ @Resource private OrderRepository orderRepository; // 操作PO @Resource private InventoryService inventoryService; // RPC或本地 @Resource private PaymentService paymentService; ​ // 用例:下单 @Transactional public OrderDTO createOrder(CreateOrderDTO cmd) { ​ // 1. 构建DO OrderDO order = OrderAssembler.toDO(cmd); ​ // 2. 执行业务校验 order.checkBeforeCreate(); ​ // 3. 聚合逻辑:扣库存、算价格 inventoryService.lock(order.getSpec()); Money payAmount = order.calcFinalPrice(); ​ // 4. 落库 OrderPO po = OrderAssembler.toPO(order, payAmount); orderRepository.save(po); ​ // 5. 返回给前端需要的数据 return OrderAssembler.toDTO(po); } }

BO 的核心是编排,它把 DO、外部服务、PO 串成一个完整的业务动作。


六、跨进程/服务:DTO

DTO 是“网络快递员”,字段被压缩成最少,只带对方需要的数据。

1)入口 DTO:前端 → 后端

kotlin

体验AI代码助手

代码解读

复制代码

@Data public class CreateOrderDTO { @NotNull private Long userId; @NotNull private Long productId; @Valid private SpecDTO spec; // 规格 }

2)出口 DTO:后端 → 前端

kotlin

体验AI代码助手

代码解读

复制代码

@Data public class OrderDTO { private Long orderId; private String productName; private BigDecimal payAmount; private String statusDesc; private LocalDateTime createTime; }

DTO 的字段命名常带 UI 友好词汇(如statusDesc),并且绝不暴露敏感字段(如userId在返回给前端时可直接省略)。


七、最后一步:VO

VO 是“前端专属快递”,字段可能二次加工,甚至带 HTML 片段。

typescript

体验AI代码助手

代码解读

复制代码

@Data public class OrderVO { private String orderId; // 用字符串避免 JS long 精度丢失 private String productImage; // 带 CDN 前缀 private String priceText; // 已格式化为“¥18.00” private String statusTag; // 带颜色:green/red }

VO 通常由前端同学自己写 TypeScript/Java 类,后端只负责给 DTO,再让前端 BFF 层转 VO。如果你用 Node 中间层或 Serverless,VO 就出现在那儿。


八、一张图记住流转过程

scss

体验AI代码助手

代码解读

复制代码

前端页面 │ JSON ▼ CreateOrderVO (前端 TS) │ 序列化 ▼ CreateOrderDTO (后端入口) │ BO.createOrder() ▼ OrderDO (充血领域模型) │ 聚合、计算 ▼ OrderPO (落库) │ MyBatis ▼ 数据库

返回时反向走一遍:

java

体验AI代码助手

代码解读

复制代码

数据库 │ SELECT OrderPO │ 转换 OrderDTO │ JSON OrderVO (前端 TS 渲染)


九、常见疑问答疑

  1. 为什么 DO 和 PO 不合并?数据库加索引、加字段不影响业务;业务改规则不改表结构。隔离变化。
  2. DTO 和 VO 能合并吗?小项目可以,但一上微服务或多端(App、小程序、管理后台),立马爆炸。比如后台需要用户手机号,App 不需要,合并后前端会拿到不该看的数据。
  3. BO 和 Service 有什么区别?BO 更贴近用例,粒度更粗。Service 可能细分读写、缓存等。命名随意,关键看团队约定。

十、一句话背下来

数据库里叫 PO,业务里是 DO,编排靠 BO,网络走 DTO,前端看 VO。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/23 2:20:51

PySceneDetect终极指南:智能视频场景检测与自动分割完整教程

PySceneDetect终极指南:智能视频场景检测与自动分割完整教程 【免费下载链接】PySceneDetect :movie_camera: Python and OpenCV-based scene cut/transition detection program & library. 项目地址: https://gitcode.com/gh_mirrors/py/PySceneDetect …

作者头像 李华
网站建设 2026/6/23 4:44:34

Warp框架v0.4迁移实战:从破局到精通的完整攻略

Warp框架v0.4迁移实战:从破局到精通的完整攻略 【免费下载链接】warp A super-easy, composable, web server framework for warp speeds. 项目地址: https://gitcode.com/gh_mirrors/war/warp 当你打开Cargo.toml,看到warp版本升级提示时&#x…

作者头像 李华
网站建设 2026/6/23 4:48:43

终极3D生成革命:腾讯Hunyuan3D-2mv让建模效率飙升40倍

你是否曾经为制作一个简单的3D模型而花费数天时间?是否因为复杂的建模软件而望而却步?现在,这一切都将改变。腾讯开源的Hunyuan3D-2mv多视角3D生成技术,正在重新定义3D内容创作的边界。 【免费下载链接】Hunyuan3D-2mv Hunyuan3D-…

作者头像 李华
网站建设 2026/6/23 12:24:54

H5可视化编辑器终极指南:无需编码快速制作专业H5页面

H5可视化编辑器终极指南:无需编码快速制作专业H5页面 【免费下载链接】h5-Dooring MrXujiang/h5-Dooring: h5-Dooring是一个开源的H5可视化编辑器,支持拖拽式生成交互式的H5页面,无需编码即可快速制作丰富的营销页或小程序页面。 项目地址:…

作者头像 李华
网站建设 2026/6/23 3:05:47

终极便携:VLC播放器绿色免安装版完整使用指南

还在为复杂的播放器安装流程烦恼吗?VLC播放器绿色免安装版就是你的完美解决方案!这款功能强大的多媒体播放器无需安装即可使用,支持几乎所有音视频格式,真正实现即下即用。 【免费下载链接】VLC播放器绿色免安装版下载 本仓库提供…

作者头像 李华
网站建设 2026/6/23 9:39:42

RabbitMQ 核心概念与工作模式全解析

一、RabbitMQ 架构深度解析1.1 核心组件架构图1.2 核心组件详解Broker(消息代理)RabbitMQ Server 本身就是 Message Broker,负责接收、存储和转发消息的中间件实体。java// RabbitMQ Broker 连接示例 ConnectionFactory factory new Connect…

作者头像 李华