什么是 HATEOAS ?超媒体作为应用程序状态引擎是 REST 应用程序架构的约束之一。
HATEOAS 将显示给定资源的相关链接的概念引入了 RESTful 服务。当我们返回特定资源的详细信息时,我们还会返回指向可以对该资源执行的操作的链接,以及指向相关资源的链接。如果服务消费者可以使用响应中的链接来执行事务,那么它就不需要对所有链接进行硬编码。
让我们在实践中看看如何做到这一点。使用“web”和“hateoas”启动器构建一个新项目:
spring init -dweb,hateoas demo-hateoas
将包括以下依赖项:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
为简单起见,我们将创建一个 In-Memory 存储库以使用 hatoas 进行查询,如本教程所述:如何在 Spring Boot 中定义模拟存储库
让我们从模型开始:
package com.example.demohateoas.model;
public class Customer {
private final Long id;
private final String firstName;
private final String lastName;
public Customer(Long id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public Long getId() {
return this.id;
}
public String getFirstName() {
return this.firstName;
}
public String getLastName() {
return this.lastName;
}
}
我们将添加一个简单的界面:
package com.example.demohateoas;
import java.util.List;
public interface CustomerRepository {
List<Customer> findAll();
Customer findCustomer(Long id);
}
现在我们将定义一个使用@Repository 标记的接口的实现:
package com.example.demohateoas;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Repository;
import org.springframework.util.ObjectUtils;
@Repository
public class MockCustomerRepository implements CustomerRepository {
private final List<Customer> customers = new ArrayList<>();
public MockCustomerRepository() {
this.customers.add(new Customer(1L, "John", "Smith"));
this.customers.add(new Customer(2L, "Mark", "Spencer"));
this.customers.add(new Customer(2L, "Andy", "Doyle"));
}
@Override
public List<Customer> findAll() {
return this.customers;
}
@Override
public Customer findOne(Long id) {
for (Customer customer : this.customers) {
if (ObjectUtils.nullSafeEquals(customer.getId(), id)) {
return customer;
}
}
return null;
}
}
最有趣的部分来了。我们将添加一个控制器来利用响应中的链接:
package com.example.demohateoas.controller;
import org.springframework.hateoas.EntityLinks;
import org.springframework.hateoas.ExposesResourceFor;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.demohateoas.model.Customer;
import com.example.demohateoas.model.CustomerRepository;
@Controller
@RequestMapping("/customers")
@ExposesResourceFor(Customer.class)
public class CustomerController {
private final CustomerRepository repository;
private final EntityLinks entityLinks;
public CustomerController(CustomerRepository repository, EntityLinks entityLinks) {
this.repository = repository;
this.entityLinks = entityLinks;
}
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
HttpEntity<Resources<Customer>> showCustomers() {
Resources<Customer> resources = new Resources<>(this.repository.findAll());
resources.add(this.entityLinks.linkToCollectionResource(Customer.class));
return new ResponseEntity<>(resources, HttpStatus.OK);
}
@GetMapping(path = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
HttpEntity<Resource<Customer>> showCustomer(@PathVariable Long id) {
Resource<Customer> resource = new Resource<>(this.repository.findOne(id));
resource.add(this.entityLinks.linkToSingleResource(Customer.class, id));
return new ResponseEntity<>(resource, HttpStatus.OK);
}
}
如您所见,从 GET 请求返回的关键类是 org.springframework.hateoas.Resource 和 org.springframework.hateoas.Resources,它们是简单的 Resources 包装了能够向其添加链接的域对象。如果必须使用链接丰富单个资源,则使用方法 linkToSingleResource。另一方面,对于集合,则使用linkToCollectionResource。
Main 应用程序类完成了应用程序:
package com.example.demohateoas;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
如果您构建并运行应用程序,您将看到在 Root Web 上下文和 /{id} 路径中都提供了一个链接,以启用导航:
在本教程中,我们了解了 HATEOAS 如何通过在响应中包含超媒体链接来提供信息以动态导航站点的 REST 接口。然而,这种能力不同于基于 SOA 的系统和 WSDL 驱动的接口,服务器和客户端通常必须访问一个固定的规范,该规范可能在网站的其他地方、另一个网站上进行。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
内容来源于网络,如有侵权,请联系作者删除!