一大堆疑惑:入参时,Controller 接收哪个 O ?Service 接收和 Mybatis 接收哪个 O ?Mybatis 返回的可能是 PO (比如 getById 或者 selectByPrimaryKey),但也可能是自定义的 POJO 吧(比如一条复杂 Join 的结果),在这类情况下,Mybatis 返回的这些对象属于什么 O ?这些对象能被 Service 直接返回吗?Service 应该返回什么 O 给 Controller ?BO 又是个啥,看了不少资料愣是没整明白。DTO 在什么时候用,有说层之间入参和输出的,也有说调用其它系统的,总之乱七八糟。。。PS:项目没有使用 DDD ,是传统 SpringMVC+Mybatis 三层的设计。主要原因是我不懂 DDD…能力有限最好能够配合示例代码或者伪代码,谢谢大佬们。

如果不是公司要求,建议换一门语言学吧

ddd 是设计问题,和语言无瓜,看那个洋葱图自己慢慢理解,话说小项目真的没必要搞得太复杂。。。

  1. 啥 O 的问题,跟着项目来就行,通常都和某一层绑定,别人咋用就咋用,别纠结,干就完了2. DDD 需要甲方乙方整体水平都比较好才能发挥正向的作用,可以借鉴,不要轻易实践

你提到的这些都没必要关注,实际开发中没有哪个项目是严格按照这个规范来的,约定好即可。你作为初学者学习的方向已经走入了误区。

你要先搞明白这些简写的全部英文单词是什么,然后再去记他是什么,而不是死记硬背 controller 应该用那个 o ,计算机是工科,不是文科。

一个 DTO 用到死就行了

看得到图片吗,上图是阿里出的规约。但具体实践应该是看你们项目的规范或者约定,跟你开发的项目保持一致

统一 DTO ,不要管其他 O ;见过整个项目只有一个大 O 的,项目也在跑;搞好 O ,还不是被裁?

XO 就是个自己定义的命名规范,没啥意思,跟着来就行。你要是不愿意,怼得过领导就按你自己的来。

与前端交互一个 O ,与数据库交互一个 O ,两者中间一个转换 O ,共三个。

我建议全部 entity

Controller 入参用 DTO ,返回用 VO数据库实体类用 Entity其他很少用如果想偷懒甚至可以 Entity 一把梭 [doge]

这东西你去 10 个公司可能有 10 个做法,跟着公司来就行了面试的话我感觉也没人问这东西,问得话你记住每个 O 的英文是啥就知道是干啥的了

就是一种命名规则,初入自学等于你一个人开发项目,你想用 dto 就用 dto ,想用 pojo 就用 pojo ,无非就是一个类的名称结尾,你自创一个 xxO 都没事。回想起来当初我学 java 的时候看到 jdk 和 jre 一头雾水,看到 j2ee 和 j2se 这 tm 都是啥和啥啊,非要搞清楚他们到底是什么,结果查到的信息就是每个字都认识,放一起也认识,但是他想说明什么我还是没搞懂,至今我不知道 ee 和 se 有什么区别,但不影响我 springBoot 开发,不影响我 CURD 一把梭

这么多的 O ,为了转换还得整各种 get/set 进行赋值,很头疼

都是 Class 而已,看别人怎么命名你就怎么命名

的确根据公司规范来就是,没有规范的话,个人不太喜欢这些 O ,根据业务定义模型,不一定要叫什么 O ,比如数据库用户就叫 User, 但是一般数据库模型要和前端模型(叫的 VO )分开,前端模型也可以叫 User, 两个 User 做 map 转换,总之思想就是面向对象模型编程,而不是面向数据库编程。

自己开心就好,不要受这么多约束。如果公司有规范就按公司的走。

又没强制让你用,也没说必须这样用才对。你完全可以不用,但前提你得有自己的最佳实践

我直接数据库模型 entity 当 god class 一把梭哈(开个玩笑,小类可以这么做,一般最好不要)业务直接关联的 crud 接口,就数据库模型报表类(关联很多其他数据),或者特殊接口 就单独写一个类.这种其实也可以凭直觉,可以先用 god class 一段时间,就能发现问题了

一个 DTO 、一个 VO 、一个 Entity ,用就行了我感觉,没有其他的条条框框。

哈哈, 笑死我了, 你可以试着搜搜看 V 站有多少关于这几个 O 的 帖子

我只用过 DTO 更新新增, Query 查询 VO 返回, 没关联字段可以直接返回 Entiry

一般上要求数据库对象和其他,毕竟数据库有些字段不想对外暴露,还是封装一层。所以我推荐 DO(Entity)+DTO 。

