为 RESTful 服务实现 HATEOAS

HATEOAS

HATEOAS 是 Hypermedia as the Engine of Application State 的缩写。超媒体指的是包含指向其他媒体(如图像、视频和文本)的链接的内容。它是 REST 应用程序的一个组成部分,将其与其他网络架构区分开。使用 HATEOAS,客户端通过超媒体从网络应用程序中获取动态信息,应用服务器通过超媒体提供信息。

Spring-HATEOAS

Spring-HATEOAS 是一组 API。我们可以在使用 Spring MVC 时,使用这些 API 创建遵循 HATEOAS 原则的 REST 表示。

在 Spring HATEOAS 项目中,我们不需要使用 Servlet 上下文,并且也不需要将路径变量连接到基本 URI。取而代之,Spring HATEOAS 提供了三个抽象用于创建 URI:ControllerLinkBuilder、LinkResourceSupport。我们可以使用这些抽象来创建与资源表示相关联的元数据。

Features

  • 它支持类似 HAL 的超媒体格式。
  • 它提供了创建指向 MVC 控制器方法的链接的 Link builder API
  • 它提供了链接、资源表示模型的 Model classes

Spring Boot 执行以下任务:

  • 配置 HAL 支持
  • 注册支持实体链接
  • 配置消息转换器支持

假设我们请求了一个 GET 请求,如 localhost:8080/users/1,它会返回用户 ID 为 1 的详细信息。除此之外,它还返回一个名为 link 的字段,其中包含一个指向所有用户的链接(localhost:8080/users),以便消费者可以检索所有用户。这个概念就是 HATEOAS

让我们在项目中实现 HATEOAS。

步骤 1: 打开 pom.xml 文件并添加 spring-boot-starter-hateoas 依赖。

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

步骤 2: 打开 UserResource.java 文件,复制 retrieveUser() 方法。

步骤 3: 粘贴该方法并进行以下更改:

  • 创建 Resource 类的构造函数。
Resource<User> resource = new Resource<User>(User)  

请注意,导入 org.springframework.hateoas 包中的 Resource 类。

  • 使用 ControllerLinkBuilder 类添加链接,以检索所有用户。它使我们能够从方法中创建链接。
  • 导入 ControllerLinkBuilder
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.
  • 使用 ControllerLinkBuilder 类的 linkTo() 方法。它使用给定控制器类上注释的映射创建一个新的 ControllerLinkBuilder 实例。
ControllerLinkBuilder linkTo=linkTo(methodOn(this.getClass().retrieveAllUsers());  

其中,methodOn()DummyInvocationUtils.methodOn(class, Object) 的包装器,以便在静态导入 ControllerLinkBuilder 时可用。

  • 将此链接添加到资源中,并指定在 HATEOAS 中要使用的名称。
resource.add(linkTo.withRel("all-users"));  

withRel(String rel) 是一种方法,用于使用当前构建器实例创建由给定的 rel 关联构建的链接。rel 参数不能为空。

  • 将返回类型从用户更改为 Resource,并将方法的返回类型更改为 Resource

经过以上更改,UserResource.java 文件如下所示:

package cn.javatiku.server.main.user;  
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;  
import java.net.URI;  
import java.util.List;  
import javax.validation.Valid;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.hateoas.Resource;  
import org.springframework.hateoas.mvc.ControllerLinkBuilder;  
import org.springframework.http.ResponseEntity;  
import org.springframework.web.bind.annotation.DeleteMapping;  
import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.PathVariable;  
import org.springframework.web.bind.annotation.PostMapping;  
import org.springframework.web.bind.annotation.RequestBody;  
import org.springframework.web.bind.annotation.RestController;  
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;  
@RestController  
public class UserResource   
{  
@Autowired  
private UserDaoService service;  
@GetMapping("/users")  
public List<User> retriveAllUsers()  
{  
return service.findAll();  
}  
@GetMapping("/users/{id}")  
public Resource<User> retriveUser(@PathVariable int id)  
{  
User user= service.findOne(id);  
if(user==null)  
//runtime exception  
throw new UserNotFoundException("id: "+ id);  
//"all-users", SERVER_PATH + "/users"  
//retrieveAllUsers  
Resource<User> resource=new Resource<User>(user);   //constructor of Resource class  
//add link to retrieve all the users  
ControllerLinkBuilder linkTo=linkTo(methodOn(this.getClass()).retriveAllUsers());  
resource.add(linkTo.withRel("all-users"));  
return resource;  
}  
//method that delete a user resource  
@DeleteMapping("/users/{id}")  
public void deleteUser(@PathVariable int id)  
{  
User user= service.deleteById(id);  
if(user==null)  
//runtime exception  
throw new UserNotFoundException("id: "+ id);  
}  
//method that posts a new user detail and returns the status of the user resource  
@PostMapping("/users")  
public ResponseEntity<Object> createUser(@Valid @RequestBody User user)     
{  
User sevedUser=service.save(user);    
URI location=ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(sevedUser.getId()).toUri();  
return ResponseEntity.created(location).build();  
}  
}  

步骤 4: 打开 REST 客户端 Postman,发送一个 GET 请求。

restful-web-services-hateoas.png

在这里,我们可以看到它返回用户以及一个名为 all-users 的链接,以便访问所有用户。现在点击该链接并再次发送 GET 请求。它返回所有用户的列表,如下图所示。
restful-web-services-hateoas2.png

标签: spring, Spring教程, Spring语言学习, Spring框架, Spring框架教程, Spring框架高级教程, spring boot, spring boot入门教程, spring boot学习教程, spring boot下载, spring boot框架入门, spring boot面试题, spring boot笔试题, spring boot技术, ot学习指南