哪个层应该用于将领域对象转换为DTO?

39
我们正在使用Spring Boot创建REST API。我们的项目中有三个层(Repository、Service和Controller)。
假设我在控制器中有一个获取用户的API,它返回UserDTO对象。
假设我在控制器中有一个名为GetUser的API,它返回UserDTO对象。
@GetMapping
public UserDTO getUser() {
   return userService.getUser();    
}
无论 userService.getUser() 返回 UserDTO 对象还是返回 User 对象并在控制器中将其转换为 UserDTO 对象? 哪种方式更好?
简而言之,领域对象到 DTO 对象的转换应该在服务层还是控制器层进行?

最佳实践是在服务层中转换DTO,不要在控制器中放置任何逻辑。 - Ahmed Nabil
自上而下。控制器应该知道服务,服务应该知道存储库。服务层不应该知道控制器、端点DTO。 - dieter
@dieter 你能详细说明一下吗?所以这个服务应该返回 User 还是 UserDTO - parsecer
@parsecer 今天我会从服务(核心应用程序)返回“CoreUser”,控制器应该将“CoreUser”映射到“ApiUser”并返回它。因此,服务层不知道控制器和REST API的存在。 - dieter
5个回答

23

我认为没有更好的方法将你的领域对象转换为数据传输对象,这只是个人口味问题。在我的项目中,我将领域对象转换为DTO作为“业务逻辑”的一部分,位于服务层,从而只将领域对象暴露给服务层。此外,我希望减少控制器中的“逻辑”,因为它们是应用程序层的一部分。

PS:如果您正在寻找将领域对象转换为DTO的多种方法,请查看我的最新Stackoverflow问题 (How to properly convert domain entities to DTOs while considering scalability & testability)


1
如果我想从JSON支持部分实体更新(PATCH,仅提供需要更改的内容),我目前使用jakson objectMapper.readerForUpdating(...)来实现。但是要更新资源,我需要更新DTO(readerForUpdating(find(id).toDTO()),然后保存dto.toEntity())。这意味着现在我需要从我的服务中调用jackson(第三方库)。这会让你感到困扰吗? - Dalibor Filus
另一方面,如果转换是在控制器中完成的,我将不得不在控制器本身中支持这个部分更新,这意味着使我的所有“领域”对象公开(假设控制器所在的模块与服务不同)。 - Dalibor Filus
另外,还有一个相关的问题:如果我需要支持数据的xlsx/csv导出,那么xlsx/csv应该包含与DTO相同的数据。你会把这个逻辑放在哪里?放到服务、控制器,还是用于将此DTO转换为xlsx/csv的某个辅助服务中?当然,你可以直接将领域实体转换为xlsx/csv,但这样一来,你就可以在访问第三方xlsx库(例如apache.poi)的地方访问领域。 - Dalibor Filus
1
如果服务层返回实体,我想我们在事务方面可能会遇到另一个问题。如果服务返回的实体具有一些延迟加载集合,我们应该在控制器中打开事务以访问数据,对吗?从控制器打开事务可以吗? - Al Xx

13

这取决于应用程序的需求和架构。重点是在边缘保持DTO转换。通常更喜欢在控制器级别进行DTO和领域转换。如果您希望将服务/业务逻辑与使用者分开,则始终最好在API级别进行。如果您的服务被多个使用者使用,这一点会更加清晰。


5

根据我的经验,转换应该在控制器层进行。这样做的优点是能够重复使用其他服务方法,并且返回的对象是原始对象。

有时候这一点可能很重要,因为DTO对象经常从原始对象中减少字段。因此,我们需要更多的代码来获取这些减少的字段,使我们的代码变得丑陋和重复。

我知道这将把逻辑移到控制器层,但这是一种权衡。


2

这是我通常的做法:

我的服务层以dto作为参数。我在服务层进行转换,因为在转换时可能需要应用一些业务逻辑。

但是我的服务层总是返回实体。我在控制器层进行转换。这使得我的服务干净且独立于消费者。可能会发生我的服务被另一个服务使用并需要实体而不是dto的情况。

总之:

Dto —> Entity(服务层)
Entity —> Dto(控制器层)


0
不要让你的应用程序/领域层依赖基础设施层。在这种情况下,UserDTO代表了传输的内容,绝对不应该是应用程序/领域服务的一部分。
控制器负责将基础设施适配到应用程序。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接