HATEOAS是REST架构中最容易被忽略的一环,很多号称RESTful的接口其实只做到了资源化,并没有提供资源之间的导航关系。HAL(Hypertext Application Language)正是为了解决这个问题而生的超媒体格式,它约定了一套简单的JSON结构,用_links字段描述当前资源可执行的操作和相关资源的地址。Spring Data REST对HAL提供了开箱即用的支持,只需要把Repository暴露出去,返回的JSON就会自动携带自链接、分页链接和关联资源链接。这篇文章完整演示Spring Boot整合Spring Data REST并输出HAL格式的全过程。

一、HAL格式到底长什么样
在动手整合之前,先花一点时间理解HAL的结构,这有助于后续阅读接口返回值。HAL在普通JSON的基础上增加了两个保留字段:_links和_embedded。_links是一个对象,键是链接关系(rel),值包含href属性,常见的rel有self表示自身地址、next和prev表示分页导航。
下面是一段典型的HAL响应,展示单个资源的表示形式:
{
"name": "张三",
"email": "zhangsan@ipipp.com",
"_links": {
"self": {
"href": "http://localhost:8080/users/1"
},
"user": {
"href": "http://localhost:8080/users/1"
}
}
}
当返回集合资源时,数据会被放进_embedded字段中,同时附带分页信息page。这种结构的好处是客户端不需要硬编码URL,直接从_links里取next链接就能翻页,接口演进时客户端几乎不用改代码。
二、整合步骤:从建项目到暴露端点
整合的第一步是引入依赖。创建一个Spring Boot项目,在pom.xml中加入以下两个starter,一个是JPA用于持久化,一个是data-rest用于自动暴露Repository:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
接着定义实体类和Repository接口。关键点在于Repository接口上不需要写任何方法,Spring Data REST会自动扫描带有@RepositoryRestResource注解的接口,并根据实体名生成REST端点:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// 省略getter和setter
}
@RepositoryRestResource(path = "users")
public interface UserRepository extends JpaRepository<User, Long> {
}
启动应用后,访问http://localhost:8080/users就能得到HAL格式的集合资源。访问根路径http://localhost:8080/还会返回一个profile入口,列出所有已暴露的资源,这本身就是HAL的超媒体导航能力的体现。默认情况下,查询方法走GET,保存走POST,更新走PUT或PATCH,删除走DELETE,全部自动生成,一行控制器代码都不用写。
三、常用配置与自定义技巧
Spring Data REST的行为可以通过配置文件精细控制。比如修改默认的基地址路径、调整分页大小、控制返回的字段:
spring.data.rest.base-path=/api spring.data.rest.default-page-size=10 spring.data.rest.max-page-size=50 spring.data.rest.return-body-on-create=true
配置之后端点会变成http://localhost:8080/api/users。有时默认暴露的资源粒度不合适,可以通过@RestResource注解隐藏某个查询方法,或者设置exported = false关闭整个Repository的暴露。如果只想暴露部分操作,建议不要直接暴露JpaRepository,而是继承CrudRepository或自定义基础接口,从源头控制可用方法。
对于返回格式的定制,可以在实体字段上使用@JsonIgnore隐藏敏感信息,或者使用Projection机制定义视图。Projection是一个接口,示例如下:
public interface UserView {
String getName();
String getEmail();
}
定义好之后,客户端在请求时加上参数?projection=UserView即可获得裁剪后的数据。需要注意HAL的媒体类型是application/hal+json,如果客户端用普通工具测试时发现返回的链接结构不符合预期,先检查请求头里的Accept设置。另外,当系统对外只需提供简单JSON而不需要超媒体时,也可以通过自定义RepositoryRestConfiguration关闭HAL渲染,不过在微服务体系内保留HAL通常利大于弊,服务间调用能借助链接发现能力降低耦合。
最后补充一点实践经验:HAL的分页信息中totalElements、totalPages等字段对前端做表格分页非常友好,配合next、prev链接可以实现无状态翻页。把这套机制用熟之后,你会发现大部分简单CRUD场景下甚至不需要手写Controller层,开发效率提升非常明显。
Spring BootSpring Data RESTHAL修改时间:2026-09-12 22:30:31