POJO/DTO/DO/EO/VO/BO/PO/AO的含义和使用

2023-11-05

关于POJO/DTO/DO/EO/VO/BO/PO/AO

本文讨论 POJO/DTO/DO/EO/VO/BO/PO/AO 的定义,另外讨论了这些xO在controller、service、dao/mapper层里的使用规范。另外还稍微讨论了controller中是否要 “轻逻辑”,mapper接口的规范等等问题。

前言

在我们的java项目中存在各种xO的概念,如POJO/DTO/DO/EO/VO,还有些后端开发可能不太常见的BO/PO/AO。这里结合阿里Java手册以及其他博客的知识总结一下。这些xO一般都具有简单的结构,如setter/getter/toString

  • POJO:Plain Old/Ordinary Java Object,是其他xO的统称。笔者也喜欢用bean来统称这些xO,但后来觉得不准确,因为bean一般指spring容器所管理的bean
  • DTO:Data Transfer Object,用来作为Controller的出参和Service的出参。一般分为两类:Controller的入参叫xxxReqDTO,Service层的出参叫xxxRespDTO。也有很多系统并不分得这么细。
  • DO:Data Object,用来和单表一一对应的实体类。也有资料显示DO是Domain Object(域对象),
    • EO:Entity Object,实体对象。有些公司用来表示跟表一一对应的类,即相当于DO。
    • PO:记得最初的阿里Java文档定义为Persistence Object,持久化对象,当时文档说是跟表一一对应的,不知道后来的文档为什么改成了DO(难道记错了?)
  • VO:View Object,阿里Java文档中说用来跟前端页面一一对应的对象。偶尔会有用错的情形,比如用来作为Controller层的入参
  • BO:Business Object,阿里Java文档说明由 Service 层输出的封装业务逻辑的对象。不理解
  • AO:Application Object,应用对象,不知道什么用。

其实搞这么多xO,有时候真的会影响效率,尤其非大型公司需要快。