最近一个项目,就是 dto 入参、一个 vo 返回、一个 Entity 对应数据库,主要是要前后端分离,文档需要规范点。一个人的话怎么方便怎么来。

这些都是人为区分的, 实际开发一把梭。

DO 和 VO 就够了,其余随意

我想楼主想说的是,如果是一个新项目,如何去规范各个层之间传递的 O 。如果是旧项目,那就按照旧项目的规范来,如果是新项目,应该是怎么规范好些?

如果是自己学,我有个建议,controller 入参都用 XXXReq ,返回的全是 XXXResp ,实体类用 XXXEntity ,其他管他什么层全用 XXXDTO 。如果是在公司,真的就是别人怎么用你就怎么用,纠结这个没用。

java 初学就是这点很烦,这些个 O 都是人为规定的,熬一段时间熟了

request response entity 一把梭

不要为了用而用 如果一个 Service 永远只会被一个类实现,那么定义 interface 的意义是什么呢

入参一个 O ,出参一个 O ,数据库交互一个 O ,管他什么 O 还是 Entity 呢,跟项目保持一致就行了

意义就是将来需要切换的话, 你就只需要完成 interface 内的方法就行了, 而不是去一个个复制

单一职责原则

对,别整那么多 O ,连想都不要想,影响思考

其实就是看项目复杂度1.项目很小,entity 一通到底2.项目有点规模了,就区分一下 vo ,dto ,entity 。大部分项目区分到这里就够了。3.项目很复杂了,根据公司需求和架构师的要求,他自然会让你知道你需要知道的部分。那么 vo ,dto ,entity 的区分就是:entity 就是你的数据库建模对象,简单来说就是和你的数据库字段一模一样,就放在 repository(mapper)层。dto 就是你的数据传输对象,根据你在后端的业务实际情况定义,一般用于后端服务之间传输数据,就放在 service 层vo 就是显示层对向,根据前端的展示需求来定义。

又一个被八股文祸害的

如楼上说的,实际中一般就是使用了 VO 、DTO 、Entity

service 的入参也是 req 吗?

我是能用 Entity 就用 Entity ,不能用 Entity ,全部都叫 VO ,从前传到后,再从后传到前,因为这个名称我看着顺眼一些。

