尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

【VO、DTO、Entity】VO、DTO、Entity三大核心数据对象全解析(附核心对比表 + 代码示例)

【VO、DTO、Entity】VO、DTO、Entity三大核心数据对象全解析(附核心对比表 + 代码示例) 文章目录VO、DTO、Entity一、核心总览1.1 核心本质1.2 架构分层全局映射1.3 拆分的核心价值二、Entity、DTO、VO单对象深度结构化拆解【重点】核心对比表2.1 Entity实体对象核心定位架构归属核心特征设计规范标准使用场景禁忌与反例2.2 DTOData Transfer Object数据传输对象核心定位架构归属核心特征设计规范标准使用场景禁忌与反例2.3 VOView Object视图对象核心定位架构归属核心特征设计规范标准使用场景禁忌与反例四、全链路数据流转与对象转换规范4.1 标准请求全链路流转流程出参链路数据从DB到前端入参链路数据从前端到DB4.2 转换边界与简化规则4.3 转换工具选型与规范五、核心设计原则与工程最佳实践5.1 核心设计原则5.2 工程化最佳实践六、高频误区与避坑指南七、扩展衍生数据对象体系区分如何在实际项目中应用VO、DTO、Entity一、项目结构先行分层包隔离二、单对象定义结合技术栈落地1. Entity实体对象与数据库强映射2. DTO数据传输对象场景化定制3. VO视图对象前后端交互专用三、全链路流转从请求到数据库的完整流程1. 用户新增流程前端 → 数据库2. 用户详情查询流程数据库 → 前端四、对象转换用 MapStruct 高效实现1. 引入依赖2. 定义转换器接口五、实际项目中的灵活简化六、避坑指南VO、DTO、Entity本文基于分层架构、DDD领域驱动设计与微服务工程实践全方位、结构化拆解VO、DTO、Entity的核心定义、架构定位、设计规范、流转规则、最佳实践与避坑指南形成完整的知识体系。一、核心总览1.1 核心本质VO、DTO、Entity 是企业级开发中分层架构下的领域数据载体均属于POJOPlain Old Java Object的细分类型核心设计目标是遵循单一职责原则解耦不同架构层级隔离数据模型的变化控制数据权限与边界是MVC三层架构、微服务架构、DDD领域驱动设计中的核心基础元素。1.2 架构分层全局映射从前端请求到数据库的全链路中三者的层级归属与核心边界如下架构层级核心职责关联核心对象前端视图层页面渲染与用户交互VO接口层/Controller层请求接入、参数校验、响应封装VO、DTO应用服务层/Service层业务流程编排、跨服务调用DTO领域层核心业务规则、领域能力Entity持久化层/Repository层数据库交互、数据持久化Entity/PO数据库数据存储表结构1.3 拆分的核心价值解耦隔离隔离不同层级的变化前端UI调整仅需修改VO表结构变更仅需修改Entity互不影响数据安全严格控制字段暴露范围避免密码、盐值等敏感字段通过接口泄露职责清晰每个对象仅服务于单一业务场景代码可读性、可维护性大幅提升团队协同前端仅需关注VO接口协议后端领域开发仅需关注Entity分工边界明确服务自治微服务场景下DTO隔离内部实现与外部接口避免表结构变更影响上下游服务。二、Entity、DTO、VO单对象深度结构化拆解【重点】核心对比表对比维度Entity实体对象DTO数据传输对象VO视图对象核心职责领域数据建模、数据库持久化映射跨层级/跨服务数据传输、协议隔离前端视图渲染、接口入参校验架构归属领域层、持久化层应用服务层、接口层接口层、视图层数据映射与数据库表结构一一对应匹配传输场景可组合多实体数据完全匹配前端页面展示需求唯一标识必须具备业务唯一主键ID无强制要求按需设计无唯一标识强制要求业务逻辑DDD充血模型可包含核心业务规则传统架构仅get/set严禁包含业务逻辑仅做数据载体严禁包含业务逻辑仅做视图封装生命周期与数据库会话绑定贯穿持久化全流程单次请求/调用内有效传输完成即销毁单次请求响应内有效渲染完成即销毁变更触发因素数据库表结构变更、核心业务规则调整传输场景需求变化、接口协议调整前端UI/交互需求变更校验规则持久化字段约束非空、长度、外键等跨系统传输的业务合法性校验前端入参的格式、合法性校验常见注解TableName/TableId/Column/Id等序列化注解、无强制专属注解NotBlank/NotNull等校验注解、JSON序列化注解对外暴露范围严禁暴露给前端/外部服务可暴露给内部服务、同服务跨层级仅暴露给前端2.1 Entity实体对象核心定位Entity是领域模型的核心载体与数据库表结构直接映射是业务数据的原子化封装具备唯一业务标识承载系统核心业务规则。在传统架构中常与POPersistent Object持久化对象同义在DDD架构中是领域层的核心资产。架构归属领域层、持久化层Repository/DAO层严禁跨层直接暴露给前端或外部服务。核心特征必须具备唯一业务标识通过主键ID区分不同实体哪怕字段完全一致ID不同则为两个不同实体与表结构强映射字段与数据库表字段一一对应是数据持久化的直接载体业务规则承载DDD充血模型中可封装与实体相关的核心业务行为如状态变更、字段校验传统贫血模型中仅包含get/set方法无业务逻辑生命周期与持久化绑定从数据库查询创建到持久化完成销毁与数据库会话强相关。设计规范类名通常以Entity/PO结尾如UserEntity、OrderPO字段必须与数据库表字段完全匹配非表字段必须标注忽略注解如TableField(exist false)必须定义唯一主键字段标注主键注解如TableId、Id禁止包含与持久化无关的前端展示、跨服务传输相关的冗余字段敏感字段如密码、身份证号必须做加密存储处理禁止明文存储。标准使用场景数据库查询结果的映射接收数据新增/修改时的持久化入参领域层核心业务规则的承载与计算同服务内Repository层与Service层之间的数据传递。禁忌与反例直接将Entity作为响应体返回给前端微服务跨服务调用时直接传递EntityEntity中包含大量非持久化字段未做忽略标注一个Entity对应多张表职责混乱。2.2 DTOData Transfer Object数据传输对象核心定位DTO是跨层级、跨服务的数据传输专用载体核心作用是隔离内部领域模型与外部交互接口仅负责数据的打包与传递不包含任何业务逻辑是不同系统/层级之间的“数据协议”。架构归属应用服务层、接口层可用于同服务内Controller与Service层之间也可用于微服务之间的远程调用。核心特征无状态纯数据载体仅包含字段、get/set方法严禁包含业务逻辑场景化定制一个DTO仅服务于一个特定的传输场景字段按需设计无需与Entity完全匹配解耦隔离隔离内部Entity的变化只要DTO协议不变内部Entity调整不会影响调用方生命周期短仅在单次请求/远程调用内有效传输完成即销毁。设计规范类名以DTO结尾同时标注场景如UserAddDTO、OrderDetailDTO、UserQueryDTO严禁一个DTO通吃所有场景字段仅包含当前传输场景必须的字段遵循最小化原则禁止冗余可根据传输需求组合多个Entity的字段如用户DTO中包含部门名称、角色名称等关联数据跨服务调用的DTO必须保持向后兼容禁止随意删除字段、修改字段类型。标准使用场景同服务内Controller层与Service层之间的入参/出参传递微服务之间的Feign/Dubbo远程调用的入参/出参消息队列MQ的消息体封装批量数据处理的中间载体CQRS架构中的Command写指令、Query查询指令均为DTO的细分类型。禁忌与反例DTO中封装业务逻辑、数据处理代码定义大而全的通用DTO服务于数十个接口字段冗余严重DTO与Entity字段100%一致无意义的重复定义跨服务DTO频繁变更导致上下游服务频繁适配。2.3 VOView Object视图对象核心定位VO是前端视图渲染的专用数据载体完全匹配前端页面的展示需求仅包含前端需要的字段与格式是后端返回给前端的最终数据封装彻底隔离内部业务模型与前端视图。架构归属接口层Controller层仅用于前端与后端接口的交互。核心特征视图强匹配字段、格式完全贴合前端页面的渲染需求与Entity无强制对应关系数据最小化仅包含前端必须的字段彻底剔除敏感字段、内部业务字段无业务逻辑仅做视图数据封装不包含任何业务处理代码序列化定制可根据前端需求定制JSON序列化规则如日期格式化、空值处理、枚举转换。设计规范类名以VO结尾标注场景如UserDetailVO、LoginResultVO、OrderListVO严格控制字段范围绝对禁止出现密码、盐值、内部状态码等敏感字段字段格式适配前端需求如日期格式化、金额单位转换、枚举值转义为前端可识别的文本入参VO必须添加JSR-380校验注解如NotBlank、NotNull、Size完成前端入参的合法性校验。标准使用场景后端接口返回给前端的响应体封装前端POST/PUT请求的表单入参接收前端分页列表、详情页、下拉选项等视图的数据封装。禁忌与反例VO中包含大量前端不需要的冗余字段直接将Entity/DTO不加处理地当作VO返回给前端VO中封装业务逻辑、数据计算代码多个完全不同的页面共用同一个VO导致字段冗余、校验混乱。四、全链路数据流转与对象转换规范4.1 标准请求全链路流转流程以用户详情查询接口为例完整的入参、出参链路如下出参链路数据从DB到前端Repository层执行查询将数据库结果映射为UserEntity包含全量字段Service层获取Entity关联查询部门、角色数据组装转换为UserDetailDTOController层获取DTO根据前端视图需求转换为UserDetailVO剔除敏感字段、格式化数据序列化VO为JSON返回给前端完成页面渲染。入参链路数据从前端到DB前端提交新增用户表单映射为UserAddVOController层完成入参校验校验通过后Controller将VO转换为UserAddDTO传递给Service层Service层执行业务逻辑密码加密、权限校验将DTO转换为UserEntityRepository层接收Entity执行数据持久化写入数据库。4.2 转换边界与简化规则强制不可省略的转换Entity绝对不能直接暴露给前端/外部服务必须经过DTO/VO的隔离转换可合并的场景单表简单CRUD、无业务逻辑、前端视图需求与传输需求完全一致时可将VO与DTO合并减少冗余代码禁止合并的场景跨服务调用、复杂业务场景、敏感数据处理、前端与内部字段需求差异较大时必须严格拆分VO与DTO。4.3 转换工具选型与规范工具核心特点适用场景避坑提示MapStruct编译期生成转换代码性能极高类型安全支持自定义转换规则中大型项目、高频转换场景优先使用避免运行期反射带来的性能损耗Spring BeanUtils基于反射性能中等使用简单小型项目、简单转换场景禁止使用Apache BeanUtils性能极差、有线程安全问题手动get/set性能最高完全可控字段少、转换规则复杂的场景避免大量重复代码优先使用MapStruct五、核心设计原则与工程最佳实践5.1 核心设计原则单一职责原则一个对象仅服务于一个业务场景如新增、修改、查询必须拆分不同的DTO/VO禁止通用对象开闭原则新增场景新增对象禁止修改已有对象的核心字段避免影响已上线链路字段最小化原则每个对象仅包含当前场景必须的字段严禁冗余字段分层隔离原则严禁跨层使用对象Controller层不能直接操作EntityRepository层不能使用DTO/VO向后兼容原则跨服务的DTO、对外暴露的VO新增字段可兼容禁止删除字段、修改字段类型。5.2 工程化最佳实践包结构隔离不同对象分不同包存放如entity、dto、vo职责清晰细分场景命名严格按照业务场景动作对象类型命名如UserUpdateDTO、OrderListVO禁止UserDTO这类模糊命名校验分层执行VO层做前端入参格式校验DTO层做业务合法性校验Entity层做持久化约束校验敏感字段处理VO中绝对禁止返回敏感字段如需传输必须做脱敏处理序列化定制VO/DTO中通过注解定制序列化规则如日期格式化、空值忽略、枚举转义避免循环依赖Entity之间的关联关系必须做懒加载处理DTO/VO禁止循环引用避免序列化异常。六、高频误区与避坑指南全链路共用一个对象最常见的坑Entity直接当DTO/VO用导致表结构暴露、敏感字段泄露、层级强耦合无意义的对象冗余VO与DTO字段100%一致重复定义导致代码冗余、维护成本翻倍大而全的通用对象一个DTO/VO包含几十个字段服务于多个接口导致接口文档混乱、字段冗余、校验失效传输对象包含业务逻辑DTO/VO中写入业务处理代码导致业务逻辑散落在各处难以维护与测试浅拷贝踩坑使用BeanUtils做对象转换时引用类型字段为浅拷贝修改会影响原对象导致数据异常Entity滥用Entity中包含大量非持久化字段未做忽略标注导致SQL执行报错、持久化异常微服务跨服务传Entity服务间直接传递Entity导致服务强耦合提供方表结构变更所有消费方都需适配违背微服务自治原则。七、扩展衍生数据对象体系区分企业级开发中除核心三类对象外还有多个衍生数据对象均为POJO的细分核心区分如下POPersistent Object持久化对象与数据库表一一对应纯数据载体无业务逻辑与传统贫血模型的Entity完全同义多数场景可互换DODomain Object领域对象DDD架构中的核心对象与Entity同义具备唯一标识封装核心业务规则为充血模型BOBusiness Object业务对象封装业务逻辑的组合对象由多个Entity/PO聚合而成用于Service层复杂业务处理目前多数场景下其职责已被充血Entity与DTO替代Query查询对象专门用于分页、条件查询的入参对象属于DTO的细分类型如UserQueryDTO包含分页参数、查询条件Command/QueryCQRS架构Command为写操作的DTO负责数据变更指令Query为读操作的DTO负责数据查询指令均属于DTO的细分场景。如何在实际项目中应用VO、DTO、Entity在实际项目中应用 VO、DTO、Entity需遵循分层架构、职责隔离、按需转换的原则结合具体技术栈如 Spring Boot MyBatis-Plus落地。以下是全流程实操指南含代码示例与最佳实践。一、项目结构先行分层包隔离先通过包结构明确三者的边界避免混乱com.example.project ├── controller # 接口层仅用 VO ├── service # 服务层用 DTO内部转 Entity │ └── impl # 服务实现 ├── mapper/repository # 持久层仅用 Entity ├── entity # 实体类数据库映射 ├── dto # 传输对象跨层/跨服务 │ ├── req # 请求型 DTO │ └── resp # 响应型 DTO └── vo # 视图对象前端交互 ├── req # 前端请求 VO └── resp # 前端响应 VO二、单对象定义结合技术栈落地1. Entity实体对象与数据库强映射以 MyBatis-Plus 为例Entity 直接对应表结构包含主键、字段映射注解// entity/User.javaDataTableName(sys_user)// 对应数据库表名publicclassUser{TableId(typeIdType.AUTO)// 主键自增privateLongid;TableField(username)// 对应表字段字段名一致可省略privateStringusername;privateStringpassword;// 敏感字段后续需加密privateStringphone;privateLocalDateTimecreateTime;TableField(existfalse)// 非表字段标注忽略privateStringtempField;}2. DTO数据传输对象场景化定制DTO 分请求型如新增、查询条件和响应型如服务间调用返回仅含场景必需字段// dto/req/UserAddDTO.java服务层新增入参DatapublicclassUserAddDTO{NotBlank(message用户名不能为空)privateStringusername;NotBlank(message密码不能为空)privateStringpassword;privateStringphone;}// dto/resp/UserDetailDTO.java服务层详情出参DatapublicclassUserDetailDTO{privateLongid;privateStringusername;privateStringphone;privateLocalDateTimecreateTime;// 可组合关联数据如部门名称privateStringdeptName;}3. VO视图对象前后端交互专用VO 需严格匹配前端需求入参做校验出参做脱敏/格式化// vo/req/UserLoginVO.java前端登录请求DatapublicclassUserLoginVO{NotBlank(message用户名不能为空)privateStringusername;NotBlank(message密码不能为空)privateStringpassword;}// vo/resp/UserDetailVO.java前端用户详情响应DatapublicclassUserDetailVO{privateLongid;privateStringusername;privateStringphone;JsonFormat(patternyyyy-MM-dd HH:mm:ss)// 日期格式化privateLocalDateTimecreateTime;// 敏感字段如密码绝对不出现}三、全链路流转从请求到数据库的完整流程以“用户新增”和“用户详情查询”为例展示三者的协作1. 用户新增流程前端 → 数据库// 1. Controller层接收VO转DTORestControllerRequestMapping(/user)RequiredArgsConstructorpublicclassUserController{privatefinalUserServiceuserService;PostMapping(/add)publicResultVoidaddUser(ValidRequestBodyUserAddVOuserAddVO){// VO → DTO使用MapStruct转换见下文UserAddDTOuserAddDTOUserConverter.INSTANCE.voToDto(userAddVO);userService.addUser(userAddDTO);returnResult.success();}}// 2. Service层接收DTO转Entity执行业务ServiceRequiredArgsConstructorpublicclassUserServiceImplimplementsUserService{privatefinalUserMapperuserMapper;OverridepublicvoidaddUser(UserAddDTOuserAddDTO){// DTO → EntityUseruserUserConverter.INSTANCE.dtoToEntity(userAddDTO);// 业务逻辑密码加密user.setPassword(PasswordUtil.encrypt(user.getPassword()));// 持久化userMapper.insert(user);}}// 3. Mapper层直接操作EntityMyBatis-PlusMapperpublicinterfaceUserMapperextendsBaseMapperUser{// 无需手写SQL直接继承BaseMapper}2. 用户详情查询流程数据库 → 前端// 1. Controller层接收VO如ID调用Service转VO返回GetMapping(/detail/{id})publicResultUserDetailVOgetUserDetail(PathVariableLongid){UserDetailDTOuserDetailDTOuserService.getUserDetail(id);// DTO → VOUserDetailVOuserDetailVOUserConverter.INSTANCE.dtoToVo(userDetailDTO);returnResult.success(userDetailVO);}// 2. Service层查询Entity组装DTOOverridepublicUserDetailDTOgetUserDetail(Longid){// 1. 查询EntityUseruseruserMapper.selectById(id);if(usernull){thrownewBusinessException(用户不存在);}// 2. Entity → DTOUserDetailDTOuserDetailDTOUserConverter.INSTANCE.entityToDto(user);// 3. 组装关联数据如查询部门名称userDetailDTO.setDeptName(deptService.getDeptNameByUserId(id));returnuserDetailDTO;}四、对象转换用 MapStruct 高效实现避免手动写get/set推荐使用MapStruct编译期生成代码性能高、类型安全1. 引入依赖dependencygroupIdorg.mapstruct/groupIdartifactIdmapstruct/artifactIdversion1.5.5.Final/version/dependencydependencygroupIdorg.mapstruct/groupIdartifactIdmapstruct-processor/artifactIdversion1.5.5.Final/versionscopeprovided/scope/dependency2. 定义转换器接口// converter/UserConverter.javaMapper(componentModelspring)// 注入Spring容器publicinterfaceUserConverter{UserConverterINSTANCEMappers.getMapper(UserConverter.class);// VO → DTOUserAddDTOvoToDto(UserAddVOuserAddVO);// DTO → EntityUserdtoToEntity(UserAddDTOuserAddDTO);// Entity → DTOUserDetailDTOentityToDto(Useruser);// DTO → VOUserDetailVOdtoToVo(UserDetailDTOuserDetailDTO);}五、实际项目中的灵活简化并非所有场景都需严格拆分三者可根据项目规模调整小型项目/单表CRUD可将 VO 与 DTO 合并如直接用UserReqVO当 Service 入参但 Entity 必须隔离无跨服务调用可省略 DTO直接用 VO 与 Entity 转换但需注意敏感字段复杂业务场景必须严格拆分甚至可新增 BO业务对象组装多 Entity 数据。六、避坑指南禁止直接返回 Entity哪怕字段一致也需转 VO避免后续表结构变更影响前端避免通用对象不要用一个UserDTO服务所有接口需按场景拆分如UserAddDTO、UserQueryDTO敏感字段处理VO 中绝对不能出现密码、身份证号等字段Entity 中需加密存储转换工具选型优先用 MapStruct避免用 Apache BeanUtils性能差、线程安全问题。
返回列表