当前位置: 首页 > news >正文

VO、DO、DTO 到底怎么分?一篇讲透后端分层的数据对象

关键词:VO、DO、DTO、Java 分层架构、领域模型、数据传输对象

刚入行的时候,最怕看到项目里一堆XxxVOXxxDOXxxDTO飞来飞去。明明都是"装数据的类",为什么还要分这么多种?能不能干脆统一用一个Xxx搞定?

答案先放这:短期能跑,长期必乱。这篇文章就把这三个"O"讲清楚,顺便给你一套能直接抄的项目分层范本。


一、先给结论:它们各管一段

对象全称中文活动区域关注点
DOData Object / Domain Object数据对象 / 领域对象数据库 ↔ DAO 层表结构、持久化
DTOData Transfer Object数据传输对象服务层 ↔ 控制层(跨进程/跨层)精简、安全、按需组装
VOView Object / Value Object视图对象控制层 ↔ 前端页面展示、格式化

一句话记忆:DO 贴近数据库,DTO 贴近传输,VO 贴近屏幕。


二、DO:和数据库表"同呼吸共命运"

DO 是数据持久层的核心,字段基本和数据库表一一对应。它的唯一职责,就是忠实地映射表结构

// 用户表 user 对应的 DO@TableName("user")publicclassUserDO{privateLongid;privateStringusername;privateStringpassword;// 注意:敏感字段privateStringphone;privateIntegerstatus;privateDatecreateTime;privateDateupdateTime;// getter / setter 省略}

要点:

  • 字段名、类型尽量和表保持一致,别在这层做"展示优化"。
  • 密码、盐值这类敏感字段可以存在于 DO,但绝不能一路传到前端。
  • 在 MyBatis / JPA 的 Entity 里,DO 和 Entity 经常是同一类东西的不同叫法。

三、DTO:跨层传输的"瘦身快递盒"

当 Controller 要调 Service,或者微服务之间要传数据,你不会把整个 DO 丢过去(里面还带着密码呢)。DTO 就是为了按需组装、减少冗余、屏蔽敏感字段而存在的。

// 创建用户的请求 DTOpublicclassUserCreateDTO{@NotBlank(message="用户名不能为空")privateStringusername;@Pattern(regexp="^1[3-9]\\d{9}$",message="手机号格式不正确")privateStringphone;// 没有 password、没有 id、没有时间戳}// 服务间返回的 DTO(聚合了用户和订单概要)publicclassUserProfileDTO{privateLonguserId;privateStringnickname;privateIntegerorderCount;privateBigDecimaltotalSpent;}

要点:

  • DTO 里通常带参数校验注解@NotBlank@Pattern),它是"入参契约"。
  • 一个 DO 可以拆成多个 DTO(列表页 DTO、详情页 DTO),反向也可以多表聚合成一个 DTO。
  • 跨服务调用时,DTO 就是接口的"对外承诺",改字段要慎重(涉及兼容性)。

四、VO:只给前端"看得到的东西"

VO 是最后一道关,专门给前端页面用。它做的是格式化 + 裁剪:日期转成字符串、枚举转成中文、数字加上单位、把嵌套结构摊平。

// 前端用户列表展示用的 VOpublicclassUserListVO{privateLongid;privateStringusername;privateStringphoneMasked;// 138****8888privateStringstatusText;// 1 -> "正常",0 -> "禁用"privateStringcreateTimeText;// 2026-07-17 10:30}// 转换过程(典型在 Controller 或 Converter 里)UserListVOvo=newUserListVO();vo.setId(do.getId());vo.setUsername(do.getUsername());vo.setPhoneMasked(maskPhone(do.getPhone()));vo.setStatusText(do.getStatus()==1?"正常":"禁用");vo.setCreateTimeText(format(do.getCreateTime()));

要点:

  • VO 里不要出现业务计算逻辑,只做"展示所需的数据搬运"。
  • 前端要什么格式,VO 就长什么样——它是以页面为中心的。
  • 敏感字段在 VO 层面必须彻底消失。

五、三者怎么串起来?一张流程图看明白

