在 Spring 上实现 REST API 的两种方法
Two approaches to implementing REST API on Spring
我在 Spring 上做 REST API。参加了 Spring Data Hibernate 课程,发现它使 REST API 成为最耗时的方式。
当我向域添加新实体时,我经历了以下对象链:
- 实体 - 域对象
- DTO - 对于transmitting/receiving一个对象to/from一个客户端
- Mapper - 在实体和 DTO 之间转换
- 存储库 - 用于与数据库交互
- RestController - 用于处理 API 个请求
- 服务 - 对象的服务class
我的大致操作链如下:
- RestController 处理请求 - 从客户端接收 DTO(在创建新对象的情况下)
- 控制器中的映射器将 DTO 转换为实体
- 调用服务
- 服务访问存储库
- Repository returns 执行结果(由实体创建)
- Service returns 实体在 RestController
中创建
- RestController returns 给客户端一个 ResponseEntity 类型的对象,我在其中放置正文和响应代码。
如您所见,有大量操作链和大量对象。
但后来我发现,如果您使用 Spring Data REST,那么所有这些都不需要 Spring 提供的所有 API。一般情况下,只需要创建一个Entity和Repository即可。
原来为了典型的CRUD类操作,白白写了很多controller和方法
问题:
- 我什么时候应该使用 RestConroller,什么时候 Spring Data REST?
- 是否可以为一个实体组合两种方法?原来我是在浪费时间写一些简单的操作,比如创建、获取、保存、删除控制器,它可以移动到 Spring Data REST。
- 我能否在 RestConroller 中实施我在 Spring Data Rest 中执行的某些操作?如:
- Return 实体 属性 值作为 id 而不是对象?我的意思是我拥有实体本身的属性,对于这些字段,我有时需要 return 它们的 ID 而不是整个实体。
- 有什么方法可以控制错误处理吗?在 RestController 中,我实现了 ResponseEntityExceptionHandler 扩展 class 并且在我的 RestController 中出现的所有错误都在一个地方以相同的方式处理,而且我始终知道所有错误都将 return 大致相同的响应结构。
- 数据验证必须取决于它过去是在从客户端收到的 DTO 上进行验证的事实。在这方面有什么细微差别等着我吗?
我对如何前进感到有点困惑。给我你的建议和想法。推进使用什么以及如何使用。
Spring Data REST 可以为您做的是将普通存储库搭建成 rest 服务的脚手架。它要快得多,理论上它应该是灵活的,但在实践中很难实现比对存储库的 REST 访问更多的东西。
在生产中,我使用 Spring Data REST 作为数据库的包装器——在 service/microservice 架构模型中,有时您只是将核心数据库包装到这样的层中,以实现与数据库无关的应用程序。然后,服务将在此包装器之上应用业务逻辑,并为前端提供 API。
另一方面,如果您打算仅使用这些生成的端点,则 Spring Data Rest(SDR) 不适合,因为您需要自定义用于获取数据和数据操作的逻辑 Repoitories/Services。您可以将两者结合起来并为 "simple" 实体使用 SDR,您只需要对它们进行基本的 CRUD,对于复杂的实体则使用标准方法,您可以将实体与端点分离并应用您的自定义业务逻辑到服务中。混合使用这两种策略的缺点是您的应用程序将不一致,并且一些 "things" 会开箱即用,这对于这个项目的新开发人员来说非常混乱。
看起来自己编写这些 类 是浪费时间和精力,但这只是因为您的应用还没有复杂的数据库 and/or 业务逻辑。
简而言之 - "standard" 方式以在开始时编写重复代码为代价提供了更大的灵活性。
您可以更好地控制自己构建完整的堆栈,您使用 DTO 而不是返回实体对象,您可以在服务中组合存储库,并且可以将业务逻辑放在服务层上。如果您没有执行上述任何操作(并且您不希望在不久的将来这样做),则无需重新编写所有样板文件,这就是 Spring Data REST 发挥作用的时候。
这是一个有趣的问题。
Spring Data Rest 提供了抽象并掌握了大部分实现。这对于业务逻辑位于存储库层的小型应用程序很有帮助。对于具有简单直接业务逻辑的应用程序,我会选择它。
但是,如果我需要在您提到的每个层上进行细粒度控制(例如:事务、AOP、单元测试、复杂的业务决策等),这是大型应用程序最常需要的,我会更喜欢编写每个层这些层。
没有经验法则。
我在 Spring 上做 REST API。参加了 Spring Data Hibernate 课程,发现它使 REST API 成为最耗时的方式。
当我向域添加新实体时,我经历了以下对象链:
- 实体 - 域对象
- DTO - 对于transmitting/receiving一个对象to/from一个客户端
- Mapper - 在实体和 DTO 之间转换
- 存储库 - 用于与数据库交互
- RestController - 用于处理 API 个请求
- 服务 - 对象的服务class
我的大致操作链如下:
- RestController 处理请求 - 从客户端接收 DTO(在创建新对象的情况下)
- 控制器中的映射器将 DTO 转换为实体
- 调用服务
- 服务访问存储库
- Repository returns 执行结果(由实体创建)
- Service returns 实体在 RestController 中创建
- RestController returns 给客户端一个 ResponseEntity 类型的对象,我在其中放置正文和响应代码。
如您所见,有大量操作链和大量对象。
但后来我发现,如果您使用 Spring Data REST,那么所有这些都不需要 Spring 提供的所有 API。一般情况下,只需要创建一个Entity和Repository即可。
原来为了典型的CRUD类操作,白白写了很多controller和方法
问题:
- 我什么时候应该使用 RestConroller,什么时候 Spring Data REST?
- 是否可以为一个实体组合两种方法?原来我是在浪费时间写一些简单的操作,比如创建、获取、保存、删除控制器,它可以移动到 Spring Data REST。
- 我能否在 RestConroller 中实施我在 Spring Data Rest 中执行的某些操作?如:
- Return 实体 属性 值作为 id 而不是对象?我的意思是我拥有实体本身的属性,对于这些字段,我有时需要 return 它们的 ID 而不是整个实体。
- 有什么方法可以控制错误处理吗?在 RestController 中,我实现了 ResponseEntityExceptionHandler 扩展 class 并且在我的 RestController 中出现的所有错误都在一个地方以相同的方式处理,而且我始终知道所有错误都将 return 大致相同的响应结构。
- 数据验证必须取决于它过去是在从客户端收到的 DTO 上进行验证的事实。在这方面有什么细微差别等着我吗?
我对如何前进感到有点困惑。给我你的建议和想法。推进使用什么以及如何使用。
Spring Data REST 可以为您做的是将普通存储库搭建成 rest 服务的脚手架。它要快得多,理论上它应该是灵活的,但在实践中很难实现比对存储库的 REST 访问更多的东西。
在生产中,我使用 Spring Data REST 作为数据库的包装器——在 service/microservice 架构模型中,有时您只是将核心数据库包装到这样的层中,以实现与数据库无关的应用程序。然后,服务将在此包装器之上应用业务逻辑,并为前端提供 API。 另一方面,如果您打算仅使用这些生成的端点,则 Spring Data Rest(SDR) 不适合,因为您需要自定义用于获取数据和数据操作的逻辑 Repoitories/Services。您可以将两者结合起来并为 "simple" 实体使用 SDR,您只需要对它们进行基本的 CRUD,对于复杂的实体则使用标准方法,您可以将实体与端点分离并应用您的自定义业务逻辑到服务中。混合使用这两种策略的缺点是您的应用程序将不一致,并且一些 "things" 会开箱即用,这对于这个项目的新开发人员来说非常混乱。
看起来自己编写这些 类 是浪费时间和精力,但这只是因为您的应用还没有复杂的数据库 and/or 业务逻辑。
简而言之 - "standard" 方式以在开始时编写重复代码为代价提供了更大的灵活性。
您可以更好地控制自己构建完整的堆栈,您使用 DTO 而不是返回实体对象,您可以在服务中组合存储库,并且可以将业务逻辑放在服务层上。如果您没有执行上述任何操作(并且您不希望在不久的将来这样做),则无需重新编写所有样板文件,这就是 Spring Data REST 发挥作用的时候。
这是一个有趣的问题。
Spring Data Rest 提供了抽象并掌握了大部分实现。这对于业务逻辑位于存储库层的小型应用程序很有帮助。对于具有简单直接业务逻辑的应用程序,我会选择它。
但是,如果我需要在您提到的每个层上进行细粒度控制(例如:事务、AOP、单元测试、复杂的业务决策等),这是大型应用程序最常需要的,我会更喜欢编写每个层这些层。
没有经验法则。