我是否应该使用 DTO?

Bla*_*ere 6 spring

我正在使用 Spring 构建一个 Web 应用程序,现在我有一个实体、一个存储库、一个 RestController,并且我可以在浏览器中访问端点。

我现在正在尝试将 JSON 数据返回到浏览器,并且我在各种指南中看到了有关 DTO 的所有内容。

我真的需要 DTO 吗?我不能将序列化逻辑放在实体本身上吗?

Gio*_*uri 8

我认为,这是一个有点有争议的问题,简短的答案是:

\n
\n

这取决于。

\n
\n
\n

长一点的答案

\n

在很多情况下,很多人更喜欢一种方法(使用 DTO)而不是另一种方法(使用裸实体),反之亦然;然而,不存在更好使用的单一事实来源。

\n

这在很大程度上取决于需求、您决定坚持的架构方法、(甚至)个人偏好和其他(与项目相关的)具体细节。

\n

有些人甚至声称 DTO 是一种反模式;有些人喜欢使用它们;有些人认为,数据细化/调整应该发生在消费者/客户端(出于各种原因,其中之一可能是对 API 更改没有政策)。

\n

话虽如此,是的,您可以直接@Entity从控制器返回实例(或实体列表),并且这种方法没有问题。我什至会说,这并不一定违反 SOLID 或 Clean Code 原则。同样,这取决于您使用响应的目的、您需要什么数据表示、相关对象的容量和目的是什么,等等

\n

在以下场景中,DTO 通常是一个很好的实践:

\n
    \n
  1. 当您想要聚合来自不同资源的对象数据时,即您想要在持久层和业务(或 Web)层之间放置一些对象转换逻辑:

    \n

    想象一下您从数据库中获取一个List<Employee>; 但是,从另一个第 3Web 服务,您还会收到每个Employee对象的一些补充员工数据,您必须在 Employee 对象中聚合这些数据(聚合或进行一些计算等。重点是您想要合并数据)。当您可能想要使用 DTO 模式时,这是一个很好的例子。可重用,符合单一职责原则,与其他层隔离良好;

    \n
  2. \n
  3. 当您不一定合并从不同来源收到的数据,但您想要修改要返回的实体时:

    \n

    想象一下,您有一个非常大的实体(具有很多字段),并且调用相应端点(前端应用程序、移动设备或任何客户端)的客户端不需要接收这个巨大的实体(或实体列表) )。如果您尽管客户端有要求,仍然会发送原始/未更改的实体,那么您最终将低效地消耗网络带宽/负载(绰绰有余),性能会变弱,通常,您只会浪费没有充分理由的计算资源。在这种情况下,您可能希望将原始实体转换为客户端需要的 DTO 对象(仅具有必填字段)。在这里,您甚至可能想要为一个实体、不同的消费者/客户端实现不同的 DTO 类。

    \n
  4. \n
\n

但是,如果您确定您的表/关系表示(@Entity 类的实例)正是客户端所需要的,那么我认为没有必要引入 DTO。

\n
\n

进一步支持这个想法,@Entity 可以在没有 DTO 的情况下返回到表示层

\n
    \n
  1. Java Persistence with Hibernate, Second Edition,在 \xc2\xa73.3.2 中,甚至明确地激发了它:

    \n
    \n

    您可以在持久性上下文之外重用持久性类,例如在单元测试中或在表示层中。您可以使用常规 Java new 运算符在任何运行时环境中创建实例,从而保留可测试性和可重用性;

    \n
    \n
  2. \n
  3. Hibernate 实体不需要显式可序列化;

    \n
  4. \n
  5. 您可能还想看看这个问题

    \n
  6. \n
\n


Abh*_*tti 0

这是不应该暴露实体的理想设计。

在将实体传递到 Web 层之前将其转换为 DTO 是一个很好的设计。

如今,RestJpa 控制器也可用。

但同样,不同的应用程序使用哪一个也是不同的。

如果您的应用程序只需要只读操作,那么使用 RestJpacontrollers 是有意义的,并且可以在 Web 层使用实体。

在应用程序频繁修改数据的其他情况下,那么在这种情况下,更好的选择是选择 DTO 并在 UI 层使用它。

另一种情况是需要多个请求来为特定任务带来数据。在相同情况下,可以将要带入的数据合并到一个 DTO 中,这样只有一个请求就可以带入所有需要的数据。

我们可以将多个实体数据的数据整合到一个DTO中。此 DTO 可用于前端或其余 API。