简体   繁体   English

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

[英]How to use DTOs in the Controller, Service and Repository pattern

I'm following the Controller, Service and Repository pattern and I'm just wondering where DTOs come into this.我正在关注 Controller,服务和存储库模式,我只是想知道 DTO 是从哪里来的。

Should the controller only receive DTOs? controller 是否应该只接收 DTO? My understanding is you wouldn't want the outside world to know about the underlying domain model?我的理解是你不想让外界知道底层域model?

Should the conversion from domain model to DTO happen in the controller or service layer?从域 model 到 DTO 的转换应该发生在 controller 还是服务层?

In today programming with Spring MVC and interactive UIs, there are really 4 layers to a web application:在今天使用 Spring MVC 和交互式 UI 进行编程时,web 应用程序实际上有 4 层:

  • UI Layer (Web Browser, JavaScript) UI 层(Web 浏览器、JavaScript)

  • MVC Controller, ie Spring components annotated with @Controller MVC Controller,即用@Controller注解的Spring组件

  • Service Layer, ie Spring components annotated with @Service服务层,即用@Service注解的Spring组件

  • Data Access Layer, ie Spring components annotated with @Repository数据访问层,即用@Repository注解的@Repository组件

Every time one of these layers interact with the underlying layer, they need to send/receive data, which generally are POJOs, to transfer the data between layers.每次这些层与底层交互时,它们都需要发送/接收数据,通常是 POJO,以在层之间传输数据。 These POJOs are DTOs, aka Data Transfer Objects.这些 POJO 是 DTO,也就是数据传输对象。

Only DTOs should be used between layers, and they are not necessarily the same, eg the Service Layer may apply business logic to DTOs received from the Data Access Layer, so the DTOs of the Service Layer API is different from the Data Access Layer API.层与层之间只能使用 DTO,它们不一定相同,例如服务层可能会对从数据访问层接收到的 DTO 应用业务逻辑,因此服务层 API 的 DTO 与数据访问层 API 不同。 Similarly, the Controller may rearrange the data to prepare it for presentation (grouping, summaries, ...), so the data sent to the web browser is different from the data received from the Service Layer.同样,Controller 可能会重新排列数据以准备呈现(分组、摘要等),因此发送到 web 浏览器的数据与从服务层接收的数据不同。

With full abstraction, the Data Access Layer's API should not reflect the technology of the Data Access, ie whether it is using JDBC, JPA, NoSQL, a web service, or some other means of storing/retrieving the data. With full abstraction, the Data Access Layer's API should not reflect the technology of the Data Access, ie whether it is using JDBC, JPA, NoSQL, a web service, or some other means of storing/retrieving the data. This means that Entity classes shouldn't make it outside the Data Access Layer.这意味着实体类不应出现在数据访问层之外。

Most projects don't need that level of abstraction, so it is common for a DTO to be an Entity class, and to flow all the way from the Data Access Layer to the Controller, where it is used either by a View, or is send to the web browser, encoded as JSON.大多数项目不需要这种抽象级别,因此 DTO 通常是一个实体 class,并从数据访问层一路流向 Controller,在那里它要么被视图使用,要么被发送到 web 浏览器,编码为 JSON。

It depends on the size and complexity of the project.这取决于项目的规模和复杂性。 The bigger the project, the more important it becomes to make each layer as abstract/standalone as possible.项目越大,使每一层尽可能抽象/独立变得越重要。

There are different patterns followed by different organizations.不同的组织遵循不同的模式。 It depends on which pattern you follow.这取决于您遵循哪种模式。 From my personal experience, I follow below architecture diagram.根据我的个人经验,我遵循以下架构图。

在此处输入图像描述

As per the above diagram, DTO to Entity Conversation and vice versa will be inside the service layer only.根据上图,DTO 到实体对话(反之亦然)将仅在服务层内。

A simplified answer would probably be: A DTO (if you nee one, see below) is something which allows you to transfer specific information to somewhere else.一个简化的答案可能是:DTO(如果你需要一个,见下文)是一种允许你将特定信息传输到其他地方的东西。 This is the task of the Controller/Adapter/Repository/whatever you call it.这是控制器/适配器/存储库/无论你怎么称呼它的任务。 It's the task of the adapter to take the information from the outside world (outside of your system boundaries) and convert these information into the respective domain model in order for service logic to be able to work with it.适配器的任务是从外部世界(系统边界之外)获取信息并将这些信息转换为相应的域 model 以便服务逻辑能够使用它。

