英文:
What are the differences of using service pattern and using standalone repository Spring Data REST?
问题
使用Spring Data REST仓库单独和围绕其实施“服务”模式(即ItemService
,ItemServiceImpl
等)的区别是什么?
乍一看,功能基本相同,区别在于服务方法允许更好的自定义,但也会产生大量样板代码(实现和控制器)。这里是使用两种方法的示例 - Oliver Drotbohm的RESTBucks中的示例(查看Payment
和CreditCard
实体)。
在该示例中,支付抽象使用了“服务”模式(PaymentService,PaymentImpl,然后在web文件夹中具有所有方法的PaymentController),而订单则直接通过Spring Data REST公开。
英文:
What are the differences of using Spring Data REST repository alone and implementing the “service” pattern around it (that is ItemService
, ItemServiceImpl
and so on)?
At the first glance the functionality is more or less the same with the difference that the service approach allows for a better customization but it also produces loads of boilerplate code (the implementation and the controller). Here is an example (look Payment
and CreditCard
entities) of using both approaches - RESTBucks of Oliver Drotbohm.
The payment abstraction there uses the "service" pattern used (PaymentService, PaymentImpl and then PaymentController with all methods in web folder) while the orders are exposed via Spring Data REST directly.
答案1
得分: 6
tl;dr
支付功能位于更高级的抽象层次,因为它不遵循已建立的HTTP资源模式(集合资源、项资源,总体上是描述在这里)所述的模式,因此需要进行自定义服务实现。相比之下,订单聚合的生命周期确实遵循这些模式,因此除了Spring Data REST的暴露外,不需要任何其他东西,再加上一些定制化。在这里找到关于这两个实现部分如何相互关联的概念概述。
详情
这是一个很好的问题。示例应用程序旨在展示API的不同部分如何受不同要求驱动,以及如何使用Spring Data REST来处理遵循已建立模式的部分,但同时又通过需要表达业务流程的更高级别方面进行增强。
该应用程序分为两个主要部分:围绕Order
聚合的订单处理,该聚合经历不同阶段。关于这些阶段的概念概述可以在这里找到。因此,订单的API的部分将遵循标准模式:可过滤的集合资源以查看所有订单,添加新订单等。这就是Spring Data REST的亮点所在。
支付部分则不同。它需要在订单处理的URI和功能空间中融合。我们通过以下步骤实现这一点:
- 我们在专用服务中实现所需功能。仓库交互与所需的抽象级别不匹配,因为我们必须验证
Order
和Payment
聚合的业务约束。那个逻辑需要存在于某个地方:在服务中。 - 我们通过Spring MVC控制器公开该功能,因为(目前)我们不需要像列出所有付款这样的标准模式。请记住,示例的重点是围绕建模订购流程,而不是会计后端。支付资源被融合到订单的URI空间中:
/orders/{id}/payment
。 - 我们使用超媒体元素来指示何时可以通过添加链接来触发功能,条件是客户端可以使用这些元素的存在或不存在来决定要触发哪些UI效果以启动该功能。
以下是我认为这种方法的好处:
- 从业务观点出发,您只需手动编写重要的部分。无需为遵循已建立模式的API部分实现大量样板代码。
- 客户端不需要关心接缝线在哪里。使用超媒体元素,API对客户端而言就像一个东西。服务器甚至可以将支付资源移动到不同的URI空间或不同的服务中。
资源
这个演示文稿详细讨论了我所描述的内容。这里有一个视频记录。如果您对特别是朝着超媒体的驱动力的更高级别想法感兴趣,我还建议查看这个幻灯片演示。
英文:
tl;dr
The payment functionality lives at a higher level of abstraction as it doesn't follow established HTTP resource patterns (collection resource, item resource, in general: the ones described here) and thus warrants a custom service implementation. In contrast, the lifecycle of the order aggregate does indeed follow those patterns and thus doesn't need anything but Spring Data REST exposure plus a few customizations. Find a conceptual overview about how the two implementation parts relate to each other here.
Details
That's a great question. The sample application is designed to showcase how different parts of an API can be driven by different requirements and how you can use Spring Data REST to take care of the parts that follow established patterns but at the same time augment it with higher level aspects that are needed to express business processes.
The application is split into two major parts: the order handling that's centered around the Order
aggregate that is taken through different stages. A conceptual overview about those can be found here. So parts of our API for the orders will be following standard patterns: filterable collection resources to see all orders, add new orders etc. This is where Spring Data REST shines.
The payment part is different. It somehow needs to blend into both the URI and functional space of the order handling. We achieve that by the following steps:
- We implement the required functionality in a dedicated service. The repository interaction doesn't match the necessary level of abstraction as we have to verify business constraints on both the
Order
andPayment
aggregates. That logic needs to live somewhere: in the service. - We expose that functionality via a Spring MVC controller as we (currently) don't need standard patterns like listing all payments. Remember, the example is centered around modeling the ordering process, it's not an accounting backend. The payment resources are blended into the URI space of the orders:
/orders/{id}/payment
. - We use hypermedia elements to indicate when the functionality can be triggered by adding a link pointing to those resources conditionally so that clients can use the presence or absence of those elements to decide what UI affordances to offer to trigger that functionality.
Here's what I think is nice about this approach:
- You only manually code the parts that are important from the business point of view. No need to implement a lot of boilerplate code for the parts of the API that follow well established patterns.
- Clients don't need to care where exactly that seam is. Using hypermedia elements, the API just looks like one thing to the client. The server could even move the payment resources to a different URI space or a different service even.
Resources
This deck discusses what I described in detail. Here's a video recording of it. If you're interested in the higher level ideas of especially the drive towards hypermedia, I suggest this slide deck, too
答案2
得分: 1
你的服务包含所有的逻辑,但是存储库层尽量保持愚笨。它的任务是执行特定的操作(例如保存、编辑)。
Spring Data 是一种方便的额外机制,用于与数据库实体交互,将它们组织在存储库中,提取数据并进行更改。在某些情况下,只需在其中声明接口和方法,而无需实现它。
附注:如果你正在创建一个简单的 CRUD,这是一个不错的选择。
英文:
Your service contains all the logic, but the repository layer is as stupid as possible. Its task is a specific operation(for ex. save, edit).
Spring Data is an additional convenient mechanism for interacting with database entities, organizing them in a repository, extracting data, changing it. in some cases, it will be enough to declare the interface and method in it, without implementing it.
P.S
and it's a good choice if you're creating a simple crud
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论