Java 中的 VO、DTO、PO、DO 是如何定义和互相转换的?

2022-04-28 14:54:20 +08:00
 devswork

1.项目中 VO 、DTO 、PO 、DO 都是怎么定义(概念)?包括这些 O 在项目 package 路径里是怎么定义的( com.xxx.model.vo )? 2.这些领域对象都是如何转换的?手动 new set get 非常痛苦 3.针对查询参数传递到 mybatis ,是否需要单独的写 xxxxParam 来传参呢? 4.若不写 VO ,是不是 swagger 里就不能显示响应格式、请求参数(body)了?

5531 次点击
所在节点    Java
39 条回复
MakHoCheung
2022-04-28 20:04:57 +08:00
看了下评论,能否通俗点?
1. DAO 返回给 Service 的是只返回 Entity ( PO )吗,如果涉及到连表的话是不是要返回 DTO ?
2. DAO 返回的 Entity 需要在 Service 转成 DTO 然后再 Controller 层转成 VO 返回给前端吗,如果三者内容一致呢,是不是有多余重复的复制操作了


C#、Go 开发 Web 有这么多规范吗
KingOfUSA
2022-04-28 20:32:24 +08:00
推荐这个库 https://github.com/ksprider/Surgical 至少在 controller 层可以无需转换成 vo ,也能将所需要的字段序列化掉,而不用新建一层 vo ,主要是这个 vo 复用性为 0 呐,
aragakiyuii
2022-04-28 21:41:06 +08:00
基本都是贫血模型搞这么多概念干嘛。。。需要去区分字段的时候定义一个新的就好了
Leviathann
2022-04-28 21:47:20 +08:00
一条垂直链路下来搞那么多纯属吃饱了撑的
我们的项目只有 entity aggregate 输出输入专用对象 三种,如果算上部分字段查询结果的对象那就是四种
逻辑都放在 aggregate 里
leeg810312
2022-04-28 22:03:35 +08:00
我同时用.net 和 Java 开发,所以行业内 2 个平台有各自的设计偏好我都有了解,现在实践中发现只用 2 种数据模型就足够了,Entity 用于数据表映射和 DTO 数据传输,太多模型分类都是过度设计,徒增无用的复杂性。ORM 获取数据都是 Entity ,DTO 顾名思义数据传输对象,那么不管转给中间服务层或是控制器都是 DTO ,不再分出其他的概念,不像楼上有人说会用得少。DTO 类的设计原则是根据业务需要,裁剪、增加、拼装 Entity 的属性,甚至可以增加一些辅助的方法,用平台常用的对象映射工具 AutoMapper/MapStruct 等进行 Entity 和 DTO 之间的转换。
twing37
2022-04-28 22:50:32 +08:00
1. VO 如果你写过脚本语言,如 php, 混在 V 层的模板对象就是 VO,
2. DTO 前后端分类的,接口对象.
> 注 1: 1 与 2 的区别在于, 举个例子, 如 性别字段, vo 里面是男, dto 里面是 1,
3. 需要. 比如, http/grpc 的 json 与 proto --> service(use case)的逻辑层对象,
4. 参见 1 与 2 的区别.
> 注 2: 在足够简单的项目中,确定架构不会改变的情况下,请忽略这些.不管是 clean arch 还是 ddd 的六边形
都不如梭哈. 我在之前的类似答案中也写过,在这个前提下,不如面条代码写来的更好.比如在 repo 下,只是简单的 curd,
完全可以嵌入整个 store 逻辑,因为该逻辑很难再去复用.
hingbong
2022-04-29 00:07:54 +08:00
我用 GitHub copilot 生成转换代码
xuanbg
2022-04-29 06:59:11 +08:00
我的做法是 DTO 用来接收数据,VO 返回数据。然后它们相同的字段从一个不带 XO 的同名类继承。相互转换很简单啊,就是 A 序列化后再反序列化成 B 就行了呀。效率虽低,但基本没有影响。谁又会在意一个接口的响应时间慢了几个微秒呢。
MonkeyJon
2022-04-29 08:40:38 +08:00
自己写个装换器或者 MapStruct
securityCoding
2022-04-29 09:14:38 +08:00
这套东西扔了吧,一群学院派搞出来的高大上概念
nothingistrue
2022-04-29 09:27:19 +08:00
@hjahgdthab750 #19 后缀是由架构或规范决定的,没有特定规则。光凭“只有 getter setter ”这一个特点,是不知道这个类是干啥的,还要结合其他特点才能确切直到这个类是干啥的,之后才能命名。

@lessMonologue #20 没有。就算有也不具备参考意义,因为这本来就是规范不是规则,是随团队变化的。

@MakHoCheung #21 再严格一点,上下层之间不管调用还是返回都只能是 DTO ,DTO 负责对象的转换。例:Service 利用 DTO 的静态方法或者工厂方法将 BO 扔进 DTO ,再用这个 DTO 作为调用 DAO 的参数;反过来就是 DAO 将 Entity 利用工厂方法将扔进 DTO ,再返回 DTO 。这三者内容不可能一致的,Entity 是 ORM 的托管对象会带有 ORM 的信息,DTO 要负责数据转换会带有业务逻辑,BO 为 Service 服务会有业务逻辑的中间数据。然而,这随不是重复操作,但是属于杀鸡用牛刀的操作。

@leeg810312 #25 你这个好,用 DTO 把数据转换和数据对象都给包了,就只剩下 Entity 和 DTO 两种,没有纯数据的 Data 了。
notwaste
2022-04-29 10:05:30 +08:00
一路看下来都是经验之谈主观看法,那么我还是坚持我的想法跟着自身项目走就可以,本身就是为了规范而存在的
LLaMA2
2022-04-29 14:33:05 +08:00
我一直想问各位大佬,mapstruct 中转换树形数据,不确定层级的嵌套数据有什么好办法,我用的时候每天被折磨的很难过,后来我用 TS 写代码,typeorm 就没有这个苦恼了
Dlin
2022-04-29 14:48:18 +08:00
这些概念,往往都只是个概念,实践起来麻烦琐碎。
issakchill
2022-04-29 15:20:50 +08:00
@ye4tar #33
issakchill
2022-04-29 15:23:59 +08:00
@issakchill 错手回复了空内容.. 如果是树形转树形 mapstruct 好像是自动递归的
cco
2022-04-29 16:46:08 +08:00
VO: 返回给前端,或者响应给请求者的对象。
DTO: 请求参数、数据库查询列映射 负责数据传输。
Entity: 和数据库表一一对应的实体对象。
一般用这三个。这东西和接口与实现分包放一样,要不要都可以。对于数据库查询出来的数据,直接响应回去,那没必要 DTO (或者 Entity ) -> BO(可以理解为还是 DTO) -> VO ,直接返回即可。

至于转换关系。mapstruct 、BeanUtil 都可以,不管什么都不可避免要手动加点进去。如果你查出来的列名和你要响应的字段都不一致呢?这些类库以及 idea 的插件也只是方便而已,不可能实现一键转换。除非你转换前和转换后几乎是一模一样的。
kahlkn
2022-05-11 13:15:27 +08:00
@sujin190 字段删掉的话,bean 就不 copy 字段,至于改字段类型,我是做了转换工具去转换得,总体上还是保留 不报错。 但是类型不一致是可以报错的,只是这些工具在实现的时候的考量可能是不报错。

反射就能做到,用反射、Cglib 都封装过 bean copy 。
generalfu
2022-08-22 14:30:03 +08:00
@kytrun 赞的很,好东西!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/849815

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX