|
对于最新的稳定版本,请使用 Spring Data REST 5.0.4! |
覆盖 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 包装器返回集合,可确保该集合被正确包装,并以适当的 Accept 类型进行渲染。 |
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 方案的 URI,但可以通过在引用实例上调用 ….withIdSource(…) 来自定义该源值的解析方式,从而提供一个函数,从接收到的 URI 所解析出的 UriComponents 中提取最终用于聚合解析的标识符值。
@RepositoryRestController VS. @BasePathAwareController
如果你对特定实体的操作不感兴趣,但仍希望在 basePath 下构建自定义操作(例如 Spring MVC 视图、资源等),请使用 @BasePathAwareController。
如果你在自定义控制器上使用了 @RepositoryRestController,那么该控制器仅在你的请求映射融入仓库所使用的 URI 空间时才会处理该请求。
它还会为控制器方法应用以下额外功能:
-
CORS 配置根据为仓库定义的配置进行设置,该仓库映射到处理方法请求映射中使用的基路径段。
-
如果使用 JPA,请应用
OpenEntityManagerInViewInterceptor,以确保您可以访问标记为延迟加载的属性。
如果你对任何内容使用了 @Controller 或 @RestController,那么这些代码完全超出了 Spring Data REST 的作用范围。这包括请求处理、消息转换器、异常处理以及其他用途。 |