Spring Boot中用HATEOAS构建接口需围绕资源建模→链接注入→统一响应结构主线,通过EntityModel包装单个资源、CollectionModel包装集合并注入类型安全链接,支持自定义关系与URI模板。

在 Spring Boot 中用 HATEOAS 构建接口,核心是让返回的资源自带可操作链接,而不是靠文档或硬编码 URL 告诉客户端“下一步该访问哪里”。它不是加个注解就完事,而是要围绕 资源建模 → 链接注入 → 统一响应结构 这条主线来组织代码。
添加依赖并启用自动配置
Spring Boot 3.x 起,spring-boot-starter-hateoas 已与 Spring Web 紧密集成,但仍需显式引入:
- 在
pom.xml中添加:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-hateoas</artifactId> </dependency>
- 无需额外配置类,启动类保持
@SpringBootApplication即可。Spring HATEOAS 会自动注册EntityModel、CollectionModel等类型转换器。
用 EntityModel 包装单个资源并添加链接
不要直接返回 Book 实体,而应包装成 EntityModel<book></book>,再手动或自动注入链接:
- 基础写法(手动构建):
@GetMapping("/books/{id}") public EntityModel<Book> getBook(@PathVariable Long id) { Book book = bookService.findById(id); return EntityModel.of(book, linkTo(methodOn(BookController.class).getBook(id)).withSelfRel(), linkTo(methodOn(BookController.class).getAllBooks()).withRel("books") ); } -
linkTo(methodOn(...))利用控制器方法生成类型安全的 URI,避免字符串拼接出错;withSelfRel()表示当前资源自身,withRel("books")表示关联资源关系名。 - 返回结果中会自动包含
_links字段(Spring HATEOAS 默认使用下划线前缀),例如:{ "id": 1, "title": "The Hobbit", "_links": { "self": { "href": "http://localhost:8080/books/1" }, "books": { "href": "http://localhost:8080/books" } } }
用 CollectionModel 包装列表并支持分页导航
对集合资源,用 CollectionModel 替代原始 List,并注入分页相关链接(如 first/next/prev/last):
- 配合 Spring Data JPA 的
Page使用更自然:@GetMapping("/books") public CollectionModel<EntityModel<Book>> getAllBooks( @PageableDefault(size = 10) Pageable pageable) { Page<Book> page = bookRepository.findAll(pageable); // 将每本书转为 EntityModel List<EntityModel<Book>> bookModels = page.getContent().stream() .map(book -> EntityModel.of(book, linkTo(methodOn(BookController.class).getBook(book.getId())).withSelfRel())) .toList(); // 构建集合模型,并添加分页链接 return CollectionModel.of(bookModels, linkTo(methodOn(BookController.class).getAllBooks(null)).withSelfRel(), linkTo(methodOn(BookController.class).getAllBooks(PageRequest.of(0, 10))).withRel("first"), linkTo(methodOn(BookController.class).getAllBooks(page.nextPageable())).withRel("next") ); } - 若使用
@RepositoryRestResource(Spring Data REST),分页链接会全自动注入,但灵活性较低;手动控制更适合定制化场景。
自定义链接关系与 URI 模板
除了 self、collection 等标准关系,你可定义业务语义化的 rel,比如 publish、approve,甚至带参数的动态链接:
- 使用
UriTemplate支持路径变量和查询参数:Link publishLink = linkTo(methodOn(BookController.class) .publishBook("{id}", "{version}")) .withRel("publish") .expand(Map.of("id", "123", "version", "2")); - 关系名建议用小写字母+短横线(如
author、related-posts),避免空格和大写;优先复用IanaLinkRelations中的标准值(如SELF、NEXT)。 - 链接中的 HTTP 方法默认为 GET,如需声明其他方法(如 POST),需在前端或文档中另行说明——HATEOAS 规范本身不强制携带 method 字段,但部分客户端(如 HAL Browser)会识别扩展字段。


















