覆盖 Spring Data REST 响应处理程序

有时,您可能希望为特定资源编写自定义处理程序。为了利用 Spring Data REST 的设置、消息转换器、异常处理等,请使用 @RepositoryRestController 注解,而不是标准的 Spring MVC @Controller@RestController。使用 @RepositoryRestController 注解的控制器将从 RepositoryRestConfiguration.setBasePath 中定义的 API 基本路径提供服务,该路径由所有其他 RESTful 端点使用(例如,/api)。以下示例展示了如何使用 @RepositoryRestController 注解

@RepositoryRestController
class ScannerController {

  private final ScannerRepository repository;

  ScannerController(ScannerRepository repository) { (1)
    this.repository = repository;
  }

  @GetMapping(path = "/scanners/search/producers") (2)
  ResponseEntity<?> getProducers() {

    List<String> producers = repository.listProducers(); (3)

    // do some intermediate processing, logging, etc. with the producers

    CollectionModel<String> resources = CollectionModel.of(producers); (4)

    resources.add(linkTo(methodOn(ScannerController.class).getProducers()).withSelfRel()); (5)

    // add other links as needed

    return ResponseEntity.ok(resources); (6)
  }
}
1 此示例使用构造函数注入。
2 此处理程序将自定义处理程序方法作为查询方法资源插入。
3 此处理程序使用底层存储库来获取数据,但随后在将最终数据集返回给客户端之前进行某种形式的后处理。
4 类型为 T 的结果需要包装在 Spring HATEOAS CollectionModel<T> 对象中以返回集合。EntityModel<T>RepresentationModel<T> 分别适合包装单个项目。
5 添加一个指向此确切方法的链接作为 self 链接。
6 使用 Spring MVC 的 ResponseEntity 包装器返回集合可确保集合被正确包装并在适当的接受类型中呈现。

CollectionModel 用于集合,而 EntityModel(或更通用的类 RepresentationModel)用于单个项目。这些类型可以组合。如果您知道集合中每个项目的链接,请使用 CollectionModel<EntityModel<String>>(或任何核心域类型,而不是 String)。这样做可以让您为每个项目以及整个集合组装链接。

在此示例中,组合路径为 RepositoryRestConfiguration.getBasePath() + /scanners/search/producers

获取聚合引用

对于接收 PUTPOST 请求的自定义控制器,请求主体通常包含一个 JSON 文档,该文档将使用 URI 来表达对其他资源的引用。对于 GET 请求,这些引用通过请求参数传递。

从 Spring Data REST 4.1 开始,我们提供 AggregateReference<T, ID> 用作处理程序方法参数类型来捕获此类引用并将它们解析为引用的聚合的标识符、聚合本身或 jMolecules Association。您只需声明该类型的 @RequestParam,然后使用标识符或完全解析的聚合。

@RepositoryRestController
class ScannerController {

  private final ScannerRepository repository;

  ScannerController(ScannerRepository repository) {
    this.repository = repository;
  }

  @GetMapping(path = "/scanners")
  ResponseEntity<?> getProducers(
    @RequestParam AggregateReference<Producer, ProducerIdentifier> producer) {

    var identifier = producer.resolveRequiredId();
    // Alternatively
    var aggregate = producer.resolveRequiredAggregate();
  }

  // Alternatively

  @GetMapping(path = "/scanners")
  ResponseEntity<?> getProducers(
    @RequestParam AssociationAggregateReference<Producer, ProducerIdentifier> producer) {

    var association = producer.resolveRequiredAssociation();
  }
}

如果您使用的是 jMolecules,AssociationAggregateReference 还允许您获取 Association。虽然这两个抽象都假设参数的值是一个与 Spring Data REST 用于公开项目资源的方案匹配的 URI,但可以通过调用引用实例上的 ….withIdSource(…) 来定制此源值解析,以提供一个函数来提取最终用于聚合解析的标识符值,该值来自从接收到的 URI 获取的 UriComponents

@RepositoryRestController VS. @BasePathAwareController

如果您对实体特定的操作不感兴趣,但仍然希望在basePath下构建自定义操作,例如 Spring MVC 视图、资源等,请使用@BasePathAwareController。如果您在自定义控制器上使用@RepositoryRestController,它只会处理请求,如果您的请求映射与存储库使用的 URI 空间混合在一起。它还会对控制器方法应用以下额外功能

  1. 根据为映射到处理程序方法请求映射中使用的基本路径段的存储库定义的 CORS 配置。

  2. 如果使用 JPA,则应用OpenEntityManagerInViewInterceptor 以确保您可以访问标记为延迟解析的属性。

如果您将@Controller@RestController 用于任何目的,该代码完全超出 Spring Data REST 的范围。这扩展到请求处理、消息转换器、异常处理和其他用途。