Skip to content

springboot项目中 PO BO VO DTO POJO DAO概念及其作用(附转换图)

下面详细解释Spring Boot项目中常见的对象类型:PO、BO、VO、DTO、POJO、DAO,并说明它们在分层架构中的位置。

Spring Boot 项目中常见对象类型详解

1. PO (Persistent Object) 持久化对象

  • 定义:与数据库表结构一一对应的 Java 对象
  • 特征
  • 每个属性对应数据库表的一个字段
  • 通常包含 ORM 框架注解(如 @Table, @Column
  • 作用:作为 ORM 框架操作数据库的载体
  • 位置:位于infrastructure层(因为与数据库直接相关)。 (e.g., UserEntity.java)

2. DAO (Data Access Object) 数据访问对象

  • 定义:封装数据库访问操作的对象
  • 特征
  • 包含 CRUD 操作方法
  • 隔离数据库操作细节
  • 作用:提供统一的数据访问接口
  • 位置:位于infrastructure层(因为直接操作数据库)。 (e.g., UserRepositoryImpl.java, UserMapper.java)

3. DTO (Data Transfer Object) 数据传输对象

  • 定义:跨层/跨系统传输数据的对象
  • 特征
  • 扁平化结构,无业务逻辑
  • 通常实现序列化接口
  • 作用:减少网络传输次数,解耦接口
  • 位置
  • 通用DTO(如分页请求/响应)放在common-dto模块。
  • 各层特有的DTO放在各自模块:
  • Web层:接收前端请求的DTO(如UserCreateRequest)和返回给前端的响应DTO(如UserResponse)放在web模块。
  • Facade层:对外暴露的接口使用的DTO放在facade模块。

4. BO (Business Object) 业务对象

  • 定义:包含业务逻辑的领域核心对象
  • 特征
  • 聚合多个 PO 或值对象
  • 包含业务方法和领域规则
  • 作用:封装核心业务逻辑和状态
  • 位置:位于domain层(核心业务领域层)。 (e.g., User.java)

5. VO (View Object) 视图对象

  • 定义:前端展示专用的数据对象
  • 特征
  • 聚合多个领域对象的展示数据
  • 包含前端需要的特定字段和格式
  • 作用:为前端提供定制化数据结构
  • 位置:放在web模块(作为Controller的响应对象)。实际上,在我们的结构中,Web层的响应DTO就可以视为VO。 (e.g., UserResponse.java)

    注意:在有些上下文中,VO与DTO概念重叠,但在分层架构中,我们通常将用于展示的VO放在Web层。

6. POJO (Plain Old Java Object) 普通Java对象

  • 定义:不继承框架特定基类的简单对象
  • 特征
  • 只有属性和 getter/setter
  • 无框架依赖
  • 作用:作为其他对象的基类
  • 位置:所有层通用基础对象

分层架构中的位置分配

graph TD
    A[基础设施层] -->|包含| A1(PO)
    A -->|包含| A2(DAO实现)

    B[核心领域层] -->|包含| B1(BO)
    B -->|包含| B2(领域服务)

    C[Web层] -->|包含| C1(VO)
    C -->|包含| C2(Controller)

    D[公共DTO] -->|包含| D1(通用DTO)

    E[外观层] -->|包含| E1(RPC DTO)

    style A fill:#f4cccc
    style B fill:#d9ead3
    style C fill:#cfe2f3
    style D fill:#fff2cc
    style E fill:#d9d2e9

总结它们在分层架构中的位置:

对象类型 所在模块 说明 示例文件
PO infrastructure 与数据库表对应的实体 UserEntity.java
DAO infrastructure 数据访问接口(如Mapper) UserMapper.java
DTO common-dto, web, facade 数据传输对象,按使用场景分模块存放 PageRequest.java
BO domain 业务对象(领域模型) User.java
VO web 视图对象(可视为Web层的响应DTO) UserResponse.java
POJO 所有模块 泛指简单的Java对象,无特定位置 简单值对象

对象转换流程

在典型的请求流程中,对象转换如下:

请求:

前端 -> web (接收DTO, 如UserCreateRequest) -> application (将DTO转换为BO) -> domain (处理BO)

-> Infrastructure (将BO转换为PO, 然后通过DAO操作数据库)

响应:

Infrastructure (从数据库获取PO) -> 将PO转换为BO -> domain (返回BO) -> application (将BO转换为DTO)

-> web (返回DTO/VO给前端)

具体转换步骤

  1. web层

  2. 接收前端请求:使用DTO(如UserCreateRequest)接收参数。

  3. 调用application层:将DTO转换为BO(业务对象)传递给application。

  4. application层(应用服务层)

  5. 处理业务逻辑:使用BO进行业务操作。

  6. 调用domain层(领域服务):传递BO

  7. domain层

  8. 执行核心业务逻辑:使用BO(领域对象)。

  9. 调用Repository接口:传递BO(注意:这里domain层只依赖接口)。

  10. Infrastructure层

  11. 实现Repository:将BO转换为PO(持久化对象)。

  12. 使用DAO(如MyBatis Mapper)操作数据库:操作的是PO

  13. 从数据库获取数据:将PO转换为BO返回给domain层。

  14. 返回流程

  15. domain层返回BO给application层。

  16. application层将BO转换为DTO(如UserResponse)返回给web。

  17. web将DTO返回给前端(此时作为VO使用)。

转换流程

  1. web 层
    VO/RequestDTOBO
    (e.g., UserCreateRequestUser)

  2. application 层
    BOPO
    (e.g., UserUserEntity)

  3. Repository 层
    PO ➔ 数据库记录

  4. 返回流程
    数据库记录 ➔ POBOVO/ResponseDTO

转换流程

graph LR
    A[前端请求] -->|1.提交| B(VO/RequestDTO)
    B --> C[web]
    C -->|2.转换| D(BO)
    D --> E[application]
    E -->|3.业务处理| F(BO)
    F --> G[Repository]
    G -->|4.转换| H(PO)
    H --> I[(数据库)]
    I -->|5.返回| H
    H -->|6.转换| F
    F -->|7.转换| J(VO/ResponseDTO)
    J --> K[前端响应]

    style B fill:#cfe2f3,stroke:#333
    style D fill:#d9ead3,stroke:#333
    style H fill:#f4cccc,stroke:#333
    style J fill:#cfe2f3,stroke:#333

请求响应流程图


sequenceDiagram
    participant Frontend as 前端
    participant web as web层
    participant application as application层
    participant domain as domain领域层
    participant Infrastructure as Infrastructure层
    participant Database as 数据库

    rect rgb(191, 223, 255, 0.3)
    note over Frontend,Database: 请求流程
    Frontend->>web: 发送请求(DTO)<br/>e.g. UserCreateRequest
    web->>application: 传递DTO
    application->>application: DTO → BO转换<br/>e.g. UserCreateRequest → User
    application->>domain: 传递BO
    domain->>Infrastructure: 调用仓储方法<br/>传递BO
    Infrastructure->>Infrastructure: BO → PO转换<br/>e.g. User → UserEntity
    Infrastructure->>Database: 执行DAO操作<br/>保存PO
    end

    rect rgb(191, 255, 191, 0.3)
    note over Database,Frontend: 响应流程
    Database->>Infrastructure: 返回PO<br/>e.g. UserEntity
    Infrastructure->>Infrastructure: PO → BO转换<br/>e.g. UserEntity → User
    Infrastructure->>domain: 返回BO
    domain->>application: 返回BO
    application->>application: BO → DTO转换<br/>e.g. User → UserResponse
    application->>web: 返回DTO
    web->>Frontend: 返回DTO/VO
    end

各层对象转换示例代码

  1. web(接收DTO,返回DTO)
@PostMapping("/users")
public UserResponse createUser(@RequestBody UserCreateRequest request) {

    User user = userConverter.toDomain(request); // DTO转BO

    User createdUser = userapplication.createUser(user);

    return userConverter.toResponse(createdUser); // BO转DTO

}
  1. application(使用BO)
public User createUser(User user) {

    // 业务逻辑处理
    user = userDomainapplication.create(user); // 调用领域服务
    return user;
}
  1. Infrastructure(BO与PO转换)
@Repository
public class UserRepositoryImpl implements UserRepository {

    @Autowired
    private UserMapper userMapper;

    @Override
    public User save(User user) {

        UserEntity entity = UserConverter.toEntity(user); // BO转PO

        userMapper.insert(entity);

        return UserConverter.toDomain(entity); // PO转BO

    }

}
  1. Converter(转换器)

  2. 通常放在infrastructure层(负责BO与PO的转换)和web层(负责BO与DTO的转换)。

  3. 也可以独立放在common模块,但要注意避免循环依赖。

总结:

  • 严格的分层和对象转换虽然增加了代码量,但提高了系统的可维护性和可扩展性。

  • 核心是保持domain层的纯净(只使用BO),避免技术细节污染业务逻辑。

  • 通过转换器(Converter)实现各层对象之间的转换,确保各层职责明确。

最佳实践示例

1. PO 定义 (基础设施层)

// infrastructure 模块
@Table(name = "t_user")
public class UserEntity {
    @Id
    private Long id;
    private String username;
    private String encryptedPassword;
    // 省略getter/setter
}

2. BO 定义 (核心层)

// domain 模块
public class User {
    private Long id;
    private String username;
    private Password password; // 值对象

    // 业务方法
    public void changePassword(String newPassword) {
        this.password = Password.create(newPassword);
    }
}

3. VO 定义 (Web层)

// web 模块
public class UserResponse {
    private Long id;
    private String name;
    private String avatarUrl;
    private LocalDateTime lastLoginTime;
    // 省略getter/setter
}

4. DTO 定义 (公共模块)

// common-dto 模块
public class PageRequest {
    private int pageNum = 1;
    private int pageSize = 10;
    // 计算偏移量
    public int getOffset() {
        return (pageNum - 1) * pageSize;
    }
}

5. 转换器 (基础设施层)

// infrastructure 模块
@Component
public class UserConverter {

    // PO -> BO
    public User toDomain(UserEntity entity) {
        User user = new User();
        user.setId(entity.getId());
        user.setUsername(entity.getUsername());
        user.setPassword(Password.fromEncrypted(entity.getEncryptedPassword()));
        return user;
    }

    // BO -> VO
    public UserResponse toResponse(User user) {
        UserResponse response = new UserResponse();
        response.setId(user.getId());
        response.setName(user.getUsername());
        response.setLastLoginTime(user.getLastLogin());
        return response;
    }
}

关键设计原则

  1. 单一职责
  2. PO 只负责数据库映射
  3. BO 只包含业务逻辑
  4. VO 只服务前端展示

  5. 层间隔离

  6. Controller 不应直接操作 PO
  7. application 不应返回 VO/DTO
  8. Repository 不应接收 BO

  9. 转换时机

    sequenceDiagram
        Controller->>application: DTO->BO
        application->>Repository: BO->PO
        Repository->>application: PO->BO
        application->>Controller: BO->VO

  10. 性能优化

  11. 使用 MapStruct 进行高效对象转换
  12. 避免在循环中进行转换
  13. VO 只包含前端需要的字段

通过这种严格的分层和对象分离,系统获得: - 核心业务与技术实现解耦 - 数据库变更不影响业务逻辑 - 前端展示独立演化 - 微服务间接口稳定