Overriding Spring Data REST Response Handlers

与标准 @Controller 或 @RestController 相比,@RepositoryRestController 处理定制资源的请求,该请求可能涉及后处理、链接和 Spring HATEOAS 对象包装。它还支持处理对其他资源的引用,通过 AggregateReference 或 AssociationAggregateReference 参数。

此外,@RepositoryRestController 内置 CORS 配置和 OpenEntityManagerInViewInterceptor,在使用 JPA 时确保可以访问延迟解析的属性。

有时,你可能希望为特定的资源编写一个自定义处理程序。为了利用 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`包装器返回集合可确保集合得到适当包装并呈现为正确的accept类型。

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

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

Obtaining Aggregate References

对于接收 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 的作用范围。这会延伸到请求处理、消息转换器、异常处理和其他用途。