一般我自己习惯 controller 的 save/update 用 DTO 接收,然后透传到 service 那边在 service 做 DTO -> Entity/DO 转换,返回值给 VO 。这里要在 service 里面做 DO 到 VO 的转换,需要给到前端对象里面的自增 id ,可以跟下面 query 返回值的转换用一套,不给数据库层面的一些值(比如 delete_flag );controller 的 query 用 Query 接收,然后返回给前端的时候给 VO ,这里需要 DO -> 转换,因为查的是数据库返回的是 DO (如果用的是 mybatis-plus 的 page 查询,可以直接用 covert 的 lambda 函数。其他用的不多

哈哈,我自己就 2 个,一个是 DTO 作为 request 入参的,一个 RTO 返回给 response ( return object )。

不要为了用而用。一些 O 是必须得,一些 O 只有业务需要得时候才存在,并且跟语言没关系,比如换成 go ,接收请求参数,响应数据和数据库持久化也一样,也需要分别定义,当然有人一把梭一个 O 从头传到尾,当我没有说。

一般 VO 、DTO 、Entity 就够了

Entity = 数据库表 ,字段类型一一对应。DTO = 查询数据库结果、也可做请求参数、controlelr -> service ,service -> mapper(dao)VO = 返回给前端的对象这就够了,除了 VO 和 entity ,其他都可以用 DTO 。最简单,最直接,Map<Stirng,Object>一把梭,拉屎贼通畅,就是不好擦屁股。

取之于 v2ex.用之于 v2ex. files.catbox.moe/5d65ey.png

我说直接点,这都是前代 Java 人拉的屎。什么 BOPOVO ,老子就是愿意 Entity+DTO ,谁管得着?

因为这些概念是重叠覆盖的。比如 POJO , 什么 POJO ,只有属性没有方法的类都算,你提到的所有 O 都属于 POJO 细分后的一种。什么是 DTO ,传输对象。 只要你用来当参数或者结果集的对象都算 DTO , 所以 VO,PO,DO,BO 那些乱七八糟的 O 也都是可以算 DTO ,只是阿里发布的许多文档之类的,DTO 单独用来指那些不好归类到 VO ,PO 之类 O 的其它传输对象了。如果你分层没像阿里或者其它复杂项目架构一样切的非常细,那么你所有不知道该叫什么的都叫 DTO 就行,或者 POJO 不带后缀都可以。--------------再接下来说说我的理解VO: 不论是叫它值对象(Value Object),还是展示层对象(View Object) 都是一个意思, 指的是展示层专用的、用来包装外部输入、输出的对象。举个例子,(假设在没有前后端分离的项目中,后端需要校验表单输入)比如用户注册接口参数对象,包含字段 登录名、密码,确认密码、验证码; 确认密码字段对于后续处理没有意义,只在 view 用于校验,所以它可以是一个单独的 VO 对象,重复密码正确后,将这个 VO 中有用的部分复制给 service 层专用的入参对象。BO:业务对象(Business Object), 感觉好像只在阿里系规范用的比较深度的项目见过 XxxxBO ,我在小厂混没实际见过。继续以上一个例子说,注册的 VO 中有价值的部分重新组装的数据传输对象就是 BO ,RegisterBO ,这个 Bo 包含登录名、密码等等,像上一个里提到的验证码,有些人是把它算额外的另一个单独业务处理,在 Controller 中调用其它方法直接校验了,所以这里的 BO 就不包含这个对象,而有些人则是认为验证码也是业务流程的一部分,应该归到这个 BO 里,在这一层处理。DO:持久化对象,基本就是与各类存储服务库表结构对应的对象,我常见的写法里也没见人加 DO 后缀的, 这个没什么好解释的。上一个 RegisterBO 中 可能最后会组转成,User 对象、UserExtra 对象、WechatUser 对象、Oauth2User 、SmsLog 等对象分别存储到各自的表里面。---------最后:DDD 那一套还有严格按照阿里发布的规范搞的某些项目可能会区分这么多 O ,划分这么多层, 甚至还有的入参都从 VO 、BO 、DTO 里拆出来,单独叫 Execute 、Query 、RequestParam ,Command 。但没那么多概念的项目我们实际上不会分那么细,从 Controller 到 Service 不管多少层,除了持久化对象,入参出参都叫 DTO 的项目也有。把不同层的数据对象拆开最大的好处就是方便项目拆分,独立部署,每个项目只需要依赖自己层的对象,当项目跨部门甚至跨公司的时候方便上游改动时控制影响范围,以及避免下游改动涉及到上游时还得跨部门让别人配合扯皮。如果整个项目所有部分的所有权都在自己手上时,不分那么细改起来也不麻烦。

可以的,Controller 直接透传给 Service 。定义各种 O 的本质就是分层,保证不暴露一些不安全的字段,只要确保这个就行了。你看一些开源的商城项目、CRM 系统会直接把 Entity 返回给前端。规矩是死的人是活的,初学者很容易纠结这些问题,因为想找到一些“最佳范式”,这很正常。多写多看多问,问题不大。

两到三个 O 梭哈全场 +1具体是 2 还是 3 ,取决于数据库的数据和给前端的数据差异大不大

他提到的做法就是 controller 入参出参用 VO ,数据库表对应对象用 PO ,中间的 service 或者其它 Job 、Util 、甚至连查表的返回对象和数据库查询参数之类的传输对象都用 DTO 。

不要那么多 O ,太多了代码都不好写

前端交互 VO ,内部数据传递 DTO ,数据库映射 Entiy

我是和数据库交互的用 DO ,其他全部 VO

VO: 前后端分离, 用不到

这都是卷的结果。。

request 入参 DTO 只有一个 int id 参数,也要写一个 dto 文件吗?

除了 CTO ,我啥都不管,CTO 让用啥就用啥。

建议题主看一下这本书 [企业应用架构模式] ,里面有详细的说明,以及不同情况下的选择。

说白了,搞这么多 O ,实际上还是项目工程化的要求。不做这些分层就写不了代码了吗,那肯定不是的。就像你要是乐意,可以把所有代码逻辑都写到 main 里,但是你肯定不会这么写,因为太难维护了。分层是在项目复杂化之后的为了方便维护的必然结果,如果你以后维护过屎山代码之后你就会更有体会了。所以反过来说,要不要这么多层级结构,也是根据项目的复杂程度来的,如果项目并不复杂,你并不需要这么多,就像上面很多楼说的,PO/Entity 、VO 、DTO 差不多就可以让项目结构比较清晰了

现在还入 java ,49 年入国军了。

这些都是缩写,先去查一下原始的英文单词是哪个,你就自然明白这些要怎么用了

初学你不用管这么多的,MVC 就成Dao 与 Service 传输用 Model ( PO ) 然后 Service 与 Controller 之间用 VO 记住这俩就行了,先把项目积累起来在考虑这这种加层

为什么我只使用 DTO ,不管其他“O”? mp.weixin.qq.com/s/mhl6SVHZvNp6BeqfeupCQw

CRUD 不用太在意这些简单的方式,写一个 baseEntity 公共字段, 写一个 queryParam 查询参数, 用业务的 entity 继承一下就行了如果按上面说的你用 dto 接,转 entity 存到 db ,转你不耗费资源吗? 如果上百个字段的 dto 你转去吧

这种应该是最常见的,只分三层就比较清晰了

通常,在我们设计一个模块的时候,我们设计的是一个又一个 Entity,实体,Entity 之间又各种各样的关联关系。Entity 构成了我们的主要设计,实际 Entity 的数据需要持久化落地的时候,就用用到 PO ,Entity 和 PO 并没有直接关系,一个 Entity 最终落地数据库的时候可以是多张表,即对应多个 PO 。DTO 是用来数据交换,VO 是用来展示层的。就这这些,没啥难的的,至于 BO ,不知道,自己灵活变通即可,也许 BO 代表 BusinessObject,那就跟 DTO 差不多一个意思了。总结下来:因为我们是面向对象编程,所以需要设计实体 Entity,实体不太表数据库表,实体代表我们抽象的业务模型。最终数据需要落地,落地就需要数据表 对应的就是 PO 了,你爱咋存咋存;中间需交互数据,或者吐数据,我们通常没法把实体 Entity 直接给别人,可能是根据业务需要,将多个实体中的数据抽出来,凑出一个 DTO ,或者 VO 给别人用。你开发经验够了,这些东西想清楚了,你就能整自己的一套,也能理解别人的套路。就是不能觉得繁琐而无脑抵制。不过,你当然可以面向数据库表编程,一个 calss 从前到后。

小项目无所谓的,直接 controller 调用 mapper 调用拿数据库对象返回都行,后面有需求可以再加 一层转的 service 和 vo

数据库结构 DO ,页面返回 VO ,其他都是 DTO也有接口请求 Req 后缀,返回 Resp 后缀,其他都 DTO 的

没逼用,把时间花在有用的东西上吧。。。

前端出身,没专门做过 Java ,但是维护过 Java 代码,个人理解的各种 O:首先为什么要有 O ,Java 是一个支持类型的语言,一个 Web 业务里各个层的方法不可能出入参都是简单类型,复杂出入参要是不写专门的类型就如 说的,可以直接入参一个变量为 Map<Stirng, Object>,返回也是,但是很明显不优雅, 比如无法编辑器自动提示,无法自动生成有意义的接口文档,所以最好要写个专门的类文件去定义,那这个类文件叫啥名呢,可以叫任何名,类名也可以叫任何名,只不过为了团队统一,约定叫 dto vo do 什么的,其实就是一个普通的 java 文件。第二为什么要分开各种 O ,上边说了,这个主要是为了支持类型的,那很明显分层多了后,不同层的出入参虽然字段可能都一样,但自已都在做自已的事,本质上就不是同一个类型了,要是还用同一个 O ,迟早会遇到这一层要加个什么东西,但另外一层不需要加,这里时候要么你改,要么别人改,所以不如一开始就分开。总之一句话总结:Java (或者说 Spring 这种框架)各种方法的出入参最好要有一个独立的类型来表示,那这个类型文件就是 O ,各种方法又分 Controller 的,Service 的,那类型文件最好不要用同一个,最好自已定义自已的,那就分开了各种 O 。

现在我待的公司的 go 代码也是有很多 DTO😂

为了方便归类人为搞出来的概念,你项目中完全可以不带 O ,没那么方便而已

管他什么 O ,统一一个 DTO 用的死!!! haha

分太细像坨💩,一模一样的内容 copy 四五份,用两三个区分下数据库对象跟其它就行了,旧项目就跟着用

过度设计的产物

有个卵子用,能跑就行,你看着清晰就行,叫啥能帮助 gc 还是能不触发 bug

分的太细违反设计原则,建议忽略,有规范 follow 规范,没规范看心情

entity 一把梭,什么多对多性能,我就套懒加载了。各种 o 转来转去一堆内存对象,你写一次数据库 3ms 后我也写一次,一堆并发锁,最后结局方式串行化。⬅️前东家的业务就是这么垮的

一般简单点 DO BO VO 就行了。 给 controller 的,比如显示页面,和导出都是用 VOBO 业务对象,比如在登录 manager 里的接口 Result login() BO 一般厚一点, 可以写方法,比如 UserBO.isAdmin() ,DO 就不用说了,数据库里捞出来就是 DO当然也可以 DO 一把梭

www.hesudu.com/t/834173

我们这边框架就两种对象,PO 持久化对象,BO 总线对象

enitity,map 一把梭,没有这么多 o,有时 entity 也没有,入参和返回 map,jdbc 直接来