PO、DTO、VO的区别与应用场景详解

在Java开发中,PO、VO、DTO是三个常见的设计模式概念,它们在数据流转过程中扮演着不同的角色。本文将结合实际项目代码,深入解析这三者的区别与应用场景。

核心概念定义

  • PO 放持久对象 主要用于 添加修改删除,一般情况下 对象中的字段和数据库 字段 需要一一对应
  • DTO 主要存放 数据传输对象 主要用于 查询 使用,对象中的字段一般不需要和数据库字段一一对应
  • VO 主要用于返回前端 对象 ,灵活选择那些数据需要返回前端,那些数据不需要返回前端, 更加安全,比如用户的密码 就不需要返回前端

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

定义与特点

PO是与数据库表结构一一对应的Java对象,主要用于数据的增删改操作。

代码示例(InvoiceApplyPo.java)

typescript 复制代码
public class InvoiceApplyPo implements Serializable {

    private String applyId;
    private String oiId;
    private String createUserId;
    private String ownerName;
    private String invoiceType;
    private String applyTel;
    private String invoiceAmount;
    private String createUserName;
    private String remark;
    private String statusCd = "0";
    private String state;
    private String communityId;
    private String invoiceCode;

    // 完整的getter/setter方法
    public String getApplyId() {
        return applyId;
    }

    public void setApplyId(String applyId) {
        this.applyId = applyId;
    }
    
    // 其他属性的getter/setter方法...
}

应用场景

  • 与数据库交互时使用,特别是执行增删改操作

  • ORM框架(如MyBatis、Hibernate)中的实体类

  • 保持数据与数据库的一致性

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

定义与特点

DTO用于系统内部各层之间的数据传输,特别是查询操作,字段不需要与数据库一一对应,可以根据业务需求灵活组合字段。

代码示例(RoomDto.java)

typescript 复制代码
public class RoomDto extends PageDto implements Serializable {
    
    // 常量定义
    public static final String STATE_SELL = "2001"; // 已入住
    public static final String STATE_FREE = "2002"; //未销售
    // 更多常量定义...

    // 基本属性
    private String feeCoefficient;
    private String section;
    private String remark;
    private String userId;
    private String roomId;
    private String[] roomIds; // 数组类型,数据库中不存在
    private String layer;
    private String[] layers; // 数组类型,数据库中不存在
    // 更多属性...

    // 集合属性
    private List<RoomAttrDto> roomAttrDto;
    private List<FeeDto> fees;

    // 日期属性
    private Date createTime;
    private Date startTime;
    private Date endTime;

    // getter/setter方法
    public String getFeeCoefficient() {
        return feeCoefficient;
    }

    public void setFeeCoefficient(String feeCoefficient) {
        this.feeCoefficient = feeCoefficient;
    }
    
    // 其他属性的getter/setter方法...
}

应用场景

  • 服务层之间的数据传递

  • 复杂查询结果的封装

  • 多表关联查询数据的组合

  • 支持分页查询(继承自PageDto)

3. VO(View Object)- 视图对象

定义与特点

VO专门用于前端视图层的数据展示,控制哪些数据需要返回给前端,哪些数据需要屏蔽,提高数据安全性。

代码示例(FeeDetailResultVo.java)

csharp 复制代码
public class FeeDetailResultVo extends ResultVo implements Serializable {

    private double totalReceivedAmount;
    private double totalReceivableAmount;

    // 无参构造函数
    public FeeDetailResultVo() {
    }

    // 带参构造函数,方便直接封装返回数据
    public FeeDetailResultVo(double totalReceivableAmount, double totalReceivedAmount, 
                           int records, int total, Object data) {
        this.totalReceivableAmount = totalReceivableAmount;
        this.totalReceivedAmount = totalReceivedAmount;
        this.setCode(CODE_OK);
        this.setMsg(MSG_OK);
        this.setRecords(records);
        this.setTotal(total);
        this.setData(data);
    }

    // getter/setter方法
    public double getTotalReceivedAmount() {
        return totalReceivedAmount;
    }

    public void setTotalReceivedAmount(double totalReceivedAmount) {
        this.totalReceivedAmount = totalReceivedAmount;
    }
    
    // 其他属性的getter/setter方法...

    // 重写toString方法,用于JSON序列化
    @Override
    public String toString() {
        return JSONObject.toJSONString(this, 
                SerializerFeature.DisableCircularReferenceDetect, 
                SerializerFeature.WriteDateUseDateFormat);
    }
}

应用场景

  • 接口返回给前端的数据封装

  • 屏蔽敏感信息(如用户密码)

  • 组装前端所需的各种展示数据

  • 格式化数据展示(如日期格式化)

4. 三者对比与关系

数据流转关系

在一个典型的Web应用中,数据流转过程通常如下:

  1. 请求处理:控制器接收前端请求

  2. 业务处理:服务层处理业务逻辑,可能需要查询数据库3.

  3. 数据查询:通过DAO层查询数据库,返回PO对象

  4. 数据转换:将PO转换为DTO,可能组合多个PO的数据

  5. 响应封装:将DTO转换为VO,添加状态码、消息等信息

  6. 响应返回:将VO序列化为JSON返回给前端

5. 最佳实践

  1. 严格分层使用:在项目中明确规定各层使用的对象类型,不要混用
  2. 数据转换工具:使用MapStruct、Dozer等工具简化对象之间的转换
  3. 命名规范:统一使用XxxPo、XxxDto、XxxVo的命名方式
  4. 避免贫血模型:可以在DTO和VO中添加简单的业务方法,但保持PO的纯粹性
  5. 安全性保障:在VO中确保不包含敏感信息,特别是用户凭证类数据

总结

PO、VO、DTO虽然都是Java对象,但在应用中承担着不同的角色和职责。合理使用这三种对象模式,可以使代码结构更加清晰,提高系统的可维护性和安全性。在实际开发中,我们需要根据具体业务场景选择合适的对象类型,并建立规范的转换机制,确保数据在不同层之间的安全、高效流转。

相关推荐
灰子学技术1 小时前
go response.Body.close()导致连接异常处理
开发语言·后端·golang
Gogo8162 小时前
BigInt 与 Number 的爱恨情仇,为何大佬都劝你“能用 Number 就别用 BigInt”?
后端
fuquxiaoguang2 小时前
深入浅出:使用MDC构建SpringBoot全链路请求追踪系统
java·spring boot·后端·调用链分析
毕设源码_廖学姐3 小时前
计算机毕业设计springboot招聘系统网站 基于SpringBoot的在线人才对接平台 SpringBoot驱动的智能求职与招聘服务网
spring boot·后端·课程设计
野犬寒鸦4 小时前
从零起步学习并发编程 || 第六章:ReentrantLock与synchronized 的辨析及运用
java·服务器·数据库·后端·学习·算法
逍遥德5 小时前
如何学编程之01.理论篇.如何通过阅读代码来提高自己的编程能力?
前端·后端·程序人生·重构·软件构建·代码规范
MX_93596 小时前
Spring的bean工厂后处理器和Bean后处理器
java·后端·spring
程序员泠零澪回家种桔子6 小时前
Spring AI框架全方位详解
java·人工智能·后端·spring·ai·架构
源代码•宸7 小时前
大厂技术岗面试之谈薪资
经验分享·后端·面试·职场和发展·golang·大厂·职级水平的薪资
晚霞的不甘8 小时前
CANN 编译器深度解析:UB、L1 与 Global Memory 的协同调度机制
java·后端·spring·架构·音视频