dto java spring spring-boot

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, i.e. Spring components annotated with @Controller

  • Service Layer, i.e. Spring components annotated with @Service

  • Data Access Layer, i.e. 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, e.g. 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, i.e. 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.