28

Restful 资源并不总是与您的 jpa 实体具有一对一的映射关系。正如我所看到的,我试图弄清楚如何处理一些问题:

  1. 当资源具有由多个实体填充和保存的信息时。
  2. 当一个实体中包含更多您想要作为资源发送的信息时。我可以只使用杰克逊的@JsonIgnore,但我仍然会有问题 1、3 和 4。
  3. 当一个实体(如聚合根)具有嵌套实体并且您想要包含其嵌套实体的一部分但仅作为您的资源的某个嵌套级别时。
  4. 当您想要排除一个实体的一部分时,它是一个父实体的一部分,但当它的一部分是不同的父实体时排除一个单独的部分。
  5. Blasted 循环引用(我主要是使用 Jackson与JSOG@JsonIdentityInfo一起工作)

可能的解决方案: 我能想到的解决所有这些问题的唯一方法是创建一大堆“资源”类,这些类将具有构造函数,这些构造函数采用所需的实体来构造资源并为此放置必要的 getter 和 setter关于它的资源。这是矫枉过正吗?

为了解决 2、3、4 和 5,我可以对实际实体进行一些预处理和后处理,然后再将其发送给 Jackson 以将我的 pojo 序列化或反序列化为 JSON,但这并不能解决问题 1。

这些都是我认为其他人会遇到的问题,我很好奇其他人会提出什么解决方案。(我目前正在使用 JPA 2、Spring MVC、Jackson 和 Spring-Data,但对其他技术开放)

4

4 回答 4

27

结合 JAX_RS 1.1 和 Jackson/GSON,您可以将 JPA 实体直接公开为 REST 资源,但您会遇到无数问题。

DTO 即对 JPA 实体的投影是可行的方法。它将允许您将 REST 的资源表示关注点与 JPA 的事务关注点分开。您可以明确定义表示的性质。如果您仔细设计 DTO/投影,您可以控制表示中出现的数据量,包括要遍历的对象图的深度。您可能需要为同一个 JPA 实体创建多个 DTO/投影,以用于不同的资源,其中实体可能需要以不同的方式表示。

此外,根据我在 JPA 实体上使用@JsonIgnore和之类的注释的经验,并不能完全提供更多可用的资源表示。@JsonIdentityInfo在将对象合并回持久化上下文时,您最终可能会遇到麻烦(因为忽略了属性),或者您的客户端可能无法使用资源表示,因为对象引用作为一种方案可能不被理解。@JsonidentityInfo由于此处缺乏标准化,大多数 JavaScript 客户端通常无法使用注释生成的对象引用。

通过 DTO/预测还有其他额外的方面是可能的。JPA@EmbeddedId并不自然地适合 REST 资源表示。一些人提倡使用 JAX-RS@MatrixParam注释在资源 URI 中唯一地标识资源,但这对于大多数客户端来说并不是开箱即用的。矩阵参数毕竟只是设计说明,而不是标准(还)。使用 DTO/投影,您可以针对计算的 Id(可能是组成键的组合)提供资源表示。

注意:我目前正在为 REST 开发 JBoss Forge 插件,其中部分或全部存在这些问题,并将在未来的某个版本中通过生成 DTO 进行修复。

于 2013-07-30T07:48:40.807 回答
11

我同意其他答案,即 DTO 是要走的路。他们解决了很多问题:

  1. 分层和干净的代码。有一天,您可能需要使用不同的格式(例如 XML)或接口(例如,非基于 Web 服务)公开数据模型。为域模型中的每个接口/格式保留所有配置(例如@JsonIgnore, @JsonidentityInfo)会非常混乱。DTO 将关注点分开。它们可以包含您的外部接口(Web 服务)所需的所有配置,而无需更改域模型,这可以保持 Web 服务和格式不可知。

  2. 安全性 - 您可以轻松控制向客户端公开的内容以及允许客户端修改的内容。

  3. 性能 - 您可以轻松控制发送给客户端的内容。

  4. (循环)实体引用、延迟加载的集合等问题也会在您转换为 DTO 时明确且有意识地解决。

于 2013-07-30T09:25:20.870 回答
2

鉴于您的限制,除了数据传输对象之外似乎没有其他解决方案 - 是的,它发生得足够频繁以至于人们将这种模式命名为......

于 2013-07-26T07:04:18.567 回答
0

如果您的应用程序完全是 CRUDish,那么要走的路绝对是 Spring Data REST,您绝对不需要 DTO。如果它比这更复杂,那么使用 DTO 保护应用程序层会更安全。但不要尝试将 DTO 封装在控制器层内。它们属于服务层,因为映射也是逻辑的一部分(您在应用程序中允许什么以及从应用程序中释放什么)。这样应用层就保持密封。当然,在大多数情况下,它可以是这两者的混合。

于 2017-11-23T13:26:53.427 回答