简体   繁体   中英

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.

Should the controller only receive DTOs? My understanding is you wouldn't want the outside world to know about the underlying domain model?

Should the conversion from domain model to DTO happen in the controller or service layer?

In today programming with Spring MVC and interactive UIs, there are really 4 layers to a web application:

  • UI Layer (Web Browser, JavaScript)

  • MVC Controller, ie Spring components annotated with @Controller

  • Service Layer, ie Spring components annotated with @Service

  • Data Access Layer, ie Spring components annotated with @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. These POJOs are DTOs, aka Data Transfer Objects.

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. 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.

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.

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.

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. 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.

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. For that it probably needs to convert the domain model into a simplified DTO to be able to be persisted in the target system.

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. That's the task of the adapter. Therefore: DTOs should stay in the adapter, if you need them.

Do you actually need DTOs?

A DTO is another abstraction of data inside of your system. 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.

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. Here you might need to step to use a DTO before you can convert it into a domain object or vice versa.


Btw.: This question is also quite good answered on softwareengineering.stackexchange.com

The correct way would be Controller -> Service -> Implementation -> Repository

Your repository layer can return the underlying model which can be converted into your DTO when received by the implementation layer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM