自定义 Spring Data REST

有许多选项可用于定制 Spring Data REST。以下小节将展示具体方法。spring-doc.cadn.net.cn

自定义项目资源 URI

默认情况下,单项资源的 URI 由集合资源所使用的路径段加上数据库标识符构成。 这使得你可以使用仓库的 findOne(…) 方法来查找实体实例。 从 Spring Data REST 2.5 开始,可以通过在 RepositoryRestConfiguration 上使用配置 API(在 Java 8 中推荐使用)或在应用程序中注册一个 EntityLookup 接口的实现类作为 Spring Bean 来自定义该行为。 Spring Data REST 会自动识别这些配置,并根据其实现调整 URI 的生成方式。spring-doc.cadn.net.cn

假设有一个 User 类,其 username 属性可唯一标识该用户。 进一步假设我们在相应的仓库(repository)中有一个 Optional<User> findByUsername(String username) 方法。spring-doc.cadn.net.cn

在 Java 8 中,我们可以将映射方法注册为方法引用,以调整 URI 的创建,如下所示:spring-doc.cadn.net.cn

@Component
public class SpringDataRestCustomization implements RepositoryRestConfigurer {

  @Override
  public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
    config.withEntityLookup()
      .forRepository(UserRepository.class)
      .withIdMapping(User::getUsername)
      .withLookup(UserRepository::findByUsername);
  }
}

forRepository(…) 以仓库类型作为第一个参数,以一个方法引用作为第二个参数(该方法引用将仓库的领域类型映射到某个目标类型),并使用另一个方法引用来通过第一个参数中指定的仓库将该值映射回去。spring-doc.cadn.net.cn

如果你运行的不是 Java 8 或更高版本,你仍然可以使用该方法,但需要编写一些相当冗长的匿名内部类。 在较旧的 Java 版本中,你可能更倾向于实现一个类似于以下内容的 UserEntityLookupspring-doc.cadn.net.cn

@Component
public class UserEntityLookup extends EntityLookupSupport<User> {

    private final UserRepository repository;

    public UserEntityLookup(UserRepository repository) {
        this.repository = repository;
    }

    @Override
    public Serializable getResourceIdentifier(User entity) {
        return entity.getUsername();
    }

    @Override
    public Object lookupEntity(Serializable id) {
        return repository.findByUsername(id.toString());
    }
}

请注意 getResourceIdentifier(…) 方法返回的是用于 URI 创建的用户名。为了根据该方法返回的值加载实体实例,我们现在通过使用 lookupEntity(…) 上提供的查询方法来实现 UserRepositoryspring-doc.cadn.net.cn

自定义仓库暴露

默认情况下,所有公共的 Spring Data 仓库都会被用来暴露 HTTP 资源,如 仓库资源 中所述。 受包保护(package-protected)的仓库接口会被排除在此列表之外,因为这表明其功能仅对包内部可见。 您可以通过在 RepositoryDetectionStrategy 上显式设置一个 RepositoryDetectionStrategies(通常通过枚举 RepositoryRestConfiguration)来自定义此行为。 可配置的值如下:spring-doc.cadn.net.cn

  • ALL — 暴露所有 Spring Data 仓库,无论其 Java 可见性或注解配置如何。spring-doc.cadn.net.cn

  • DEFAULT — 暴露公开的 Spring Data 仓库,或显式使用 @RepositoryRestResource 注解且其 exported 属性未设置为 false 的仓库。spring-doc.cadn.net.cn

  • VISIBILITY — 仅暴露公共的 Spring Data 仓库,而不考虑注解配置。spring-doc.cadn.net.cn

  • ANNOTATED — 仅暴露那些显式使用 @RepositoryRestResource 注解标注的 Spring Data 仓库,并且其 exported 属性未设置为 falsespring-doc.cadn.net.cn

如果需要应用自定义规则,只需手动实现 RepositoryDetectionStrategy 即可。spring-doc.cadn.net.cn

自定义支持的 HTTP 方法

自定义默认公开

默认情况下,Spring Data REST 会根据仓库所暴露的 CRUD 方法,按照仓库资源一节中所述的方式暴露 HTTP 资源和方法。 仓库无需继承 CrudRepository,也可以选择性地声明上述章节中描述的方法,资源的暴露将据此进行。 例如,如果某个仓库未暴露 delete(…) 方法,则针对单个资源的 HTTP DELETE 请求将不被支持。spring-doc.cadn.net.cn

如果你需要声明一个仅供内部使用的方法,但又不希望它触发 HTTP 方法的暴露,可以在仓库方法上添加 @RestResource(exported = false) 注解。 有关应注解哪些方法以移除对特定 HTTP 方法的支持,请参见Repository resourcesspring-doc.cadn.net.cn

有时在方法级别上管理暴露粒度还不够精细。 例如,save(…) 方法既用于集合资源上的 POST 请求,也用于单个资源上的 PUTPATCH 请求。 为了有选择地定义应暴露哪些 HTTP 方法,您可以使用 RepositoryRestConfiguration.getExposureConfiguration()spring-doc.cadn.net.cn

该类提供了一个基于 Lambda 的 API,用于定义全局规则和基于类型的规则:spring-doc.cadn.net.cn

ExposureConfiguration config = repositoryRestConfiguration.getExposureConfiguration();

config.forDomainType(User.class).disablePutForCreation(); (1)
config.withItemExposure((metadata, httpMethods) -> httpMethods.disable(HttpMethod.PATCH)); (2)
1 禁用对 HTTP PUT 方法的直接支持以创建项目资源。
2 禁用所有项资源对 HTTP PATCH 的支持。