Skip to main content
 首页 » 编程设计

spring之Spring Data REST 在不使用 DTO 的情况下通过 REST 资源公开实体是否有问题

2024年09月07日17bonelee

以我有限的经验,我一再被告知不应将实体传递到前端或通过 rest 传递,而应使用 DTO。

Spring Data Rest 不正是这样做的吗?我已经简要地研究了预测,但那些似乎只是限制了正在返回的数据,并且仍然期望一个实体作为参数来保存到数据库中。我是否在这里遗漏了什么,或者我(和我的同事)是否不正确,因为你不应该绕过和实体?

请您参考如下方法:

tl;博士

不。DTO 只是将服务器端域模型与 HTTP 资源中公开的表示分离的一种方法。您还可以使用其他解耦方式,这就是 Spring Data REST 所做的。

细节

是的,Spring Data REST 检查您在服务器端拥有的域模型,以推断它公开的资源表示的方式。然而,它应用了几个关键概念来缓解领域对象的幼稚暴露带来的问题。

Spring Data REST 查找聚合并默认相应地塑造表示。

天真的“我把我的领域对象扔在 jackson 面前”的根本问题是,从普通实体模型中,很难推断出合理的表示边界。尤其是从数据库表派生的实体模型习惯于将几乎所有东西连接到所有东西。这源于这样一个事实,即聚合等重要的领域概念在大多数持久性技术中根本不存在(阅读:尤其是在关系数据库中)。

但是,我认为在这种情况下,“不要公开您的域模型”更多地是针对症状而不是问题的核心。如果您正确设计了域模型,那么域模型中的有益之处与通过状态更改有效驱动该模型的良好表示之间存在巨大重叠。几个简单的规则:

  • 对于与另一个实体的每一个关系,问问自己:这难道不是一个 id 引用吗?通过使用对象引用,您可以将关系另一侧的许多语义拉入您的实体中。弄错了通常会导致实体引用实体引用实体,这是更深层次的问题。在表示级别,这允许您截断数据、满足一致性范围等。
  • 避免双向关系,因为众所周知,它们很难在事物的更新方面做到正确。

  • Spring Data REST 做了很多事情来实际将这些实体关系转移到 HTTP 级别的适当机制中:一般链接,更重要的是链接到管理这些关系的专用资源。它通过检查为实体声明的存储库来实现,并且基本上用指向关联资源的链接替换了相关实体的其他必要内联,该链接允许您显式管理该关系。

    这种方法通常与 HTTP 级别的 DDD 聚合描述的一致性保证很好地配合。 PUT默认情况下,请求不会跨越多个聚合,这是一件好事,因为它意味着资源的一致性范围与您的域的概念相匹配。

    如果 DTO 只是复制域对象的字段,那么强制用户使用 DTO 是没有意义的。

    您可以根据需要为域对象引入任意数量的 DTO。在大多数情况下,域对象中捕获的字段将以某种方式反射(reflect)到表示中。我还没有看到实体 Customer包含 firstname , lastnameemailAddress属性(property),以及那些与代表完全无关的人。

    引入 DTO 并不能保证解耦。我见过太多的项目,它们是出于培养 cargo 的原因而引入的,只是简单地复制了支持它们的实体的所有字段,这只会导致额外的工作量,因为每个新字段都必须添加到 DTO 中。但是,嘿,脱钩!不是。 ¯\_(ツ)_/¯

    也就是说,在某些情况下,您当然希望稍微调整这些属性的表示,特别是如果您使用强类型值对象,例如 EmailAddress (好!)但仍想将其渲染为普通 String在 JSON 中。但这绝不是一个问题:Spring Data REST 在幕后使用 Jackson,它为您提供了多种调整表示的方法 - 注释、mixin 以将注释保留在域类型之外,自定义序列化程序等。所以有一个之间的映射层。

    默认情况下不使用 DTO 本身并不是一件坏事。试想一下,如果我们要求为所有内容编写 DTO,用户会强烈抗议所需的样板数量! DTO 只是达到目的的一种手段。如果可以以不同的方式实现这一目标(通常可以),为什么要坚持 DTO?

    只是不要在不符合您要求的地方使用 Spring Data REST。

    继续进行定制工作,值得注意的是 Spring Data REST 的存在是为了准确覆盖 API 的各个部分,只是遵循它实现的基本 REST API 实现模式。并且该功能已经到位,让您有更多时间思考
  • 如何塑造您的领域模型
  • 通过超媒体驱动的交互可以更好地表达 API 的哪些部分。

  • 这是我在 SpringOne Platform 2016 上发表的演讲的幻灯片,总结了这种情况。



    完整的幻灯片可以在 here 中找到.还有一个 recording of the talk在 InfoQ 上可用。

    Spring Data REST 的存在是为了让您能够专注于带下划线的圆圈。我们绝不认为您可以仅通过打开 Spring Data REST 来构建真正出色的 API。我们只是想减少样板文件的数量,让您有更多时间思考有趣的部分。

    就像 Spring Data 一样,通常会减少为标准持久性操作编写的样板代码量。没有人会争辩说,您实际上可以仅通过 CRUD 操作来构建真实世界的应用程序。但是从无聊的部分中抽出精力,我们允许您更深入地思考真正的领域挑战(您实际上应该这样做:))。

    您可以非常有选择性地覆盖某些资源以完全控制它们的行为,包括根据需要手动将域类型映射到 DTO。您还可以将自定义功能放在 Spring Data REST 提供的功能旁边,并将两者连接在一起。对你使用的东西要有选择性。

    一个 sample

    你可以找到我在 Spring RESTBucks 中描述的稍微高级的例子。 ,RESTful Web 服务书中 RESTBucks 示例的基于 Spring(数据 REST)的实现。它使用 Spring Data REST 来管理 Order实例但调整其处理以引入自定义要求并完全手动实现故事的支付部分。