Java 分层对象详解:POJO、JavaBean、Entity、DTO、VO、Query、BO

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:

  1. 必须提供无参构造函数
  2. 所有成员变量私有 private,对外提供 getter、setter
  3. 可选:实现 java.io.Serializable(用于 JDK 原生序列化)
  4. 可选:重写 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 返回给前端 风险点:

  1. 容易泄露敏感字段(密码、内部编号)
  2. 实体存在一对多互引时,JSON 序列化出现循环引用栈溢出
  3. 数据库字段变更,会直接影响前端返回结构,耦合严重

三、对象转换工具选型

DO、DTO、VO 之间互相转换,手写大量 getter/setter 非常冗余:

  1. MapStruct(首选推荐):编译期生成转换代码,性能高、类型安全,支持自定义转换逻辑;
  2. Hutool BeanUtil:使用简单,基于反射,适合小项目简单转换;
  3. Spring 自带 BeanUtils.copyProperties:谨慎使用,存在 null 覆盖、类型转换异常、日期转换翻车等经典坑。

四、BO 什么时候才需要?

BO 是业务对象,用来承载一段复杂业务组合后的模型。

  • 简单 CRUD 项目:完全可以删掉 BO,不需要硬套设计;
  • 适合 BO 场景:一个业务需要聚合多个 DO、多表查询、复杂计算组装,单独抽 BO 承载业务中间模型,隔离数据库实体。

五、本篇小结

  1. POJO 是宽泛概念;JavaBean 是带编码规范的 POJO 子集;
  2. Entity 映射数据库,Query 负责查询条件,SaveDTO 负责新增修改入参,VO 负责返回前端;
  3. 分层核心目的:解耦,隔离数据库、后端业务、前端视图;
  4. Lombok 使用重点关注无参构造,这是高频报错源头;
  5. 转换优先 MapStruct,少用 Spring BeanUtils