【问题标题】:Exposing JPA entities through Service通过 Service 公开 JPA 实体
【发布时间】:2015-04-14 14:34:17
【问题描述】:

我们正在使用 AngularJS、Rest、JPA 开发 Web 应用程序。我已经阅读了几篇关于域实体不应通过服务公开的文章。 我知道这是紧密耦合,可能存在循环引用,关注点分离,这对我来说似乎是有效的。 但后来我看到有关将 jpa 和 jaxb 映射应用于同一模型的文章,eclipseLink moxy 就是一个例子。

然后是 Spring data REST,它通过 rest api 公开 jpa 实体。(可能是 Spring Data REST 用于解决手头的不同问题)

所以我有点困惑。以下 2 个问题和场景的答案,其中一个比另一个更好。

  1. 将 jaxb 和 JPA 注释应用于同一个域模型有什么优势?这样做是否主要是为了避免介于两者之间的 DTO 层?

  2. 是否应该仅在您开发需要公开 CRUD 操作并且确实不涉及其他业务功能的应用程序时才使用 Spring 数据 REST?

【问题讨论】:

    标签: java spring-data


    【解决方案1】:

    使用 DTO 需要一定的开销:必须创建 DTO 类;实体类必须在序列化之前映射到 DTO。

    DTO 也“感觉不对”,因为它们似乎违反了“不要重复自己”的原则。查看实体和 DTO 并发现它们本质上是相同的,这令人沮丧。

    因此,直接公开您的 JPA 实体可以减少代码并减少使用代码时的脑力开销。您的控制器、服务和存储库都处理相同的类。

    但是有一些问题:

    • 您的内部表示与您要向 API 用户公开的接口不匹配。

      真实世界的例子:根文档是article,子文档是sections的分层文档。在内部,每个文档都与可能为空的父文档有关系。

      通过 REST 接口直接公开此实体将要求客户端发送 id(或 HATEOAS 中的 url)作为其提交实体的一部分,以正确链接文档。

      在创建小节时让 api 用户 POST 到 /articles/{id}/sections/ 会更好。

    • 公开内部数据。

      您的实体可能包括标识符、磁盘上的路径等,它们并不真正供公众使用。在序列化时,您必须@JsonIgnore 这些。反序列化时,您还将手动从实体中填充这些内容。

    • 性能。

      与上述类似;也许您的实体包含一个大数据对象。您希望用户能够 POST 或 PUT 这些内容,但不应要求他们下载对象只是为了读取实体的其他字段。

    • 潜在的序列化问题。

      延迟加载的集合是这里典型的失败案例。

    • 比必要的更复杂的序列化表示。

      现实世界的例子:word 实体与 synonyms 的集合;同义词取决于单词。直接序列化实体将导致:

      { "id":12, 
        "word": "cat",
        "synonyms": [
          { "id": 23,
            "synonym": "kitty"
          },
          { "id": 34,
            "synonym": "pussycat"
          }
        ]
      }
      

      更好的模型是:

      { "word": "cat",
        "synonyms": [
          "kitty",
          "pussycat"
        ]
      }
      
    • 同一类的大量注释会降低清晰度。

      根据您的实体复杂性,您可能有 JPA 注释(@Entity@Id@GeneratedValue@Column@ManyToMany@MappedBy 等)、XML 注释(@XmlRootElement、@ 987654340@、@XmlElement 等)、JSON 注释(@JsonInclude@JsonIgnore@JsonProperty 等)和验证注释(@NotNull@Null 等)都在同一个类上。

    由于所有这些问题,我通常使用 DTO。我手动将实体映射到 DTO,但是有些项目试图让这更容易,比如Dozer

    我可以想象使用spring-data-rest 或仅在我有非常简单的实体,它们之间没有太多关系,并且实体模型与我希望的模型之间存在高度对应的情况下直接公开我的实体暴露给用户。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 2012-12-06
    • 2023-01-07
    • 2015-07-31
    相关资源
    最近更新 更多