POJO/DTO/DO/EO/VO/BO/PO/AO的含义和使用_dto vo eo-程序员宅基地

技术标签: pojo  Java基础/JUC/JVM  dto  

关于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里呢?  我建议是不需要不强制。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/w8y56f/article/details/103515185

智能推荐

Spring Boot 获取 bean 的 3 种方式!还有谁不会?,Java面试官_springboot2.7获取bean-程序员宅基地

文章浏览阅读1.2k次,点赞35次,收藏18次。AutowiredPostConstruct 注释用于在依赖关系注入完成之后需要执行的方法上,以执行任何初始化。此方法必须在将类放入服务之前调用。支持依赖关系注入的所有类都必须支持此注释。即使类没有请求注入任何资源,用 PostConstruct 注释的方法也必须被调用。只有一个方法可以用此注释进行注释。_springboot2.7获取bean

Logistic Regression Java程序_logisticregression java-程序员宅基地

文章浏览阅读2.1k次。理论介绍 节点定义package logistic;public class Instance { public int label; public double[] x; public Instance(){} public Instance(int label,double[] x){ this.label = label; th_logisticregression java

linux文件误删除该如何恢复?,2024年最新Linux运维开发知识点-程序员宅基地

文章浏览阅读981次,点赞21次,收藏18次。本书是获得了很多读者好评的Linux经典畅销书**《Linux从入门到精通》的第2版**。下面我们来进行文件的恢复,执行下文中的lsof命令,在其返回结果中我们可以看到test-recovery.txt (deleted)被删除了,但是其存在一个进程tail使用它,tail进程的进程编号是1535。我们看到文件名为3的文件,就是我们刚刚“误删除”的文件,所以我们使用下面的cp命令把它恢复回去。命令进入该进程的文件目录下,1535是tail进程的进程id,这个文件目录里包含了若干该进程正在打开使用的文件。

流媒体协议之RTMP详解-程序员宅基地

文章浏览阅读10w+次,点赞12次,收藏72次。RTMP(Real Time Messaging Protocol)实时消息传输协议是Adobe公司提出得一种媒体流传输协议,其提供了一个双向得通道消息服务,意图在通信端之间传递带有时间信息得视频、音频和数据消息流,其通过对不同类型得消息分配不同得优先级,进而在网传能力限制下确定各种消息得传输次序。_rtmp

微型计算机2017年12月下,2017年12月计算机一级MSOffice考试习题(二)-程序员宅基地

文章浏览阅读64次。2017年12月的计算机等级考试将要来临!出国留学网为考生们整理了2017年12月计算机一级MSOffice考试习题,希望能帮到大家,想了解更多计算机等级考试消息,请关注我们,我们会第一时间更新。2017年12月计算机一级MSOffice考试习题(二)一、单选题1). 计算机最主要的工作特点是( )。A.存储程序与自动控制B.高速度与高精度C.可靠性与可用性D.有记忆能力正确答案:A答案解析:计算...

20210415web渗透学习之Mysqludf提权(二)(胃肠炎住院期间转)_the provided input file '/usr/share/metasploit-fra-程序员宅基地

文章浏览阅读356次。在学MYSQL的时候刚刚好看到了这个提权,很久之前用过别人现成的,但是一直时间没去细想, 这次就自己复现学习下。 0x00 UDF 什么是UDF? UDF (user defined function),即用户自定义函数。是通过添加新函数,对MySQL的功能进行扩充,就像使..._the provided input file '/usr/share/metasploit-framework/data/exploits/mysql

随便推点

webService详细-程序员宅基地

文章浏览阅读3.1w次,点赞71次,收藏485次。webService一 WebService概述1.1 WebService是什么WebService是一种跨编程语言和跨操作系统平台的远程调用技术。Web service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准...

Retrofit(2.0)入门小错误 -- Could not locate ResponseBody xxx Tried: * retrofit.BuiltInConverters_已添加addconverterfactory 但是 could not locate respons-程序员宅基地

文章浏览阅读1w次。前言照例给出官网:Retrofit官网其实大家学习的时候,完全可以按照官网Introduction,自己写一个例子来运行。但是百密一疏,官网可能忘记添加了一句非常重要的话,导致你可能出现如下错误:Could not locate ResponseBody converter错误信息:Caused by: java.lang.IllegalArgumentException: Could not l_已添加addconverterfactory 但是 could not locate responsebody converter

一套键鼠控制Windows+Linux——Synergy在Windows10和Ubuntu18.04共控的实践_linux 18.04 synergy-程序员宅基地

文章浏览阅读1k次。一套键鼠控制Windows+Linux——Synergy在Windows10和Ubuntu18.04共控的实践Synergy简介准备工作(重要)Windows服务端配置Ubuntu客户端配置配置开机启动Synergy简介Synergy能够通过IP地址实现一套键鼠对多系统、多终端进行控制,免去了对不同终端操作时频繁切换键鼠的麻烦,可跨平台使用,拥有Linux、MacOS、Windows多个版本。Synergy应用分服务端和客户端,服务端即主控端,Synergy会共享连接服务端的键鼠给客户端终端使用。本文_linux 18.04 synergy

nacos集成seata1.4.0注意事项_seata1.4.0 +nacos 集成-程序员宅基地

文章浏览阅读374次。写demo的时候遇到了很多问题,记录一下。安装nacos1.4.0配置mysql数据库,新建nacos_config数据库,并根据初始化脚本新建表,使配置从数据库读取,可单机模式启动也可以集群模式启动,启动时 ./start.sh -m standaloneapplication.properties 主要是db部分配置## Copyright 1999-2018 Alibaba Group Holding Ltd.## Licensed under the Apache License,_seata1.4.0 +nacos 集成

iperf3常用_iperf客户端指定ip地址-程序员宅基地

文章浏览阅读833次。iperf使用方法详解 iperf3是一款带宽测试工具,它支持调节各种参数,比如通信协议,数据包个数,发送持续时间,测试完会报告网络带宽,丢包率和其他参数。 安装 sudo apt-get install iperf3 iPerf3常用的参数: -c :指定客户端模式。例如:iperf3 -c 192.168.1.100。这将使用客户端模式连接到IP地址为192.16..._iperf客户端指定ip地址

浮点性(float)转化为字符串类型 自定义实现和深入探讨C++内部实现方法_c++浮点数 转 字符串 精度损失最小-程序员宅基地

文章浏览阅读7.4k次。 写这个函数目的不是为了和C/C++库中的函数在性能和安全性上一比高低,只是为了给那些喜欢探讨函数内部实现的网友,提供一种从浮点性到字符串转换的一种途径。 浮点数是有精度限制的,所以即使我们在使用C/C++中的sprintf或者cout 限制,当然这个精度限制是可以修改的。比方在C++中,我们可以cout.precision(10),不过这样设置的整个输出字符长度为10,而不是特定的小数点后1_c++浮点数 转 字符串 精度损失最小

推荐文章

热门文章

相关标签