[ 数据库 ] │ (MyBatis 查询) ▼ UserDO ──► Service 层做业务处理 │ │ (DO → DTO,跨层/跨服务传) ▼ UserDTO ──► Controller 接收 / 转发 │ │ (DTO/DO → VO,按页面需求组装) ▼ UserVO ──► 返回给前端渲染

简化记忆:DO 进来,DTO 跑腿,VO 出去。


六、新手最容易踩的 3 个坑

  1. 一个类打天下:前端要改个字段展示,你直接改了 DO,结果把数据库映射也搞崩了。分层就是为了"改展示不动存储"。
  2. DTO 当 VO 用:把带密码的 DTO 直接序列化返回前端——这是真实发生过的严重事故。
  3. 过度设计:只有 3 张表的小项目,硬凑 VO/DO/DTO 三套,反而拖慢开发。中小项目可以DO + VO两件套起步,等业务复杂了再补 DTO。

七、什么时候该用,什么时候可以省?

项目规模推荐组合说明
内部小工具 / DemoEntity 直接用怎么快怎么来
普通单体后台DO + VOController 直接转 VO 返回
标准分层后台DO + DTO + VOService 出 DTO,Controller 转 VO
微服务DTO(强约束)+ VO跨服务必须用 DTO 当契约

八、总结

  • DO忠于数据库,DTO忠于传输,VO忠于页面。
  • 分层的本质不是"多写几个类",而是隔离变化:存储结构、接口契约、展示需求,三者各自演进互不干扰。
  • 别为了分层而分层,但一旦项目超过"玩具级",这套三件套就是你的安全带。

如果你现在项目里还是"一个 User 类走天下",不妨从今天起,先把返回前端的对象单独抽成 VO,这一步成本最低、收益最明显。


觉得有用点个赞 👍,关于 DTO 和 VO 的互相转换(MapStruct / 手写 Converter),下篇可以展开讲。评论区说说你们项目用的是几件套?

http://www.cnnetsun.cn/news/3495317.html

相关文章:

  • 树莓派操作系统Trixie升级指南与兼容性解决方案
  • FPGA启动时间优化:SPI Flash选型与配置技巧
  • EUV光刻机核心技术解析:13.5nm波长与激光等离子体光源
  • 开放式耳机推荐哪个品牌?盘点2026年十款音质最好的开放式耳机
  • 半导体材料电特性测量:从直流到高频的精准挑战
  • openeuler/ros-porting-tools常见问题解决指南:新手必看的10个避坑技巧
  • SL1588HB替代TPS54202 耐压36V2A 脚位兼容
  • ComfyUI-WanVideoWrapper:高效AI视频生成工作流搭建与进阶应用指南
  • 碳化硅MOSFET在功率器件中的优势与应用
  • isaacsim安装--解决 Vulkan 问题
  • 百考通生成:AI赋能任务书生成,让科研与项目启动更高效
  • 电感线圈Q值优化:原理、材料与设计实践
  • Soul 在WAIC 2026:AI硬件首次亮相、SoulX实时数字人,共探下一代人机交互范式新可能
  • 信号隔离与电源隔离技术详解及应用指南
  • 2026年苏州市科技型中小企业评价入库申报指南
  • 【无标题】 2026最新2款AI编程工具平替之选深度实测
  • 2026口碑好的扫码点餐小程序系统服务商哪个好用?实测推荐
  • 揭秘2026年KVM坐席市场:这三大厂家的口碑为何遥遥领先?
  • 县域水务泵站运维优化方案:污水泵站无人值守监测改造落地案例
  • 2026年南京AI六小龙企业服务能力横向对比
  • PCB焊盘设计:从基础认知到工程实践
  • GPU流处理器原理与并行计算优化实践
  • 谐振功率放大器设计与性能优化实践
  • 2026年搞AI,Python仍是“唯一真神”(极简版)
  • 大健康服务迈入量化时代!AI饮食数字化重构机构营养干预核心体系
  • 工地空气能热水器故障,三步排查快速解决
  • 学习笔记:函数栈帧的创建与销毁
  • 数字化管控原料保质期,助力烘焙企业实现库存降本增效
  • AI Agent可靠性如何验证?:3类致命缺陷+4步自动化检测法,错过=线上事故
  • 佳通轮胎携手仰望U9X亮相古德伍德,以轮胎科技挑战性能边界