【问题标题】:Two approaches to implementing REST API on Spring在 Spring 上实现 REST API 的两种方法
【发布时间】:2020-04-12 18:23:02
【问题描述】:

我在 Spring 上做 REST API。参加了 Spring Data Hibernate 的课程,发现它使 REST API 成为最耗时的方式。

当我向域中添加一个新实体时,我经历了以下对象链:

  1. 实体 - 域对象
  2. DTO - 用于向/从客户端传输/接收对象
  3. 映射器 - 在实体和 DTO 之间进行转换
  4. 存储库 - 用于与数据库交互
  5. RestController - 用于处理 API 请求
  6. Service - 对象的服务类

我的大致行动链如下:

  1. RestController 处理请求 - 从客户端接收 DTO(在创建新对象的情况下)
  2. 控制器中的映射器将 DTO 转换为实体
  3. 服务被调用
  4. 服务访问存储库
  5. Repository 返回执行结果(由Entity创建)
  6. 服务返回实体在 RestController 中创建
  7. RestController 向客户端返回一个 ResponseEntity 类型的对象,我在其中放置了正文和响应代码。

如您所见,一连串的动作和大量的对象。

但后来我发现,如果你使用 Spring Data REST,这一切都不需要 Spring 提供的所有 API。一般情况下,只需要创建一个Entity和Repository即可。

事实证明,对于典型的 CRUD 类型的操作,我徒劳地写了很多控制器及其方法。

问题:

  • 什么时候应该使用 RestConroller,什么时候应该使用 Spring Data REST?
  • 是否可以为一个实体组合两种方法?事实证明,我是在浪费时间编写简单的操作,例如创建、获取、保存、删除控制器,可以将其移至 Spring Data REST。
  • 我能否在 RestConroller 中实现我在 Spring Data Rest 中所做的一些操作?如:
  • 将实体属性值作为 id 而不是对象返回?我的意思是我有实体本身的实体的属性,对于这些字段,我有时需要返回它们的 ID 而不是整个实体。
  • 有什么方法可以控制错误处理吗?在 RestController 中,我实现了 ResponseEntityExceptionHandler 扩展类,并且在我的 RestController 中出现的所有错误都以相同的方式在一个地方进行处理,并且我始终知道所有错误将返回大致相同的响应结构。
  • 数据验证必须取决于它曾经在从客户端收到的 DTO 上进行验证的事实。在这方面有什么细微差别在等着我吗?

我对如何前进有点困惑。给我你的建议和想法。推进使用什么以及如何使用。

【问题讨论】:

    标签: spring spring-mvc spring-data-jpa spring-data spring-data-rest


    【解决方案1】:

    您可以自行构建完整的堆栈,使用 DTO 而不是返回实体对象,您可以在服务中组合存储库,并且可以将业务逻辑放在服务层上。如果您没有执行上述任何操作(并且您不希望在不久的将来这样做),则无需重新编写所有样板,这就是 Spring Data REST 发挥作用的时候。

    【讨论】:

      【解决方案2】:

      Spring Data REST 可以为您做的是将普通存储库搭建到 REST 服务的脚手架。它速度更快,理论上它应该是灵活的,但在实践中,除了对存储库的 REST 访问之外,很难实现其他目标。

      在生产中,我使用 Spring Data REST 作为数据库的包装器 - 在服务/微服务架构模型中,有时您只需将核心 DB 包装到此类层中,以实现与 DB 无关的应用程序。然后服务将在此包装器之上应用业务逻辑,并为前端提供 API。 另一方面,如果您计划仅使用这些生成的端点,则 Spring Data Rest(SDR) 不适合,因为您需要自定义获取数据和数据操作到 Repoitories/Services 的逻辑。您可以将两者结合起来并将 SDR 用于“简单”实体,您只需要对它们进行基本的 CRUD,而复杂实体则使用标准方法,您可以将实体与 endopint 分离并应用您的自定义业务逻辑进入服务。混合使用这两种策略的缺点是您的应用会不一致,并且一些“事情”会开箱即用地发生,这对于该项目的新开发人员来说非常困惑。

      自己编写这些类看起来很浪费时间和精力,但这只是因为您的应用还没有复杂的数据库和/或业务逻辑。

      简而言之 - “标准”方式提供了更大的灵活性,但代价是在一开始就编写重复代码。

      【讨论】:

      • 我有一个例子,我应该怎么做:我要做一个复杂的对象,叫做Report。它有与之关联的字符串。如果只有一行没有写报告,就不应该写所有的行。你觉得在那种情况下,我应该用“标准”的方式来做我的项目吗?
      • 这是一个 Spring Data Rest 将更难配置的示例。在您的“@Service”中,您需要对 ReportLines 列表中的行应用验证。如果您登录数据库并在读取行时执行其他操作,则需要设置所有工作流“@Transactional”,以免损坏数据污染数据库。否则,如果您可以批量持久化,我可以只执行 1.validate 2. 如果验证 = OK 然后 reportRepository.saveAll() 并配置 Hibernate/JPA 以进行批量持久化。
      【解决方案3】:

      这是一个有趣的问题。

      Spring Data Rest 提供了抽象,并掌握了大部分实现。这对于业务逻辑位于存储库层的小型应用程序很有帮助。我会为具有简单直接业务逻辑的应用程序选择它。

      但是,如果我需要在每一层进行细粒度的控制(例如:事务、AOP、单元测试、复杂的业务决策等),正如您提到的,这对于大型应用程序来说是最常见的,我更愿意编写这些中的每一个层。

      没有经验法则。

      【讨论】:

        猜你喜欢
        • 2021-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多