如何在控制器、服务和存储库模式中使用 DTO

kco*_*123 13 java spring dto spring-boot

我正在遵循控制器、服务和存储库模式,我只是想知道 DTO 从何而来。

控制器应该只接收 DTO 吗?我的理解是你不想让外界知道底层的领域模型?

从域模型到 DTO 的转换应该发生在控制器层还是服务层?

And*_*eas 16

在当今使用 Spring MVC 和交互式 UI 进行编程时,Web 应用程序实际上有 4 层:

  • UI 层(Web 浏览器、JavaScript)

  • MVC 控制器,即带有注释的 Spring 组件 @Controller

  • 服务层,即带有注解的 Spring 组件 @Service

  • 数据访问层,即带有注解的 Spring 组件 @Repository

每次这些层之一与底层交互时,它们都需要发送/接收数据,通常是 POJO,以在层之间传输数据。这些 POJO 是 DTO,也就是数据传输对象。

层与层之间只能使用DTO,它们不一定相同,例如Service Layer 可能会将业务逻辑应用到从Data Access Layer 接收到的DTO,因此Service Layer API 的DTO 与Data Access Layer API 不同。类似地,控制器可能会重新排列数据以准备呈现(分组、摘要等),因此发送到 Web 浏览器的数据与从服务层接收的数据不同。

在完全抽象的情况下,数据访问层的 API 不应反映数据访问的技术,即它是否使用 JDBC、JPA、NoSQL、Web 服务或其他一些存储/检索数据的方法。这意味着实体类不应使其位于数据访问层之外。

大多数项目不需要这种抽象级别,因此 DTO 通常是一个实体类,并且从数据访问层一直流到控制器,在那里它要么被视图使用,要么被发送到 Web 浏览器,编码为 JSON。

这取决于项目的规模和复杂性。项目越大,使每一层尽可能抽象/独立变得越重要。


小智 12

不同的组织遵循不同的模式。这取决于您遵循哪种模式。根据我的个人经验,我遵循以下架构图。

在此处输入图片说明

根据上图,DTO 到实体对话(反之亦然)将仅在服务层内。

  • 太棒了,哪里来的? (2认同)

Flo*_*ian 6

一个简单的答案可能是:DTO(如果您需要一个,请参见下文)是一种允许您将特定信息传输到其他地方的东西。这是控制器/适配器/存储库/无论你怎么称呼它的任务。适配器的任务是从外部世界(系统边界之外)获取信息并将这些信息转换为相应的域模型,以便服务逻辑能够使用它。

而且,从我的角度来看,这也适用于存储库:存储库将数据持久保存到外部系统(例如数据库甚至另一个 REST 服务),并在请求时将其返回。为此,它可能需要将域模型转换为简化的 DTO,以便能够持久保存在目标系统中。

适配器的想法是,业务逻辑不需要知道如何转换要在 REST/SOAP/MySQL/... 协议中表示或传输的对象。这就是适配器的任务。因此:如果需要,DTO 应保留在适配器中。

您真的需要 DTO 吗?

DTO 是系统内部数据的另一种抽象。您还应该考虑一下您是否真的需要它们。您可能会也可能不会,这取决于您想如何处理该信息。如果您使用自己编写查询的数据库来保存数据(这意味着您没有使用 ORM 映射器),则可能根本不需要 DTO,因为您可以直接从域模型中提取相关信息。

另一方面,如果您对对象使用反序列化器(例如 Jackson 用于 JSON 或类似的东西),您可能会发现自己需要 DTO,因为这些工具有时需要一些特殊要求才能序列化和反序列化你的数据到一个对象中。在这里,您可能需要先使用 DTO,然后才能将其转换为域对象,反之亦然。


顺便说一句:这个问题在 softwareengineering.stackexchange.com 上也得到了很好的回答