关于DTO、DO、BO、VO

一、参考文章

二、详解

这些都不是强制性要求,只是一个规范,比如对于一个比较小的系统,强制增加分层对象,可能各个分层对象之间的转换成了最繁琐的事情

典型分层架构使用对象:

复制代码
Controller (Web层) 
    ↓ VO/Request/Response
Service (业务层)
    ↓ BO/DTO
Manager/Repository (数据访问层)
    ↓ DO/Entity
Database (数据库层)

典型数据流转:

复制代码
前端 Request/Response ↔ VO ↔ Controller
                              ↓
                    Service ↔ DTO ↔ BO
                              ↓
              Repository ↔ DO ↔ Database

转换方法示例:

java 复制代码
// VO ↔ DTO 转换
public class OrderConverter {
    public static OrderVO toVO(OrderDTO dto) { ... }
    public static OrderDTO toDTO(OrderVO vo) { ... }
}

// DTO ↔ BO 转换
public class OrderBO {
    public static OrderBO fromDTO(OrderDTO dto) { ... }
    public OrderDTO toDTO() { ... }
}

// BO ↔ DO 转换
public class OrderBO {
    public OrderDO toDO() { ... }
    public static OrderBO fromDO(OrderDO do) { ... }
}

1、VO (View Object) - 视图对象

概述:

VO (View Object),用于表示一个与前端进行交互的视图对象,它的作用是把某个指定页面(或组件)的所有数据封装起来。实际上,这里的 VO 只包含前端需要展示的数据,对于前端不需要的数据,比如数据创建和修改的时间等字段,出于减少传输数据量大小和保护数据库结构不外泄的目的,不应该在 VO 中体现出来

使用场景:

  • 前端展示层:专门为前端界面设计的数据结构

  • API 响应:Controller 返回给前端的数据

  • 页面渲染:JSP/Thymeleaf 等模板引擎使用

典型例子:

java 复制代码
// 用户列表页面的 VO
public class UserListVO {
    private Long userId;
    private String userName;
    private String statusName;        // 状态中文名
    private String createTimeStr;     // 格式化后的时间
    private Boolean canEdit;          // 是否可编辑(业务权限)
    private String avatarUrl;         // 头像完整URL
}


// controller层
public class xxxController {
    @PostMapping("/query")
    public Result<UserListVO> query(@RequestBody xxxParam param) {
        // 返回 VO 给前端
    }
}

2、DO (Data Object) - 数据对象

概述:

DO(Data Object) ,持久化对象,它跟持久层(Dao)的数据结构形成一一对应的映射关系。如果持久层是关系型数据库,那么数据库表中的每个字段就对应PO的一个属性,常是entity实体类。

使用场景:

  • 数据库映射:与数据库表一一对应

  • ORM 框架:MyBatis/JPA 的实体映射

  • 数据持久化:直接操作数据库的对象

典型例子:

java 复制代码
@TableName("user")
public class UserDO {
    private Long id;
    private String name;
    private String email;
 
    // getters and setters
}

3、BO (Business Object) - 业务对象

概述:

BO(Business Object):业务对象,就是从现实世界中抽象出来的有形或无形的业务实体。

使用场景:

  • 复杂业务逻辑:封装核心业务规则和计算

  • 聚合根:DDD 中的聚合根对象

  • 状态管理:管理复杂的业务状态

  • 业务验证:包含业务验证逻辑

典型例子:

java 复制代码
// 复杂业务逻辑的 BO
public class OrderBO {
    private Long orderId;
    private OrderStatus status;
    private List<OrderItemDTO> items;
    private CustomerDTO customer;
    
    // 业务方法
    public boolean canCancel() {
        return status == OrderStatus.PENDING 
            && createTime.isAfter(LocalDateTime.now().minusHours(24));
    }
    
    public BigDecimal calculateTotalWithDiscount() {
        BigDecimal total = items.stream()
            .map(OrderItemDTO::getSubtotal)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
            
        return applyCustomerDiscount(total, customer.getVipLevel());
    }
    
    public void processPayment(PaymentDTO payment) {
        validatePaymentAmount(payment);
        updateOrderStatus();
        sendNotification();
    }
  
  // 包含复杂的业务逻辑和数据转换
    public static BillingDetailBO of(...) { ... }
    public OrderDTO get() { ... }
}

4、DTO (Data Transfer Object) - 数据传输对象

概述:

DTO(Data Transfer Object),用于表示一个数据传输对象,DTO 通常用于展示层(Controller)和服务层(Service)之间的数据传输对象。DTO 与 VO 概念相似,并且通常情况下字段也基本一致。但 DTO 与 VO 又有一些不同,这个不同主要是设计理念上的,比如 API 服务需要使用的 DTO 就可能与 VO 存在差异。

使用场景:

  • 跨层传输:Service 层之间的数据传递【主要】

  • 跨服务调用:微服务之间的数据传输

  • RPC 调用:远程过程调用的参数和返回值

  • 缓存对象:Redis 等缓存中存储的数据结构

典型例子:

java 复制代码
public class UserDTO {
  private Long id;
  private String displayName;

  public UserDTO(UserBO userBO) {
    this.id = userBO.getUserDO().getId();
    this.displayName = userBO.getUserDO().getName();
  }
}


// service 层中的传递
@Service
public class UserService {
  @Autowired
  private UserRepository userRepository;

  public UserDTO getUserDetails(Long userId) {
    UserDO userDO = userRepository.findById(userId).orElse(null);
    UserBO userBO = new UserBO(userDO);
    UserDTO userDTO = new UserDTO(userBO);
    return userDTO;
  }

5、应用示例

Controller 层:

java 复制代码
@RestController
public class OrderController {
    
    @PostMapping("/create")
    public Result<OrderVO> createOrder(@RequestBody CreateOrderRequest request) {
        // Request → DTO 转换
        OrderDTO orderDTO = convertToDTO(request);
        
        // 调用 Service
        OrderDTO result = orderService.createOrder(orderDTO);
        
        // DTO → VO 转换
        OrderVO orderVO = convertToVO(result);
        return Result.success(orderVO);
    }
}

Service 层:

java 复制代码
@Service
public class OrderService {
    
    public OrderDTO createOrder(OrderDTO orderDTO) {
        // DTO → BO 转换(复杂业务逻辑)
        OrderBO orderBO = OrderBO.createFromDTO(orderDTO);
        
        // 业务逻辑处理
        orderBO.validateOrder();
        orderBO.calculatePrice();
        orderBO.applyPromotions();
        
        // BO → DO 转换
        OrderDO orderDO = orderBO.toDO();
        
        // 保存到数据库
        orderRepository.save(orderDO);
        
        // DO → DTO 返回
        return OrderDTO.fromDO(orderDO);
    }
}

Repository/Dao 层:

java 复制代码
@Repository
public class OrderRepository {
    
    public OrderDO save(OrderDO orderDO) {
        // 直接操作数据库
        return orderMapper.insert(orderDO);
    }
    
    public List<OrderDO> findByPatientId(Long patientId) {
        // 返回 DO 对象
        return orderMapper.selectByPatientId(patientId);
    }
}

六、特殊场景的选择

1.简单CRUD场景

复制代码
// 可以简化,跳过 BO
Controller → Service → DTO → Repository → DO

2.复杂业务场景

复制代码
// 必须使用 BO 封装业务逻辑
Controller → VO → Service → DTO → BO → Repository → DO

3.微服务调用

复制代码
// 服务间只传输 DTO
ServiceA → DTO → RPC → ServiceB

4.报表展示

复制代码
// 重点使用 VO 进行数据格式化
Service → DTO → ReportVO (包含格式化数据)
相关推荐
快乐肚皮1 分钟前
IntelliJ IDEA Debug 模式功能指南
java·ide·intellij-idea·debug
_風箏18 分钟前
SpringBoot【ElasticSearch集成 02】Java HTTP Rest client for ElasticSearch Jest 客户端集成
java·后端·elasticsearch
野犬寒鸦32 分钟前
力扣hot100:字母异位词分组和最长连续序列(49,128)
java·数据结构·后端·算法·哈希算法
浮游本尊34 分钟前
Java学习第14天 - 微服务架构与Spring Cloud
java
燃尽余火39 分钟前
Knife4j 文档展示异常的小坑
java·开发语言·spring
渣哥1 小时前
如果没有双亲委派,Java 会乱成什么样?
java
jokr_1 小时前
C++ STL 顶层设计与安全:迭代器、失效与线程安全
java·c++·安全
Code_Artist1 小时前
[Java并发编程]6.并发集合类:ConcurrentHashMap、CopyOnWriteArrayList
java·后端·源码阅读
爬虫程序猿1 小时前
利用 Java 爬虫按关键字搜索 1688 商品详情 API 返回值说明实战指南
java·开发语言·爬虫
前端赵哈哈2 小时前
初学者入门:Android 实现 Tab 点击切换(TabLayout + ViewPager2)
android·java·android studio