1. 简介

Spring Data REST 能帮我们省掉大量 REST 服务中重复性的模板代码。

本文将带你了解如何 对 Spring Data REST 默认的 HTTP 接口行为进行定制化配置

2. Spring Data REST Repository 基础知识

首先,我们创建一个空接口并继承 CrudRepository,指定实体类型和主键类型:

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

默认情况下,✅ Spring 会自动生成所有必要的映射路径,并为每个资源绑定合适的 HTTP 方法,返回正确的状态码。

如果不需要 CrudRepository 提供的所有方法,可以继承更基础的 Repository 接口,并 只暴露我们需要的方法

public interface UserRepository extends Repository<WebsiteUser, Long> {
  void deleteById(Long aLong);
}

当收到请求时,Spring 会根据 HTTP 方法和资源类型来调用接口中对应的方法(如果存在),否则返回 HTTP 状态码 ❌ 405 Method Not Allowed

比如上面的例子中,收到 DELETE 请求时,就会执行我们定义的 deleteById 方法。

3. 限制暴露的 HTTP 方法

假设我们有一个用户管理系统,对应的 UserRepository 继承了 CrudRepository

@RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserRepository extends CrudRepository<WebsiteUser, Long> {}

此时,所有的 CRUD 操作都被暴露出来。例如执行如下命令:

curl -v -X DELETE http://localhost:8080/users/<existing_user_id>

会返回 ✅ HTTP 状态码 204 No Content,表示删除成功。

但如果现在我们希望 ❌ 对外隐藏 delete 操作,而内部仍然可以使用该方法,该怎么办?

我们可以在接口中显式声明 deleteById 方法,并加上注解 *@RestResource(exported = false)*,告诉 Spring Data REST 不要对外暴露这个方法:

@Override
@RestResource(exported = false)
void deleteById(Long aLong);

再次执行同样的 DELETE 请求,就会收到 ❌ 405 Method Not Allowed 的响应。

4. 自定义支持的 HTTP 方法

@RestResource 注解不仅可以控制方法是否暴露,还可以用来 自定义 URL 路径和 HATEOAS 返回的链接 ID

它的两个常用参数是:

  • path:用于设置 URL 路径
  • rel:用于设置 JSON 中的 link ID

继续以 UserRepository 为例,我们添加一个 findByEmail 查询方法:

WebsiteUser findByEmail(@Param("email") String email);

访问 http://localhost:8080/users/search/ 可以看到新方法出现在返回结果中:

{
  "_links": {
    "findByEmail": {
      "href": "http://localhost:8080/users/search/findByEmail{?email}"
    },
    "self": {
      "href": "http://localhost:8080/users/search/"
    }
  }
}

如果你不喜欢默认生成的路径名,可以直接通过 @RestResource 来修改,而无需更改方法名:

@RestResource(path = "byEmail", rel = "customFindMethod")
WebsiteUser findByEmail(@Param("email") String email);

重新访问后,返回的 JSON 就会变成:

{
  "_links": {
    "customFindMethod": {
      "href": "http://localhost:8080/users/search/byEmail{?email}",
      "templated": true
    },
    "self": {
      "href": "http://localhost:8080/users/search/"
    }
  }
}

5. 编程式配置

有时我们需要更精细地控制哪些 HTTP 方法可以被暴露。比如,集合资源上的 POST、单个资源上的 PUT 和 PATCH 都会调用同一个 save 方法。

✅ 从 Spring Data REST 3.1 开始(对应 Spring Boot 2.1),我们可以通过 ExposureConfiguration 类来 针对特定 HTTP 方法进行暴露控制

它提供了一个基于 Lambda 的 API,可以定义全局规则或按类型分别控制。

举个例子,我们可以禁止对 WebsiteUser 类型的资源执行 PATCH 请求:

public class RestConfig implements RepositoryRestConfigurer {
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration restConfig,
      CorsRegistry cors) {
        ExposureConfiguration config = restConfig.getExposureConfiguration();
        config.forDomainType(WebsiteUser.class).withItemExposure((metadata, httpMethods) ->
          httpMethods.disable(HttpMethod.PATCH));
    }
}

⚠️ 注意:这种配置方式更适合需要统一控制多个资源的场景,简单粗暴但灵活。

6. 总结

这篇文章介绍了如何在 Spring Data REST 中定制默认的 HTTP 接口行为,包括:

  • 控制方法是否暴露
  • 自定义 URL 路径与 link ID
  • 使用编程方式进行细粒度配置

如需查看完整示例代码,请前往我们的 GitHub 项目


原始标题:Customizing HTTP Endpoints in Spring Data REST