如何在控制器、服务和存储库模式中使用 DTO
How to use DTOs in the Controller, Service and Repository pattern
我正在遵循控制器、服务和存储库模式,我只是想知道 DTO 是从哪里来的。
控制器应该只接收 DTO 吗?我的理解是你不想让外界知道底层领域模型?
领域模型到DTO的转换应该发生在控制器层还是服务层?
一个简单的答案可能是:DTO(如果您需要一个,请参见下文)是一种允许您将特定信息传输到其他地方的东西。这是你调用它的Controller/Adapter/Repository/whatever的任务。适配器的任务是从外部世界(系统边界之外)获取信息并将这些信息转换为相应的域模型,以便服务逻辑能够使用它。
并且,从我的角度来看,这也适用于存储库:存储库将数据持久保存到外部系统(例如数据库甚至另一个 REST 服务),并在请求时将其取回。为此,它可能需要将域模型转换为简化的 DTO,以便能够持久保存在目标系统中。
适配器的想法是,业务逻辑不需要知道如何转换要通过 REST/SOAP/MySQL/... 协议表示或传输的对象。这是适配器的任务。因此:如果需要,DTO 应该保留在适配器中。
你真的需要 DTO 吗?
DTO 是系统内部数据的另一种抽象。您还应该考虑是否真的需要它们。你可能会也可能不会,这取决于你想用这些信息做什么。如果您使用自己编写查询的数据库来持久化数据(意味着您没有使用 ORM 映射器),您可能根本不需要 DTO,因为您可以直接从域模型中提取相关信息。
另一方面,如果您为您的对象使用反序列化器(例如 Jackson 用于 JSON 或类似的东西),您可能会发现自己需要 DTO,因为这些工具有时需要一些特殊要求为了能够将您的数据序列化和反序列化为一个对象。在这里,您可能需要逐步使用 DTO,然后才能将其转换为域对象,反之亦然。
顺便说一句:这个问题也很好回答on softwareengineering.stackexchange.com
正确的方式应该是Controller -> Service -> Implementation -> Repository
您的存储库层可以 return 底层模型,当实现层收到时可以将其转换为您的 DTO。
不同的组织遵循不同的模式。这取决于您遵循哪种模式。根据我的个人经验,我遵循以下架构图。
根据上图,DTO 到实体对话,反之亦然仅在服务层内。
在当今使用 Spring MVC 和交互式 UI 进行编程时,Web 应用程序实际上有 4 层:
UI层(网络浏览器,JavaScript)
MVC 控制器,即 Spring 组件注释 @Controller
服务层,即 Spring 组件注释 @Service
数据访问层,即用@Repository
注释的Spring组件
每次这些层中的一个与底层交互时,它们需要 send/receive 数据(通常是 POJO)在层之间传输数据。这些 POJO 是 DTO,又名数据传输对象。
层与层之间只能使用DTO,而且不一定相同,例如服务层可能会将业务逻辑应用于从数据访问层接收的 DTO,因此服务层 API 的 DTO 不同于数据访问层 API。同样,控制器可能会重新排列数据以准备呈现(分组、摘要等),因此发送到 Web 浏览器的数据与从服务层接收到的数据不同。
在完全抽象的情况下,数据访问层的 API 不应反映数据访问的技术,即它是否使用 JDBC、JPA、NoSQL、Web 服务或其他一些storing/retrieving 数据的手段。这意味着实体 classes 不应位于数据访问层之外。
大多数项目不需要那种抽象级别,因此 DTO 通常是一个实体 class,并从数据访问层一直流到控制器,在那里它由视图使用,或发送到 Web 浏览器,编码为 JSON.
这取决于项目的大小和复杂程度。项目越大,将每一层尽可能abstract/standalone变得越重要。
我正在遵循控制器、服务和存储库模式,我只是想知道 DTO 是从哪里来的。
控制器应该只接收 DTO 吗?我的理解是你不想让外界知道底层领域模型?
领域模型到DTO的转换应该发生在控制器层还是服务层?
一个简单的答案可能是:DTO(如果您需要一个,请参见下文)是一种允许您将特定信息传输到其他地方的东西。这是你调用它的Controller/Adapter/Repository/whatever的任务。适配器的任务是从外部世界(系统边界之外)获取信息并将这些信息转换为相应的域模型,以便服务逻辑能够使用它。
并且,从我的角度来看,这也适用于存储库:存储库将数据持久保存到外部系统(例如数据库甚至另一个 REST 服务),并在请求时将其取回。为此,它可能需要将域模型转换为简化的 DTO,以便能够持久保存在目标系统中。
适配器的想法是,业务逻辑不需要知道如何转换要通过 REST/SOAP/MySQL/... 协议表示或传输的对象。这是适配器的任务。因此:如果需要,DTO 应该保留在适配器中。
你真的需要 DTO 吗?
DTO 是系统内部数据的另一种抽象。您还应该考虑是否真的需要它们。你可能会也可能不会,这取决于你想用这些信息做什么。如果您使用自己编写查询的数据库来持久化数据(意味着您没有使用 ORM 映射器),您可能根本不需要 DTO,因为您可以直接从域模型中提取相关信息。
另一方面,如果您为您的对象使用反序列化器(例如 Jackson 用于 JSON 或类似的东西),您可能会发现自己需要 DTO,因为这些工具有时需要一些特殊要求为了能够将您的数据序列化和反序列化为一个对象。在这里,您可能需要逐步使用 DTO,然后才能将其转换为域对象,反之亦然。
顺便说一句:这个问题也很好回答on softwareengineering.stackexchange.com
正确的方式应该是Controller -> Service -> Implementation -> Repository
您的存储库层可以 return 底层模型,当实现层收到时可以将其转换为您的 DTO。
不同的组织遵循不同的模式。这取决于您遵循哪种模式。根据我的个人经验,我遵循以下架构图。
根据上图,DTO 到实体对话,反之亦然仅在服务层内。
在当今使用 Spring MVC 和交互式 UI 进行编程时,Web 应用程序实际上有 4 层:
UI层(网络浏览器,JavaScript)
MVC 控制器,即 Spring 组件注释
@Controller
服务层,即 Spring 组件注释
@Service
数据访问层,即用
@Repository
注释的Spring组件
每次这些层中的一个与底层交互时,它们需要 send/receive 数据(通常是 POJO)在层之间传输数据。这些 POJO 是 DTO,又名数据传输对象。
层与层之间只能使用DTO,而且不一定相同,例如服务层可能会将业务逻辑应用于从数据访问层接收的 DTO,因此服务层 API 的 DTO 不同于数据访问层 API。同样,控制器可能会重新排列数据以准备呈现(分组、摘要等),因此发送到 Web 浏览器的数据与从服务层接收到的数据不同。
在完全抽象的情况下,数据访问层的 API 不应反映数据访问的技术,即它是否使用 JDBC、JPA、NoSQL、Web 服务或其他一些storing/retrieving 数据的手段。这意味着实体 classes 不应位于数据访问层之外。
大多数项目不需要那种抽象级别,因此 DTO 通常是一个实体 class,并从数据访问层一直流到控制器,在那里它由视图使用,或发送到 Web 浏览器,编码为 JSON.
这取决于项目的大小和复杂程度。项目越大,将每一层尽可能abstract/standalone变得越重要。