2022 就业季|Spring 认证教你,如何使用 Spring 构建 REST 服务 (三)
书接上文⬆⬆⬆
是什么让一些东西变得 RESTful?
到目前为止,您拥有一个基于 Web 服务来处理涉及员工数据的核心操作。但这还不足以让事情变得“RESTful”。
漂亮的 URL/employees/3 不是 REST。
仅使用 GET,POST 等不是 REST。
安排好所有的 CRUD 操作不当 REST。
事实上,到目前为止,我们构建的更好地描述为 RPC(远程过程调用)。那是因为没有办法知道如何与这个服务器交互。如果您今天发布了此内容,您还必须编写文档或在某个地方托管开发人员的门户,其中包含所有详细信息。
Roy Fielding 的这一陈述可能会进一步为 REST 和 RPC 之间的区别提供线索:
我对将任何基于 HTTP 的接口称为 REST API 的人数感到沮丧。今天的例子是 SocialSite REST API。那就是 RPC。它尖叫 RPC。展示的耦合太多了,应该给它一个 X 评级。
要做些什么来使用 REST 架构风格清楚地认识到超文本是一种约束?换句话说,应用程序状态引擎(以及 API)不是由超文本驱动的,那么它就不能是 RESTful 并且不能是 REST API。时期。是否有一些损坏的手册需要修复?
— 罗伊菲尔丁https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
在我们的表示中不包括超媒体的副作用是客户端必须硬编码 URI 来导航 API。这导致了与网络电子商务兴起之前相同的脆弱性。这表明我们的 JSON 输出需要一点帮助。
介绍 Spring HATEOAS,这是一个 Spring 项目,旨在帮助您编写超媒体驱动的输出。要将您的服务升级为 RESTful,请将其添加到您的构建中:
将 Spring HATEOAS 添加 dependencies 到 pom.xml
这个小型库将为我们提供定义 RESTful 服务的结构,然后以可接受的格式呈现它以供客户使用。
任何 RESTful 服务的一个关键要素是添加指向相关操作的链接。要使您的控制器更加 RESTful,请添加如下链接:
获取单个项目的资源
本教程基于 Spring MVC 并使用静态辅助方法 WebMvcLinkBuilder 来构建这些链接。如果您在项目中使用 Spring WebFlux,则必须改用 WebFluxLinkBuilder.
这与我们之前的情况非常相似,但有一些变化:
该方法的返回类型已从 更改 Employee 为 EntityModel<Employee>。EntityModel<T>是来自 Spring HATEOAS 的通用容器,它不仅包含数据,还包含链接集合。
linkTo(methodOn(EmployeeController.class).one(id)).withSelfRel()要求 Spring HATEOAS 建立到 EmployeeController'one()方法的链接,并将其标记为自链接。
linkTo(methodOn(EmployeeController.class).all()).withRel("employees")要求 Spring HATEOAS 建立到聚合根的链接 all(),并将其称为“员工”。
“建立链接”是什么意思?Spring HATEOAS 的核心类型之一是 Link. 它包括一个 URI 和一个 rel(关系)。链接是赋予网络权力的东西。在万维网之前,其他文档系统会呈现信息或链接,但正是将文档与这种关系元数据链接在一起,才将网络缝合在一起。
Roy Fielding 鼓励使用使 Web 成功的相同技术构建 API,链接就是其中之一。
如果您重新启动应用程序并查询 Bilbo 的员工记录,您将得到与之前略有不同的响应:
冰壶更漂亮
当你的 curl 输出变得更复杂时,它可能变得难以阅读。使用这个或其他技巧来美化 curl 返回的 json:
# 指示部分将输出通过管道传输到 json_pp 并要求它使您的 JSON 更漂亮。(或者使用任何你喜欢的工具!)
# v------------------v
curl -v localhost:8080/employees/1 | json_pp
单个员工的 RESTful 表示
{
"id": 1,
"name": "Bilbo Baggins",
"role": "burglar",
"_links": {
"self": {
"href": "http://localhost:8080/employees/1"
},
"employees": {
"href": "http://localhost:8080/employees"
}
}
}
这个解压缩的输出不仅显示了您之前看到的数据元素(id 和 name)role,而且还显示了一个_links 包含两个 URI 的条目。整个文档使用 HAL 进行格式化。
HAL 是一种轻量级媒体类型,它不仅可以编码数据,还可以编码超媒体控件,提醒消费者注意他们可以导航的 API 的其他部分。在这种情况下,有一个“自我”链接(有点像 this 代码中的语句)以及一个返回聚合根的链接。
为了使聚合根 ALSO 更加 RESTful,您希望包括顶级链接,同时还包括其中的任何 RESTful 组件。
所以我们把这个
获取聚合根
进入这个
获取聚合根源
哇!曾经的那个方法,repository.findAll()都长大了!不用担心。让我们打开它。
CollectionModel<>是另一个 Spring HATEOAS 容器;它旨在封装资源集合,而不是像 EntityModel<>之前那样封装单个资源实体。CollectionModel<>,也可以让您包含链接。
不要让第一个声明溜走。“封装集合”是什么意思?员工收藏?
不完全的。
由于我们谈论的是 REST,它应该封装员工资源的集合。
这就是为什么您获取所有员工,然后将它们转换为 EntityModel<Employee>对象列表的原因。(感谢 Java 8 流!)
如果您重新启动应用程序并获取聚合根,您可以看到它现在的样子。
员工资源集合的 RESTful 表示
对于提供员工资源集合的聚合根,有一个顶级“自我”链接。“集合”列在“_embedded”部分下方;这就是 HAL 表示集合的方式。
并且集合的每个单独成员都有他们的信息以及相关链接。
添加所有这些链接有什么意义?它使得随着时间的推移发展 REST 服务成为可能。可以维护现有链接,而将来可以添加新链接。新客户可以利用新链接,而旧客户可以在旧链接上维持自己的生命。如果服务被重新定位和移动,这将特别有用。只要保持链接结构,客户端仍然可以找到事物并与之交互。
简化链接创建
在前面的代码中,您是否注意到单个员工链接创建中的重复?为员工提供单个链接以及创建到聚合根的“员工”链接的代码显示了两次。如果这引起了您的关注,很好!有一个解决方案。
简单地说,你需要定义一个将 Employee 对象转换为 EntityModel<Employee>对象的函数。虽然您可以轻松地自己编写此方法,但在实现 Spring HATEOAS 的 RepresentationModelAssembler 接口的道路上也有好处——它将为您完成工作。
进化/src/main/java/payroll/EmployeeModelAssembler.java
这个简单的接口有一个方法:toModel(). 它基于将非模型对象 ( Employee) 转换为基于模型的对象 ( EntityModel<Employee>)。
您之前在控制器中看到的所有代码都可以移到此类中。并且通过应用 Spring Framework 的 @Component 注解,将在应用程序启动时自动创建汇编程序。
Spring HATEOAS 的所有模型的抽象基类是 RepresentationModel. 但是为了简单起见,我建议使用 EntityModel<T>作为您的机制来轻松地将所有 POJO 包装为模型。
要利用此汇编器,您只需 EmployeeController 通过在构造函数中注入汇编器来更改 。
将 EmployeeModelAssembler 注入控制器
从这里,您可以在单项员工方法中使用该汇编程序:
使用汇编程序获取单项资源
这段代码几乎是一样的,除了不是在 EntityModel<Employee>这里创建实例,而是将它委托给汇编器。也许这看起来并不多。
在聚合根控制器方法中应用相同的东西更令人印象深刻:
使用汇编程序获取聚合根资源
同样,代码几乎相同,但是您可以将所有 EntityModel<Employee>创建逻辑替换为 map(assembler::toModel). 由于 Java 8 方法引用,插入它并简化您的控制器非常容易。
Spring HATEOAS 的一个关键设计目标是让 The Right Thing™ 变得更容易。在这种情况下:将超媒体添加到您的服务中,而无需对事物进行硬编码。
在这个阶段,您已经创建了一个实际生成超媒体驱动内容的 Spring MVC REST 控制器!不讲 HAL 的客户端可以在使用纯数据时忽略额外的位。使用 HAL 的客户可以浏览您授权的 API。
但这并不是使用 Spring 构建真正的 RESTful 服务所需的唯一内容。
......未完待续......
以上就是今天关于 Spring 的一些讨论,对你有帮助吗?如果你有兴趣深入了解,欢迎到留言交流!
评论