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
对于接收 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
VS. @BasePathAwareController
如果你对与实体相关的操作不感兴趣,但仍希望在 basePath
下构建自定义操作,例如 Spring MVC 视图、资源和其他操作,请使用 @BasePathAwareController
。如果你在自定义控制器上使用 @RepositoryRestController
,它只会在你的请求映射融合到储存库使用的 URI 空间中时处理请求。它还将对控制器方法应用以下额外功能:
-
CORS配置根据为存储库定义的,映射到请求映射中的基础路径段的处理程序方法。
-
如果使用JPA,请应用`OpenEntityManagerInViewInterceptor`以确保你可以访问标记为延迟解决的属性。
如果你将 @Controller
或 @RestController
用于任何内容,则该代码完全超出 Spring Data REST 的作用范围。这会延伸到请求处理、消息转换器、异常处理和其他用途。