Blogger Information
Blog 29
fans 0
comment 0
visits 17910
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
2022就业季|Spring认证教你,如何使用 Spring 构建 REST 服务(三)
IT胶囊
Original
403 people have browsed it

书接上文⬆⬆⬆

是什么让一些东西变得 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

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-hateoas</artifactId></dependency>复制

这个小型库将为我们提供定义 RESTful 服务的结构,然后以可接受的格式呈现它以供客户使用。

任何 RESTful 服务的一个关键要素是添加指向相关操作的链接。要使您的控制器更加 RESTful,请添加如下链接:

获取单个项目的资源

@GetMapping("/employees/{id}")EntityModel<Employee> one(@PathVariable Long id) {  Employee employee = repository.findById(id) //      .orElseThrow(() -> new EmployeeNotFoundException(id));  return EntityModel.of(employee, //      linkTo(methodOn(EmployeeController.class).one(id)).withSelfRel(),      linkTo(methodOn(EmployeeController.class).all()).withRel("employees"));}

本教程基于 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 组件。

所以我们把这个

获取聚合根

@GetMapping("/employees")List<Employee> all() {  return repository.findAll();}

进入这个

获取聚合根源

@GetMapping("/employees")CollectionModel<EntityModel<Employee>> all() {  List<EntityModel<Employee>> employees = repository.findAll().stream()      .map(employee -> EntityModel.of(employee,          linkTo(methodOn(EmployeeController.class).one(employee.getId())).withSelfRel(),          linkTo(methodOn(EmployeeController.class).all()).withRel("employees")))      .collect(Collectors.toList());  return CollectionModel.of(employees, linkTo(methodOn(EmployeeController.class).all()).withSelfRel());}

哇!曾经的那个方法,repository.findAll()都长大了!不用担心。让我们打开它。

CollectionModel<>是另一个 Spring HATEOAS 容器;它旨在封装资源集合,而不是像EntityModel<>之前那样封装单个资源实体。CollectionModel<>,也可以让您包含链接。

不要让第一个声明溜走。“封装集合”是什么意思?员工收藏?

不完全的。

由于我们谈论的是 REST,它应该封装员工资源的集合。

这就是为什么您获取所有员工,然后将它们转换为EntityModel<Employee>对象列表的原因。(感谢 Java 8 流!)

如果您重新启动应用程序并获取聚合根,您可以看到它现在的样子。

员工资源集合的 RESTful 表示

{  "_embedded": {    "employeeList": [      {        "id": 1,        "name": "Bilbo Baggins",        "role": "burglar",        "_links": {          "self": {            "href": "http://localhost:8080/employees/1"          },          "employees": {            "href": "http://localhost:8080/employees"          }        }      },      {        "id": 2,        "name": "Frodo Baggins",        "role": "thief",        "_links": {          "self": {            "href": "http://localhost:8080/employees/2"          },          "employees": {            "href": "http://localhost:8080/employees"          }        }      }    ]  },  "_links": {    "self": {      "href": "http://localhost:8080/employees"    }  }}复制

对于提供员工资源集合的聚合根,有一个顶级“自我”链接。“集合”列在“_embedded”部分下方;这就是 HAL 表示集合的方式。

并且集合的每个单独成员都有他们的信息以及相关链接。

添加所有这些链接有什么意义?它使得随着时间的推移发展 REST 服务成为可能。可以维护现有链接,而将来可以添加新链接。新客户可以利用新链接,而旧客户可以在旧链接上维持自己的生命。如果服务被重新定位和移动,这将特别有用。只要保持链接结构,客户端仍然可以找到事物并与之交互。

简化链接创建

在前面的代码中,您是否注意到单个员工链接创建中的重复?为员工提供单个链接以及创建到聚合根的“员工”链接的代码显示了两次。如果这引起了您的关注,很好!有一个解决方案。

简单地说,你需要定义一个将Employee对象转换为EntityModel<Employee>对象的函数。虽然您可以轻松地自己编写此方法,但在实现 Spring HATEOAS 的
RepresentationModelAssembler接口的道路上也有好处——它将为您完成工作。

进化
/src/main/java/payroll/EmployeeModelAssembler.java

package payroll;import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;import org.springframework.hateoas.EntityModel;import org.springframework.hateoas.server.RepresentationModelAssembler;import org.springframework.stereotype.Component;@Componentclass EmployeeModelAssembler implements RepresentationModelAssembler<Employee, EntityModel<Employee>> {  @Override  public EntityModel<Employee> toModel(Employee employee) {    return EntityModel.of(employee, //        linkTo(methodOn(EmployeeController.class).one(employee.getId())).withSelfRel(),        linkTo(methodOn(EmployeeController.class).all()).withRel("employees"));  }}复制

这个简单的接口有一个方法:toModel(). 它基于将非模型对象 ( Employee) 转换为基于模型的对象 ( EntityModel<Employee>)。

您之前在控制器中看到的所有代码都可以移到此类中。并且通过应用 Spring Framework 的@Component注解,将在应用程序启动时自动创建汇编程序。

Spring HATEOAS 的所有模型的抽象基类是RepresentationModel. 但是为了简单起见,我建议使用EntityModel<T>作为您的机制来轻松地将所有 POJO 包装为模型。

要利用此汇编器,您只需EmployeeController通过在构造函数中注入汇编器来更改 。

将 EmployeeModelAssembler 注入控制器

@RestControllerclass EmployeeController {  private final EmployeeRepository repository;  private final EmployeeModelAssembler assembler;  EmployeeController(EmployeeRepository repository, EmployeeModelAssembler assembler) {    this.repository = repository;    this.assembler = assembler;  }  ...}

从这里,您可以在单项员工方法中使用该汇编程序:

使用汇编程序获取单项资源

@GetMapping("/employees/{id}")EntityModel<Employee> one(@PathVariable Long id) {  Employee employee = repository.findById(id) //      .orElseThrow(() -> new EmployeeNotFoundException(id));  return assembler.toModel(employee);}

这段代码几乎是一样的,除了不是在EntityModel<Employee>这里创建实例,而是将它委托给汇编器。也许这看起来并不多。

在聚合根控制器方法中应用相同的东西更令人印象深刻:

使用汇编程序获取聚合根资源

@GetMapping("/employees")CollectionModel<EntityModel<Employee>> all() {  List<EntityModel<Employee>> employees = repository.findAll().stream() //      .map(assembler::toModel) //      .collect(Collectors.toList());  return CollectionModel.of(employees, linkTo(methodOn(EmployeeController.class).all()).withSelfRel());}

同样,代码几乎相同,但是您可以将所有EntityModel<Employee>创建逻辑替换为map(assembler::toModel). 由于 Java 8 方法引用,插入它并简化您的控制器非常容易。

Spring HATEOAS 的一个关键设计目标是让 The Right Thing™ 变得更容易。在这种情况下:将超媒体添加到您的服务中,而无需对事物进行硬编码。

在这个阶段,您已经创建了一个实际生成超媒体驱动内容的 Spring MVC REST 控制器!不讲 HAL 的客户端可以在使用纯数据时忽略额外的位。使用 HAL 的客户可以浏览您授权的 API。

但这并不是使用 Spring 构建真正的 RESTful 服务所需的唯一内容。

......未完待续......

#java##spring认证##spring认证##程序员#

2022就业季|Spring认证教你,如何使用 Spring 构建 REST 服务

2022就业季|Spring认证教你,如何使用 Spring 构建 REST 服务(二)

以上就是今天关于Spring的一些讨论,对你有帮助吗?如果你有兴趣深入了解,欢迎到Spring中国教育管理中心留言交流!


Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post