Java 分层对象详解:POJO、JavaBean、Entity、DTO、VO、Query、BO
标签:Java、SpringBoot、后端规范、分层设计 适合人群:刚梳理领域对象分层,经常分不清各种 XXO 职责的后端开发
前言
在 SpringBoot 业务开发里,我们总会见到一堆后缀:Entity、DO、DTO、VO、Query、BO。 很多同学写项目的时候随手混用,入参直接用 Entity,返回直接丢数据库实体,线上时不时爆出敏感字段泄露、循环引用、参数校验混乱等问题。 同时还有两个基础概念:POJO 和 JavaBean,很容易被当成同一个东西。 本文只讲对象分层和概念职责,序列化相关内容放到另一篇,不交叉混淆。
一、基础概念:POJO 和 JavaBean
POJO(Plain Old Java Object)
直译:简单老式 Java 对象。 定义:一个普通 Java 类,不强制继承特定父类、不强制实现接口、没有框架侵入性注解约束,单纯用来承载数据。 POJO 是一个非常宽泛的概念,没有强制编码规范。
只要不是特殊框架类、不是接口、不是枚举,单纯装数据的类,都可以叫 POJO。
JavaBean
JavaBean 是 POJO 的子集,有一套严格的规范约束,满足下面全部条件,才是 JavaBean:
- 必须提供无参构造函数
- 所有成员变量私有
private,对外提供 getter、setter - 可选:实现
java.io.Serializable(用于 JDK 原生序列化) - 可选:重写
toString()
一句话总结:所有 JavaBean 都是 POJO,但 POJO 不一定是 JavaBean。
👉 开发实操(Lombok) 日常用 @Data + @NoArgsConstructor 可以快速生成符合 JavaBean 规范的类。 高频坑:只写 @Data + @AllArgsConstructor,缺少无参构造。 MyBatis、JPA、Jackson 反序列化都需要无参构造,缺失直接报错。 @Builder 默认也不会生成无参构造,组合使用需要额外注意。
二、各个分层对象职责定义
表格
| 对象 | 全称 | 核心职责 | 数据流向 |
|---|---|---|---|
| Entity / DO | Data Object | 数据库映射实体,和表结构一一对应 | Service ↔ 数据库 |
| Query | Query Object | 查询条件对象,承载过滤条件、分页、排序 | 前端 → Controller → Service,仅入参 |
| DTO | Data Transfer Object | 数据传输对象 | 分为 SaveDTO/UpdateDTO(新增修改入参)、微服务内部传输 DTO |
| VO | View Object | 视图对象 | Service → Controller → 前端,用于接口返回 |
| BO | Business Object | 业务对象 | Service 内部复杂业务组装;简单单体项目可以不使用 |
重点澄清:Query 和 SaveDTO 为什么分开?
两者都是前端传 JSON,很多人会疑惑能不能合并成一个类。
- Query:偏向查询场景,字段大多是过滤条件,大量字段允许为空,一般不做强校验;
- SaveDTO / UpdateDTO:新增、修改场景,配合
@Valid做严格参数校验(非空、长度、正则等)。 职责拆分后代码语义清晰,校验规则互不干扰,是团队推荐写法。
推荐极简分层链路(单体项目足够用)
前端 → Query(查询接口) / SaveDTO(新增修改接口)
→ Service
→ Entity(DO)(和数据库交互)
→ Service组装、数据脱敏
→ VO(返回给前端)
铁律:禁止直接把 Entity 返回给前端 风险点:
- 容易泄露敏感字段(密码、内部编号)
- 实体存在一对多互引时,JSON 序列化出现循环引用栈溢出
- 数据库字段变更,会直接影响前端返回结构,耦合严重
三、对象转换工具选型
DO、DTO、VO 之间互相转换,手写大量 getter/setter 非常冗余:
- MapStruct(首选推荐):编译期生成转换代码,性能高、类型安全,支持自定义转换逻辑;
- Hutool
BeanUtil:使用简单,基于反射,适合小项目简单转换; - Spring 自带
BeanUtils.copyProperties:谨慎使用,存在 null 覆盖、类型转换异常、日期转换翻车等经典坑。
四、BO 什么时候才需要?
BO 是业务对象,用来承载一段复杂业务组合后的模型。
- 简单 CRUD 项目:完全可以删掉 BO,不需要硬套设计;
- 适合 BO 场景:一个业务需要聚合多个 DO、多表查询、复杂计算组装,单独抽 BO 承载业务中间模型,隔离数据库实体。
五、本篇小结
- POJO 是宽泛概念;JavaBean 是带编码规范的 POJO 子集;
- Entity 映射数据库,Query 负责查询条件,SaveDTO 负责新增修改入参,VO 负责返回前端;
- 分层核心目的:解耦,隔离数据库、后端业务、前端视图;
- Lombok 使用重点关注无参构造,这是高频报错源头;
- 转换优先 MapStruct,少用 Spring BeanUtils