覆盖 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。 |
获取聚合引用
对于接收 PUT 和 POST 请求的自定义控制器,请求正文通常包含一个 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 与 @BasePathAwareController
如果您对实体特定的操作不感兴趣,但仍希望在 basePath 下构建自定义操作,例如 Spring MVC 视图、资源等,请使用 @BasePathAwareController。如果您在自定义控制器上使用 @RepositoryRestController,则只有当您的请求映射与存储库使用的 URI 空间融合时,它才会处理请求。它还会为控制器方法应用以下额外功能。
-
根据为映射到处理程序方法请求映射中使用的基本路径段的存储库定义的 CORS 配置。
-
如果使用 JPA,则应用
OpenEntityManagerInViewInterceptor,以确保您可以访问标记为延迟解析的属性。
如果您将 @Controller 或 @RestController 用于任何目的,该代码完全在 Spring Data REST 的范围之外。这包括请求处理、消息转换器、异常处理和其他用途。 |