为Spring Boot 启用超媒体支持
超媒体是一种创建自描述API的方式,即API所返回的资源中会包含相关资源的链接,客户端只需要了解最少的API URL 信息就能导航整个应用API。
Spring HATEOAS项目为Spring提供了超链接的支持,它提供了一些类和资源装配器(assembler),在SpringMVC控制器返回资源之前能够为其添加链接。
⒈,添加hateoas starter依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-hateoas</artifactId> </dependency>
⒉,创建实体,实体资源类【即可以携带链接信息的实体】,转换工具类
1.实体类
public class User { private int id; private String username; private String password; private int age; public User() { } public User(int id, String username, String password, int age) { this.id = id; this.username = username; this.password = password; this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", age=" + age + '}'; }
2,实体资源类【即可以携带链接信息的实体】,通过继承 RepresentationModel,从而继承了一个Link对象的列表和管理链接列表的方法。
import org.springframework.hateoas.RepresentationModel; import org.springframework.hateoas.server.core.Relation; /** * User的资源类,即在User类的基础上携带资源链接 * 用于替换 EntityModel * 通过继承 RepresentationModel,从而继承了一个Link对象的列表和管理链接列表的方法 */ @Relation(value = "user", collectionRelation = "users") //规定json中Key的名称,默认为资源名称 public class UserEntityModel extends RepresentationModel<UserEntityModel> { // 和User实体具有相同的属性 private int id; private String username; private String password; private int age; //接收User对象并复制相关属性 public UserEntityModel(User user){ this.id = user.getId(); this.username = user.getUsername(); this.password = user.getPassword(); this.age = user.getAge(); } public int getId() { return id; } public String getUsername() { return username; } public String getPassword() { return password; } public int getAge() { return age; } }
3,转换工具类【资源适配器】
import org.springframework.hateoas.server.mvc.RepresentationModelAssemblerSupport; /** * 资源装配器 * 一个将User对象转换为可以携带资源链接的User封装类的工具类 */ public class UserRepresentationModelAssembler extends RepresentationModelAssemblerSupport<User, UserEntityModel> { /** * 默认构造器,将告诉父类在创建User封装类中的链接时 * 将会使用 UserController 来确定所有URL的基础路径 */ public UserRepresentationModelAssembler(){ super(UserController.class,UserEntityModel.class); } /** * 基于 User实例创建User封装类实例。 * 如果 User封装类有默认构造器,则该方法是可选的 * @param entity * @return */ @Override protected UserEntityModel instantiateModel(User entity) { return new UserEntityModel(entity); } /** * 基于 User实例创建User封装类实例并填充其self链接属性 * 以下代码是指链接的URL是根据User对象的id属性确定的。 * toModel()方法在创建实例时将会调用instantiateModel()方法 * @param entity * @return */ @Override public UserEntityModel toModel(User entity) { return createModelWithId(entity.getId(),entity); } }
⒊,更改控制器代码
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * 对API响应内容启用超媒体支持 * 即API返回的资源信息中会包含相关资源的链接 * Spring HATEOAS项目为Spring提供了超链接支持,在SpringMVC控制器返回资源之前能够为其添加链接 * EntityModel代表资源,CollectionModel代表某种资源的集合 */ @RestController @RequestMapping("/user") public class UserController { @Autowired private UserRepository userRepository; @GetMapping("/get") public ResponseEntity<List<User>> getUsers(){ ResponseEntity<List<User>> datas = ResponseEntity.ok(userRepository.getUsers()); return datas; } @GetMapping("/get2") public CollectionModel<EntityModel<User>> getUsersWithR(){ List<User> userList = userRepository.getUsers(); CollectionModel<EntityModel<User>> recentCollectionModel = CollectionModel.wrap(userList); //recentCollectionModel.add(Link.of("http://localhost:10035/user/get2","recents")); //垃圾的硬编码形式 //recentCollectionModel.add(WebMvcLinkBuilder.linkTo(UserController.class).slash("get2").withRel("recents")); //方式1,还是有硬编码的因素 recentCollectionModel.add(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(UserController.class).getUsersWithR()).withRel("recents")); //方式2,推荐 return recentCollectionModel; } @GetMapping("/get3") public CollectionModel<UserEntityModel> getUserWithA(){ List<User> userList = userRepository.getUsers(); UserRepresentationModelAssembler assembler = new UserRepresentationModelAssembler(); CollectionModel<UserEntityModel> modelList = assembler.toCollectionModel(userList); //为用户列表添加资源链接 modelList.add(WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(UserController.class).getUserWithA()).withRel("recents")); //为根节点添加资源链接 return modelList; } }