数据传输对象 DTO 在哪里构建

Data Transfer Object DTO Where to build

正在尝试重构一些代码。我看到一些 类 创建 DTO 对象,这些对象在服务层中传递并稍后由 @RestController 返回。据我所知,最好只在控制器中构建数据传输对象并将它们传递给视图,尤其是当我们将 WrapperDTO<T> 之类的东西与 get 和 set 值一起使用时。当我们使用复杂对象或简单数据类型构建 WrapperDTO 时,可能存在差异。所有意见将不胜感激。

我觉得还是在Service层创建DTO比较好

控制器不能知道业务逻辑细节。例如。我们需要 return 用户信息,但必须排除某些字段(密码等)。这些字段存在于用户实体中,但必须从 DTO 中删除。

我们在 Controller 上得到 SomePaginationDTO 的另一个案例,我们仍然需要将 DTO 传递给服务以解析过滤器、应用排序、限制结果等。所有逻辑都是服务责任的一部分。所以我会将 SomePaginationDTO 传递给服务。

DTO 可用于在应用程序的不同层之间传输数据:DAO、服务、外观、控制器。以我的经验,DTO 是一个自以为是的话题。

个人认为越晚转换越好,不转换就更好了。通常,后者在应用程序边界。 DTO 不是免费的,它涉及映射及其支持。因此,当跨边界存在领域模型不匹配或模型技术不匹配时,DTO 将有意义。有关详细信息,您可以查看 LocalDTO article and the associated link

如果我关注 service -> facade -> controller 层:

  • 服务:他们在做服务的事情,他们可能会互相打电话来做他们的处理。如果您的域模型在整个服务边界保持一致 service => facade,那么将结果转换为 DTO 还为时过早。

  • Facades: 他们可以编排服务并转换 input/output。在我看来,这将是转换为 DTO 或从 DTO 转换的正确位置。但前提是需要即。因为您的域模型必须跨越此边界进行转换(过滤字段、聚合...)

  • Gateway/Controllers: 它们处于应用程序边界。他们的逻辑很简单,简化为边界逻辑。外观和控制器之间的关系通常是 one <-> one。 ***

    合并外观和控制器通常是有意义的


因此,在我看来,您的第一个提案更适合,例如。 UserController....。最重要的是保持务实。

我会说没有规范正确的方法可以做到这一点。这取决于 DTO 的用途。

我为自己找到了一个关于在服务级别中何处使用 DTO 以及何处不使用 DTO 的简单规则:如果服务级别只有一个客户端,我将跨服务级别使用 DTO。如果有两个或更多客户端,最好不要在服务级别使用 DTO。

让我更详细地解释一下:

基本上很明显,不将DTO纳入服务级别需要更多的努力。因此,如果只有一个客户端,我会保持简单并使用 DTO 作为服务方法的 return 类型。

如果服务的客户端不止一个,那么客户端很可能需要不同的 DTO(例如,我想要一个对象的 jsoncsv 表示)。在这种情况下,我不会从服务中 return DTO。否则我需要为每个 DTO 提供不同的服务,或者不同的服务方法等。

注意:我并不是说如果您不在服务级别使用 DTO,则必须将转换逻辑移至控制器级别。我仍然认为控制器级别必须尽可能简单。您可能在控制器和服务之间有一些中间转换级别 - 不舒服,但它比拥有多个服务要好得多。

作为其他问题的一部分,我找到了一个很好的答案。当然 this/my 回答不参与赏金。这只是一个灵感,有人来解释现在的事情是如何实施的。那么来看看:

  • 型号类。他们不会得到 getters/setters 的一切。它 取决于模型逻辑。否则,您将获得可以轻松获得的模型 打破一致性。或者哪里有很多不明显的东西。假设你 有 User.registrationDate 字段。当您构造一个新用户时 对象,你不应该忘记字段 registrationDate 字段 手。所以,只需将 registrationDate 初始化放在你的 构造函数并删除 setter!
  • 存储库接口就在您的模型中。假设你有一些 依赖于现有存储对象的业务逻辑。你不能 明确地将您的域逻辑引用到基础架构中 JPA、Hibernate、JDBC 等依赖项。所以你查询这个存储的 来自接口的对象。
  • 商业服务(可选)。他们实现了一些复杂的逻辑, 涉及许多不同的实体,不包括安全和 交易管理。你的问题是关于它的。是的,如果你需要 查询域逻辑中的实体,将查询放入存储库 并从您的业务服务调用它。
  • 基础设施包内的存储库实现。器具 使用 JPA 或 mockito 或其他任何东西的存储库接口。他们 也不包括安全性和交易。
  • 应用程序服务(可选)。如果有一些复杂的 与基础设施或安全检查的互动。
  • 远程外观接口。客户端和服务器只能通过 远程外观接口。
  • 远程外观实现(控制器)。转换厚实体 对象转换为瘦 DTO(数据传输对象)。所有交易 分界和安全就在这里(经常使用注解)。

你觉得这个设计怎么样?它适用于众所周知的 spring mvc 吗?