java 项目分层 PO、VO、BO、DTO、DAO、POJO个人项目实践中的见解

大家做了很多的项目,发现好多的架构分层和实体类的分层。

发现一个问题,一个人的项目 自己做着做着就为了省事 混着用,多人团体项目,可能从一开始就用错了,大家就将错就错。

这样就出现一个问题:分层到底怎么tm的分...当自己建立一个项目的时候,拔剑四顾心茫然,当我在旧的项目里面扒拉屎的时候,脑子混乱。作者现在还没有读DDD领域,但是频繁的遇见这样的问题的时候,说明你已经到时候读读书了(后面看完了,会继续完善该文章的),同时也是和各位看官共勉。

前面算是前沿,按照我个人的经验来看,下面的图和定义,很可能让人陷入到形而上学,实际上类只有一个核心的目的:谁用 || 用于谁 || 作用于谁 || 返回给谁 举个例子:VO给谁用,给前端用,那就是需要返回给前端,那就是在Controlller 层定义返回值(return value)。

bash 复制代码
public BasePageVO<DeviceListVO> queryDeviceList(xxx)

直接整图:


图多不多,整昏你,来继续上定义

一种是基于 DDD(领域驱动设计) 的术语体(VO/DTO/BO/PO/DO),另一种是更偏向 工程实践中的 POJO 分类(vo/query/entity/dto)。

分层领域模型规约:
VO:(View Object)视图对象,一般位于Controller层,用于展示视图。
DTO:(Data Transfer Object)数据传输对象, 即RPC 接口请求或传输出去的对象,用于展示层与服务层之间的数据传输对象。
BO:(Business Object)业务层对象,一般位于Service层,它与 DO 会有一定的属性差别。
PO:(Persistent Object)持久化对象,对象属性与数据库字段形成映射关系。
DO:(Domain Object)领域对象,就是从现实世界中抽象出来的有形或无形的业务实体,可以当成BO;(Data Object)数据层对象,对象属性与数据库字段形成映射关系,可以当成PO
Query:数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装,禁止使用 Map 类来传输。
POJO
• vo (与前端交互的所有对象,包括接参和返回)
• query (查询的筛选条件,前端传参和后端内部传参通用)
• entity (数据库表基础对象)
• dto(后端内部传输用,例如多张表字段合并到一个对象)


如果项目规模小、团队约定宽松:用 DTO 当请求参数 没问题,很多项目都这么干。

Controller层 :DTO 作为前端调用后端的接口参数

Service 层 :DTO 处理后转换成 DO 或者BO 作为参数作为Service 层调Dao 层的数据库

Dao 层 :Dao 返回 Entity (PO)

Service 层: 将Entity (PO) 转换成 DO 或者BO

Controller层 :将 DO 或者BO 转换成VO 作为前端的返回

更规范的流程

bash 复制代码
前端
  ↓ (HTTP JSON)
Controller
  → 接收:XXXRequest (VO)
  → 调用 Service
      ↓
Service
  → 将 Request 转为 Domain Object (DO/BO)
  → 调用 DAO
      ↓
DAO
  → 使用 Entity (PO) 操作数据库
  → 返回 Entity 或 查询投影对象
      ↑
Service
  → 组装 BO / 聚合多个 Entity
  → 转为 XXXResponse (VO)
      ↑
Controller
  → 返回 VO 给前端
bash 复制代码
dto/     → 跨服务用(可选)
vo/      → controller 用
entity/  → dao 用
bo/      → service 用(复杂业务时)
query/   → 查询条件

什么是"跨服务"(Service-to-Service)?

指的是 后端微服务之间的调用,例如:

用户服务(User Service) → 调用 → 订单服务(Order Service)

通过 Feign、Dubbo、gRPC、HTTP + JSON 等方式通信

特点:

后端对后端

通常有强契约(接口版本、字段稳定性要求高)

可能涉及内部敏感字段(如 internalStatus, auditLog)

不暴露给前端

什么时候可以"Entity = BO"?

在以下场景中,可以简化,让 Entity 兼任 BO:

CRUD 简单系统(如后台管理、配置表维护)

业务逻辑极轻,没有复杂规则、状态机、聚合需求

快速原型开发,追求效率而非架构严谨性

bash 复制代码
// DAO 层
UserEntity entity = userMapper.selectById(id);

// Service 层
UserBO bo = UserBO.from(entity);
bo.validate(); // 业务校验
bo.updateLastLoginTime();

// 转 VO 返回
return UserVO.from(bo);

简单项目:可用 Entity 兼做 BO,但不要直接暴露给 Controller

相关推荐
码哥DFS12 分钟前
构造函数、实例对象、对象原型 ----三者关系
开发语言·javascript·原型模式
9523637 分钟前
Spring-cloud配置中心
java·spring·spring cloud·微服务
quantdash_cc41 分钟前
告别自建 Requests/BS4 网页爬虫:基于 QuantDash 搭建零维保的高性能量化行情流水线
开发语言·爬虫·python·pandas·量化·quantdash
ydd1001001 小时前
寻找两个正序数组的中位数 Java 题解,二分分割详解
java·开发语言
半亩码田1 小时前
C#转Python第3.1篇:Python 的 class 没有访问修饰符?面向对象的另一条路
开发语言·python·c#
真上帝的左手2 小时前
10. 软件设计&架构-Spring Security 7 整合CAS SSO 单点登录
java·spring·架构·sso
Wzx1980122 小时前
python沙箱和docker沙箱你选对了吗?
开发语言·python·docker
牧羊人.3332 小时前
Python 办公自动化从入门到入土|09 数据容器之字典
开发语言·python
Zane19942 小时前
单例线程安全、生产者消费者、死锁:并发面试三连问串讲
java·后端
小僧景贤2 小时前
嵌入式C语言 第二篇:基础语法|嵌入式C与标准C的核心差异
c语言·开发语言·嵌入式c语言