And, from my point of view, this also applies to the Repositories: A repository is persisting data to an outside system (eg a database or even another REST service) and bring it back when requested.而且,从我的角度来看,这也适用于存储库:存储库将数据持久化到外部系统(例如数据库或什至另一个 REST 服务)并在请求时将其带回。 For that it probably needs to convert the domain model into a simplified DTO to be able to be persisted in the target system.为此,它可能需要将域 model 转换为简化的 DTO 以便能够持久保存在目标系统中。

The idea of the adapters is, that the business logic does not need to know how to convert an object to be represented in or transferred via a REST/SOAP/MySQL/... protocol.适配器的想法是,业务逻辑不需要知道如何转换 object 以在 REST/SOAP/MySQL/... 协议中表示或传输。 That's the task of the adapter.这就是适配器的任务。 Therefore: DTOs should stay in the adapter, if you need them.因此:如果需要,DTO 应该留在适配器中。

Do you actually need DTOs?你真的需要 DTO 吗?

A DTO is another abstraction of data inside of your system. DTO 是系统内部数据的另一种抽象。 You should also think about if you actually need them.您还应该考虑是否真的需要它们。 You may or may not, depending on what you want to do with the information.您可能会也可能不会,这取决于您要如何处理这些信息。 If you persist data using a database where you write your queries yourself (meaning you're not using an ORM mapper), you may not need a DTO at all, as you can extract the relevant information from the domain model directly.如果您使用自己编写查询的数据库来保存数据(这意味着您没有使用 ORM 映射器),您可能根本不需要 DTO,因为您可以直接从域 model 中提取相关信息。

If you, on the other hand, use a deserializer for your objects (like Jackson for JSON or something like that), you may find yourself to require a DTO as these tools sometimes need some special requirements in order to be able to serialize and deserialize your data into an object.另一方面,如果您对对象使用反序列化器(例如 Jackson 用于 JSON 或类似的东西),您可能会发现自己需要 DTO,因为这些工具有时需要一些特殊要求才能进行序列化和反序列化您的数据到 object 中。 Here you might need to step to use a DTO before you can convert it into a domain object or vice versa.在这里,您可能需要先使用 DTO,然后才能将其转换为域 object,反之亦然。


Btw.: This question is also quite good answered on softwareengineering.stackexchange.com顺便说一句:这个问题在 softwareengineering.stackexchange.com 上也得到了很好的回答

The correct way would be Controller -> Service -> Implementation -> Repository正确的方法是 Controller -> 服务 -> 实施 -> 存储库

Your repository layer can return the underlying model which can be converted into your DTO when received by the implementation layer.您的存储库层可以返回底层 model,当实现层接收到它时,可以将其转换为您的 DTO。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在单个 controller / 服务方法中处理多个继承的 DTO? - How to handle Multiple inherited DTOs in a single controller / service method? 无法在Controller类中使用组件/服务/存储库 - Cannot use Components/Service/Repository in Controller class JPA 实体和 DTO 属于 Service 还是 Spring Repository 层 - Do JPA entities and DTOs belong to Service or Spring Repository layer 如何在服务和存储库中使用@Qualifier - How to use @Qualifier with Service and Repository 使用工厂设计模式的服务类中的@Autowired存储库 - @Autowired repository in service class with use of Factory Design Pattern 在控制器中返回 DTO - Return DTOs in the controller Spring Controller / Service / Repository中的泛型 - Generics in Spring Controller/Service/Repository 如何在 Model View Presenter 模式中使用存储库模式和交互器模式? - How do I use Repository pattern and Interactor pattern in a Model View Presenter pattern? 存储库模式:存储库可以使用其他存储库吗? - Repository pattern: Can a repository use other repositories? 在Java中使用存储库模式时,可以将单个Manager / Controller用于3个不同的存储库吗? - When using the Repository Pattern in Java, is it ok to use a single Manager/Controller for 3 different Repositories?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM