You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置Spring Data REST返回带模板化ID的链接如users/{id}

如何让Spring Data REST生成实体的模板化链接?

我有一个针对User实体的Spring Data仓库,Spring Data REST在根路径返回的HAL JSON如下:

{
  "_links": {
    "users": {
      "href": "http://localhost:8080/users"
    }
  }
}

我希望客户端能知晓,可以通过http://localhost:8080/users/{id}(比如http://localhost:8080/users/25)获取特定用户,期望Spring Data REST返回这样的格式:

{
  "_links": {
    "users": {
      "href": "http://localhost:8080/users/{id}",
      "templated": true
    }
  }
}

更新1

我想要实现类似GitHub API的效果——API根路径明确标识/users/{user}是可用接口,比如/users/odrotbohm是有效请求地址。怎么让Spring Data REST也把http://localhost:8080/users/{id}标识为API的一部分?

更新2

CrudRepository会提供http://localhost:8080/users/{id}这类模板化链接吗?我没看到。我用的是JavaScript Traverson HAL客户端,缺少这个链接的话没法遍历到特定用户。

更新3

以下是完整的示例代码:

build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.2'
    id 'io.spring.dependency-management' version '1.1.2'
}

group = 'com.example'
version = '1.0'

java {
    sourceCompatibility = '17'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-data-rest'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

项目文件

TaversonIssueApplication.java

@SpringBootApplication
public class TaversonIssueApplication {

    public static void main(String[] args) {
        SpringApplication.run(TaversonIssueApplication.class, args);
    }

}

User.java

@Entity
@Table(name="`User`")
@Data
public class User {
 
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
}

UserRepository.java

public interface UserRepository extends CrudRepository<User, Long> {
}

初始化数据(src/main/resources)

INSERT INTO "user" (name) VALUES ('bob');
INSERT INTO "user" (name) VALUES ('sally');

启动应用后,请求http://localhost:8080/得到的响应是:

{
  "_links" : {
    "users" : {
      "href" : "http://localhost:8080/users"
    },
    "profile" : {
      "href" : "http://localhost:8080/profile"
    }
  }
}

客户端没法从这个响应知道http://localhost:8080/users/1是有效链接,Traverson HAL客户端也没法从根路径遍历到该地址,核心问题就是缺少http://localhost:8080/users/{id}这种模板化链接。

有没有办法让Spring Data REST在根路径响应中返回这样的模板化链接?


解决方案

方法1:自定义资源处理器(ResourceProcessor)

通过实现RepresentationModelProcessor<RepositoryLinksResource>来修改根路径的链接,添加模板化的单用户链接:

import org.springframework.data.rest.webmvc.RepositoryLinksResource;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.server.RepresentationModelProcessor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

@Component
public class RootResourceProcessor implements RepresentationModelProcessor<RepositoryLinksResource> {

    @Override
    public RepositoryLinksResource process(RepositoryLinksResource resource) {
        // 动态获取当前上下文的Base URL,避免硬编码
        String baseUrl = ServletUriComponentsBuilder.fromCurrentContextPath().build().toUriString();
        // 添加模板化单用户链接,标记为templated=true
        Link userTemplateLink = Link.of(baseUrl + "/users/{id}", "user")
                                    .withTemplated(true);
        resource.add(userTemplateLink);
        return resource;
    }
}

这样根路径响应会新增一个user链接,格式完全符合需求。

方法2:利用Spring Data REST原生的Profile端点

Spring Data REST默认提供的/profile端点包含实体的完整API元数据,其中就有单实体的模板化链接。引导客户端访问/profile/users,会得到如下响应:

{
  "_links": {
    "self": {
      "href": "http://localhost:8080/profile/users"
    },
    "collection": {
      "href": "http://localhost:8080/users"
    },
    "item": {
      "href": "http://localhost:8080/users/{id}",
      "templated": true
    }
  }
}

这是Spring Data REST原生支持的方案,不需要额外编码,适合能兼容先查询profile信息的客户端。

方法3:自定义根控制器

直接编写控制器覆盖默认根路径响应,手动添加所有必要链接:

import org.springframework.hateoas.Link;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

@RestController
public class CustomRootController {

    @GetMapping("/")
    public RepresentationModel<?> root() {
        RepresentationModel<?> model = new RepresentationModel<>();
        String baseUrl = ServletUriComponentsBuilder.fromCurrentContextPath().build().toUriString();
        
        // 添加集合链接
        model.add(Link.of(baseUrl + "/users", "users"));
        // 添加模板化单用户链接
        model.add(Link.of(baseUrl + "/users/{id}", "user").withTemplated(true));
        // 添加默认的profile链接
        model.add(Link.of(baseUrl + "/profile", "profile"));
        
        return model;
    }
}

注意这种方式会完全替换Spring Data REST的默认根路径响应,需要确保包含所有业务需要的链接。

内容的提问来源于stack exchange,提问作者James

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 16:45:55