Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 微服务Restful API-DTO与否?_Java_Spring_Web Services_Spring Mvc_Spring Boot - Fatal编程技术网

Java 微服务Restful API-DTO与否?

Java 微服务Restful API-DTO与否?,java,spring,web-services,spring-mvc,spring-boot,Java,Spring,Web Services,Spring Mvc,Spring Boot,我想在Microservices的上下文中再次问这个问题。这是原问题的引述 我目前正在为一个项目创建一个REST-API,并且一直在阅读 关于最佳实践的文章层出不穷。许多人似乎反对 DTO,只需公开域模型,而其他人似乎 认为DTO(或用户模型或任何你想称之为DTO的东西)是不好的 练习。就我个人而言,我认为这篇文章很有意义 然而,我也理解DTO的缺点以及所有额外的功能 映射代码,域模型可能与它们的 数据传输到对应方等 现在,我的问题是 我更倾向于在应用程序的所有层中使用一个对象(换句话说,只公开

我想在Microservices的上下文中再次问这个问题。这是原问题的引述

我目前正在为一个项目创建一个REST-API,并且一直在阅读 关于最佳实践的文章层出不穷。许多人似乎反对 DTO,只需公开域模型,而其他人似乎 认为DTO(或用户模型或任何你想称之为DTO的东西)是不好的 练习。就我个人而言,我认为这篇文章很有意义

然而,我也理解DTO的缺点以及所有额外的功能 映射代码,域模型可能与它们的 数据传输到对应方等

现在,我的问题是 我更倾向于在应用程序的所有层中使用一个对象(换句话说,只公开域对象,而不是创建DTO并手动复制每个字段)。我的Rest契约与域对象之间的差异可以通过使用Jackson注释来解决,比如
@JsonIgnore
@JsonProperty(access=access.WRITE_ONLY)
@JsonView
等)。或者,如果有一个或两个字段需要使用Jackson Annotation进行转换,而这无法使用Jackson Annotation完成,那么我将编写自定义逻辑来处理这一点(相信我,在我5年多的Rest服务之旅中,我从未遇到过这种情况)


我想知道我是否因为没有将域复制到DTO而错过了任何真正的坏影响,我会投票支持使用DTO,原因如下:

  • 不同的请求(事件)和数据库实体。通常情况下,您的请求/响应与域模型中的请求/响应不同。特别是在微服务体系结构中,它是有意义的,在微服务体系结构中,您有许多来自其他微服务的事件。例如,您有Order实体,但从另一个microservice获得的事件是OrderItemAdded。即使有一半的事件(或请求)与实体相同,为所有事件(或请求)设置DTO以避免混乱也是有意义的
  • DB模式和您公开的API之间的耦合。当使用实体时,您基本上公开了如何在特定的微服务中对数据库进行建模。在MySQL中,您可能希望您的实体具有关系,它们在组成方面相当庞大。在其他类型的数据库中,您将拥有没有许多内部对象的平面实体。这意味着,如果您使用实体公开API,并希望将数据库从MySQL更改为Cassandra,那么您也需要更改API,这显然是一件坏事
  • 。这可能与前一个项目有关,但DTO可以更容易地确保微服务之间的通信不会在其发展过程中中断。因为契约和DB不耦合,所以这更容易测试
  • 聚合。有时,您需要返回的数据多于单个DB实体中的数据。在这种情况下,DTO将只是一个聚合器
  • 性能。微服务意味着通过网络传输大量数据,这可能会导致性能问题。如果您的微服务的客户端需要的数据比您存储在数据库中的数据要少,那么您应该为它们提供更少的数据。再次-只需做一个DTO,您的网络负载就会减少
  • 忘记LazyInitializationException。DTO没有任何延迟加载和代理,而不是由ORM管理的域实体
  • 使用正确的工具支持DTO层并不难。通常,将实体映射到DTO并向后映射时会出现问题-每次要进行转换时,都需要手动设置正确的字段。在向实体和DTO添加新字段时,很容易忘记设置映射,但幸运的是,有很多工具可以为您完成此任务。例如,我们的项目中曾经有MapStruct,它可以在编译时自动为您生成转换

如果您使用CQR,则决策要简单得多,因为:

  • 对于写入端,您使用已经是DTO的
    命令
    <代码>聚合-域层中的富行为对象-未公开/查询,因此没有问题
  • 对于读取端,因为您使用的是薄层,所以从持久性中获取的对象应该已经是DTO了。应该没有映射问题,因为您可以为每个用例使用
    readmodel
    。在最坏的情况下,您可以使用GraphQL之类的工具来仅选择所需的字段
如果不将读写分离,那么决策就更难了,因为这两种解决方案都存在权衡。

只公开域对象的好处是什么
  • 编写的代码越少,产生的bug就越少。
    • 尽管在我们的代码库中有大量(有争议的)测试用例,但我还是遇到了错误,原因是从域到DTO或viceversa的字段复制丢失/错误
  • 可维护性-无锅炉板代码。
    • 如果我必须添加一个新属性,当然,我不必添加域、DTO、映射器和测试用例。不要告诉我,这可以通过使用反射beanCopy utils来实现,它破坏了整个目的
    • 我知道龙姆博克、格洛夫、科特林,但这只会让我省去一个令人头痛的问题
  • 干的
  • 演出
    • 我知道这属于“过早的性能优化是万恶之源”的范畴。但这仍然会节省一些CPU周期,因为不必为每个请求创建(以及稍后的垃圾收集)一个以上的对象(至少)
  • 欺骗
  • 从长远来看,DTO将为您提供更大的灵活性
    • 要是我需要那种灵活性就好了。至少,到目前为止,我遇到的是http上的CRUD操作,我可以使用两个