【阿里Java手册】
POJO(Plain Ordinary Java Object): 在本手册中,POJO 专指只有 setter/getter/toString 的简单类,包括 DO/DTO/BO/VO 等。
DO(Data Object):此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
DTO(Data Transfer Object):数据传输对象,Service 或 Manager 向外传输的对象。
BO(Business Object):业务对象,由 Service 层输出的封装业务逻辑的对象。
AO(Application Object):应用对象,在 Web 层与 Service 层之间抽象的复用对象模型,极为贴 近展示层,复用度不高。
VO(View Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象。
Query:数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装,禁止使用 Map 类来传输。

总结:这么多O,都搞晕了,感觉常用的就只有DTO;和表一一对应的类要不要后缀都不是很重要,所以DO也不是说很常用(当然有更好,能快速识别)

xO 的使用方法

总结:controller入参用dto,出参也是dto(从service层返回的);service层入参是dto,出参dto;dao层入参不建议用dto而是分拆,出参dto或do。dao层接口不要用map作为入参,有不用map和list作为出参。

  • http(s) 传参的方式

    常见如下

    • 键值对:Content-Type 是 x-www-form-urlencoded 。准确说是 “名值对”,因为是可以重复的,如 ?favor=music&favor=reading 中的favor。

      特殊情况

      • 键值对传文件:Content-Type 是 form-data。跟 “键值对” 不同之处是可传文件
    • 传 JSON:Content-Type 是 application/json。注意和 “传JSON字串” 的表述区分开,后者是键值对的传参方式 ?jsonStr={}

    • 路径参数:如 /user/9527,中的 9527 是路径参数

  • Controller 入参

    • 参数少:采用 “键值对” 和 “路径参数”
    • 参数多、结构复杂:采用 “传JSON”。一般用 xxxReqDTO 接收
      • 注意:有时不区分这么细,将 xxxReqDTO 和 xxxRespDTO 合并用同一个,叫 xxxDTO
      • “传JSON” 的同时也可以使用键值对方式。即JSON字串在请求方法体里,键值对参数追加在URL
  • Controller 出参

    • 出参格式
      • 一般总是返回200的 http 状态码,并用固定的返回类封装起来,例如 ResponseDTO
      • ResponseDTO 一般带有系统自定义的业务异常码、信息提示、时间、数据
    • 出参从 Service 层获得,一般不再二次处理,直接放在 ResponseDTO 的 “数据” 里。
    • 无出参用 ResponseDTO
  • Service 层的入参

    • 接收Controller层传入的简单类型或者 xxxReqDTO(或 xxxDTO)
  • Service 层的出参

    • 出参简单的,直接返回:如基本类型、包装类和String等

    • 出参复杂的,返回 xxxRespDTO(或 xxxDTO)

      • 注意:“返回 xxxRespDTO” 的表述也包括 List、PageInfo、Map<String, xxxRespDTO>等形式,下文不再赘述
    • 反例:

      • 【禁止】有时贪快,用DO 作为出参,是不好的实践,必须用 DTO
      • 【疑惑】是不是每个Service接口都要定义自己的 DTO,DTO 可以跨不同的 Service 接口复用吗? 这个真的很纠结,复制一份DTO比较独立但是代码却重复非常多,用继承又导致复杂化不直观
  • Dao 层(Mapper)的入参

    • 简单和复杂的参数都分拆成基本类型、包装列和String等
      • insert接口或update接口会有很多字段,全列出来会不会很麻烦? 这些接口的sql不太可能自己写,因为代码生成框架可以自动生成的,所以不麻烦
      • 【建议】建议别用 Service 层的 xxxReqDTO(或 xxxDTO)作为入参,因为通常并非DTO里的所有字段在sql里会用到
      • 【疑惑】其实这个还是有点纠结的,要不要定义一个 xxxQuery 作为 mapper的查询入参?
    • 反例:
      • 【禁止】禁止入参用 Map
      • 【建议】建议入参也别用 xxxDO,因为xxxDO势必有很多字段其实并不是sql里需要的
  • Dao 层(Mapper)的出参

    • 简单的直接返回
    • 复杂的返回 xxxRespDTO(或xxxDTO)
      • 【建议】能不能用 xxxDO 作为mapper的出参? 这块不强制禁止,因为生成的sql就是返回这些的
    • 反例:禁止出参用 Map 或 List

其他思考

  • controller层:对此层大家的共识是不要写重的逻辑。但是要轻逻辑到什么程度? 比如我比较喜欢的一种方式是接口参数校验在参数声明中进行,但controller的方法的大括号里仅仅有一行调用service层的代码。这种方式把参数的进一步校验也交给service了。其实这种做法虽然很简洁,但是可能很难复用service层的接口。所以,是不是可以保证controller层有轻的 “分发” 性质的代码? 例如一个接口既可以新增也可以修改,在controller层里判断operType,新增的话分发到新增的service接口里,修改的话分发到修改的service接口里。
  • controller里的RequestMapping,一般可能叫 “路由”、“路由地址”,这可能是来源于前端router的概念;其实也可以叫endpoint(端点),这个称呼更加显得后端
  • 其实我不太建议用 “路径参数”,会容易混淆
@GetMapping("/user/list")
public List<ListUserDTO> listUser(String name) {}@GetMapping("/user/{name}")
public List<ListUserDTO> listUser2(@PathVariable("name") String name) {}
  
会符合 "精确匹配优先" 的原则,即访问/user/list匹配上面的,假设有个name是 "list" 值的,就没办法调用到下面的方法;如果是非 "list",则匹配下面的方法。

------------------------------

@GetMapping("/user/{name}")
public List<ListUserDTO> listUser2(@PathVariable("name") String name){}

@GetMapping("/user/{id}")
public QueryUserDTO queryUser(@PathVariable("id") Integer id){}

这两个方法能正常启动springboot,但是只有在运行时抛出异常,即无法确认要匹配哪个方法。因为前端的传参本质上是没有字串和整形的区分的,本质都是字串,只是在spring框架里如需要会进行转换。

* dao层的mapper接口真的不建议使用pojo作为入参,强烈建议把字段分拆成基本类型、包装类和String即可。原因是:1、这样清晰一点;2、一般入参的个数不会很多,比较多入参的insert接口都交给了代码生成,完全不需要自己写这样的sql。3、pojo作为入参,比如这个pojo是service层传如的xxxReqDTO,但是这个dto里并非所有字段都是sql里的条件,所以这会造成不好维护。
* dao层的mapper更加不建议用map作为入参,看似灵活,实际过于灵活导致难以分析真正传入的参数
* dao层的mapper接口出参也不建议用Map<String, Object> 或 List<Map<String, Object>>,看似灵活,实际也是过于灵活导致很难维护,比如从map中get值,key写错时很难发现。我们希望在编码的早期阶段尽快暴露出这些bug
* service层的接口是可以调用其他同是service层的接口的。有时候为了共用接口,确实会有这样的需要。那被共用的接口是否要提取到类似CommonService里呢?  我建议是不需要不强制。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

POJO/DTO/DO/EO/VO/BO/PO/AO的含义和使用 的相关文章

  • 多态对象的 JSON 使用者

    我正在解析 JSON 并且很难理解一种可以具有三种形式之一的结构 就我而言 它可以是零维 一维或二维 有什么方法可以即时检查 JSON 以确定它是哪一个吗 或者也许无论如何都要吃掉它 然后再弄清楚它是什么 这些结构看起来像这样 并且可以嵌入
  • 具有动态 localName 值的 JacksonXmlRootElement

    我正在更新一个POJO我们映射到XML唯一的区别是有人想要旧的XML还有一些新的 唯一的区别是根包装器名称 所有相同的字段 例如当前根 Xml 标记设置为ExistingName他们想要一个新的值 比如BrandNewName具有所有相同的
  • 对于具有大量字段的对象,是否有更好的方法来实现 Equals?

    也可以看看C 中如何快速检查数据传输的两个对象是否具有相同的属性 我有很多数据传输对象 DTO 每个对象都包含很多简单的字段 我需要对所有这些实现 Equals 这样我就可以编写一些单元测试来传输它们 var WCF 我正在使用的代码是 p
  • 为什么 ToOptimizedResult 会抛出“请求的功能未实现”。在单声道上?

    我正在使用 Visual Studio 构建 ServiceStack 4 0 8 服务 在 Windows 上一切正常 但当我尝试在 Mono 2 10 8 1 Ubuntu 13 10 上运行 NGINX 1 4 1 和 fastcgi
  • 创建一个映射来调用 Spark Dataframe 的每一行的 POJO

    我在 R 中构建了一个 H2O 模型并保存了 POJO 代码 我想使用 POJO 在 hdfs 中对 parquet 文件进行评分 但我不知道如何去做 我计划将 parquet 文件读入 Spark scala SparkR PySpark
  • 使用 MapStruct 将抽象类映射到 DTO

    我发现了很多与此相关的主题 但在我看来 所有解决方案都走向了错误的方向 那么 在这种情况下我该如何使用 MapStruct 映射 抽象类人 public abstract class Person implements Serializab
  • 我的 ASP.NET MVC 应用程序结构是否正确?

    我已经阅读了教程 特别是使用 Linq To Entities 的教程 并且了解基本概念 但是有些事情给我带来了问题 这些教程通常只涉及简单的模型和表单 仅使用基本的创建 更新和删除语句 我的有点复杂 我不确定我是否以正确的方式处理这个问题
  • XML 和 JSON Web api:从 POJO 自动映射?

    我即将开始一个小项目 其目标是最终得到一个 Web xml json api 我将用 Java 编写它 并使用 Restlet 库 如何处理 xml json 二元性 我知道我可以使用 JAXB 将 pojos 转换 为 xml 并返回 但
  • 使用 DTO 时,Automapper 和 Nhibernate 反映正在更新的域对象中 DTO 子集合的更改

    我对这个设计不是很熟悉 但我希望得到一些指导 我有一个后端服务 它将 DTO 发送到 WPF 智能客户端 在 WPF 智能客户端上 用户将更改 删除和修改项目 然后将更改发送回 客户端 gt 服务器 举个例子 目前我正在处理客户详细信息表单
  • POCO、DTO、DLL 和贫血域模型

    我正在看POCO和DTO的区别 https stackoverflow com questions 725348 poco vs dto 看起来 POCO 是具有行为 方法 的 dto 并遇到本文 http www martinfowler
  • Java EE DAO / DTO(数据传输对象)设计模式

    目前 我正在为我的工作项目使用 struts2 框架 在设计我的 DAO 类时 我心中有一个改进设计模式的问题 在我的搜索功能上 我有3种搜索 使用一个参数和另一个参数进行搜索 使用多个参数进行搜索 不带参数搜索 我的问题是 做DAO方法最
  • DDD:Dto 汇编器应该是域层的一部分吗?

    提前致谢 我有一些骨料 in the 领域层图书馆 另外 一些DTO位于一个单独的库中 该库在之间共享Server and Client side An 总计的实体的信息量比其本身的信息量更丰富DTO 所以 为了从DTO to 总计的 a
  • 我应该在 DTO 中使用构建器模式吗?

    这可能是一个相当主观的问题 但我想知道更多的意见 我使用 Spring MVC 构建了 Rest API 服务 并实现了 DTO 域 实体模式 我想知道您对实施该法案有何看法建造者模式 https en wikipedia org wiki
  • 如何使用 MapStruct 将字符串转换为映射?

    I have Story我的 Spring Boot 应用程序中的实体 它有String field storyInfo其中包含 title random title description random description For m
  • 如何在jackson json反序列化中跳过包装对象

    我正在尝试使用 Jackson 反序列化以下字符串 roomName u8ec29p0j7q2m9f broadcastPresenceRoles broadcastPresenceRole moderator participant vi
  • REST API - 是否 DTO? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我目前正在为一个项目创建 REST API 并且一直在阅读有关最佳实践的文章 许多人似乎反对 DTO 只是简单地公开域模型 而其他人似乎认为 D
  • DTO 接口

    我目前正在开始开发一个大型 Web 应用程序 主要包含 Angular SPA 和可以访问后端层的 OData WebAPI 我们正处于早期阶段 并已开始实施第一批课程 包括Model dll它位于公共名称空间中 以便所有层都可以访问它 我
  • Jersey 2.0 和 Moxy 内部服务器错误但没有服务器日志

    我遵循了 Jersey 2 0 文档 https jersey java net documentation latest user guide html json moxy https jersey java net documentat
  • ServiceStack操作命名约定可以被覆盖吗?

    我需要为 ServiceStack 服务定义一个 DTO 类 服务堆栈使用基于类名的约定 因此如果我的类称为 Transmission 则相应的服务将使用 HTTP 操作中使用的类型为 Transmission 的公开元数据 但我已经有了
  • 如何将 sqldatareader 转换为 dto 列表?

    我刚刚开始将所有 ado net 代码从 asp net 页面移动到存储库 并为每个表创建 dto 手动 但现在我不知道将 sqldatareader 转换为我的列表的有效方法是什么dto 对象 例如 我的 dto 是 Customer 我

随机推荐

  • UNIAPP实战项目笔记30 购物车内容块布局

    UNIAPP实战项目笔记30 购物车内容块布局 主要代码 主要代码 shopcart vue
  • 【网络工程师实战教学】华为ENSP模拟器——NAT配置实验详解_必看干货!

    NAT Network Address Translation 网络地址转换 是将IP数据报文中的IP地址转换为另一个IP地址的过程 当内部IP想要访问外网时 NAT主要实现内部网络和外部网络之间IP的转换 这种通过使用少量的公网IP地址代
  • 剑指offer题解(C++版)

    CSDN话题挑战赛第2期 参赛话题 算法题解 一 常见数据结构 1 数组 3 找出数组中重复的数字 4 二维数组中的查找 5 替换空格 29 顺时针打印矩阵 leetcode 989 数组形式的整数加法 leetcode26 删除有序数组中
  • Python字典使用教程:Python字典常用操作方法

    1 python字典是什么 无论是参加Python培训还是自学 都会接触到Python字典这一章节 字典是Python中比较常用的数据结构 字典中每个成员是以 键 值 对的形式存放具有映射关系的数据 2 Python如何创建字典 字典语法
  • Latex之公式太长跨页

    文章目录 公式环境 跨页公式 公式环境 跨页公式 写毕业论文的过程中 难免会出现较长的公式 如果这个公式恰好是上一页放不下 放到下一页的话 上一页又空一大片 这样就很不美观了 本文介绍对这种公式的处理办法 第一步 在导言区加上命令 allo
  • Qt窗口程序设计

    转载自https blog csdn net lbb2016 article details 52509645 感谢博主 用Qt Creator编写一个简单的窗口程序 这次编写的窗口程序的效果图如下 这个小程序的功能是 在文本框中输入半径
  • Windows建立UDP的客户端和服务端

    一 UDP的服务端建立 udp服务端创建的步骤 1 加载库 2 创建套接字 3 绑定IP地址 4 接收数据 5 发送数据 6 关闭套接字 卸载库 代码如下 include
  • 你必须要记住的动态内存管理函数

    问题引入 首先我们要明白为什么要动态内存分配 这是因为我们所熟知的内存开辟方式通常有两个特点 1 空间开辟大小是固定的 2 数组在声明时 必须指定数组的长度 他所需要的内存在编译的时候分配 但是由于我们对空间的需求多种多样 有时候我们需要的
  • 服务器虚拟机ping不通百度,未知的名称或服务,解决方法

    ping不通百度 未知的名称或服务 解决方法 route添加一条路由 需要先安装net tools工具包 root localhost yum install net tools y root localhost route n Kerne
  • 拉格朗日函数与广义拉格朗日函数

    拉格朗日函数用来求解等式约束的最优化问题 广义拉格朗日函数用来求解不等式约束的最优化问题 无约束优化问题 关于优化问题包括无约束优化问题 等式约束优化问题 不等式约束优化问题 这里简略地介绍一下无约束优化问题 以后再来填坑 考虑无约束优化问
  • TypeError: ‘tuple‘ object does not support item assignment

    TypeError tuple object does not support item assignment 原因 修改了tuple 而tuple是不支持修改的 或者说tuple不支持直接修改 解决方法 定义一个临时变量temp temp
  • Docker日志查看命令

    docker容器列表查看 docker ps 日志查看语法 docker logs OPTIONS CONTAINER OPTIONS说明 f 跟踪日志输出 since 显示某个开始时间的所有日志 t 显示时间戳 tail 仅列出最新N条容
  • 2022十三届蓝桥杯国赛题解

    特此声明 本文仅为参考文档 标准答案请参考官方文档 试题A 该题是一道背包dp题 我的思路是定义三维dp 第一维表示第i个数 第二维表示前i个数的总和为j 第三维表示前i个数 总和为j 第i个数为z的方案数 首先观察这个题的性质 要求互不相
  • 十五、使用Selector(多路复用器)实现Netty中Reactor主从模型

    导论 前面几篇文章我们分别从 一 C10K问题经典问答 二 java nio ByteBuffer用法小结 三 Channel 通道 四 Selector选择器 五 Centos Linux安装nc 六 windows环境下netcat的安
  • 医疗场景下CV应用的总结与思考

    目录 背景 项目总体思路与框架 技术难题及解决思路 Data模块 Modeling模块 Deployment模块 可优化方向 标注流程 基于GAN的眼底图像生成模型 隐私计算 联邦学习 即时标注平台 自动化机器学习 背景 随着新生儿眼底筛查
  • 【Flask】Flask 会话

    Flask Sessions 会话 由于HTTP是无状态的 因此无法纪录客户一连串的动作 必须有一种机制使服务器能认得客户 这就引入了 会话 概念 服务器发给客户一个会话ID 当客户再访问服务器时就带着这个ID 服务器就凭着这个唯一的ID来
  • 毕业实习:Vue+Springboot+MySQL实现的订餐系统

    为期4天的毕业实习的收获 第一部分 vue框架的准备工作 测试vue cli创建工程 要以管理员身份运行cmd 1 在F盘下新建一个F shixuntestvue code文件 2 cd F 3 cd shixuntestvue code
  • python爬虫+数据分析完整流程--豆瓣电影分类排行榜

    整体思路 利用requests BeautifulSoup爬虫豆瓣电影分类排行榜数据 数据输出到本地csv文件 构建mongodb数据库 将数据存放入mongodb 利用pandas matplotlib画图分析数据 1 利用Beautif
  • Nginx安全性配置

    隐藏版本号 http server location http server tokens off 访问黑白名单设置 http server location limit except 白名单 只允许192 168 1 0 24网段的主机访
  • POJO/DTO/DO/EO/VO/BO/PO/AO的含义和使用

    关于POJO DTO DO EO VO BO PO AO 本文讨论 POJO DTO DO EO VO BO PO AO 的定义 另外讨论了这些xO在controller service dao mapper层里的使用规范 另外还稍微讨论了