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
注解:
Sometimes, you may want to write a custom handler for a specific resource.
To take advantage of Spring Data REST’s settings, message converters, exception handling, and more, use the @RepositoryRestController
annotation instead of a standard Spring MVC @Controller
or @RestController
.
Controllers annotated with @RepositoryRestController
are served from the API base path defined in RepositoryRestConfiguration.setBasePath
, which is used by all other RESTful endpoints (for example, /api
).
The following example shows how to use the @RepositoryRestController
annotation:
@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 | This example uses constructor injection. |
2 | This handler plugs in a custom handler method as query method resource |
3 | This handler uses the underlying repository to fetch data, but then does some form of post processing before returning the final data set to the client. |
4 | The results of type T need to be wrapped up in a Spring HATEOAS CollectionModel<T> object to return a collection. EntityModel<T> or RepresentationModel<T> are suitable wrappers for a single item, respectively. |
5 | Add a link back to this exact method as a self link. |
6 | Returning the collection by using Spring MVC’s ResponseEntity wrapper ensures that the collection is properly wrapped and rendered in the proper accept type. |
CollectionModel
是用于集合,而 EntityModel
(或更通用的类 RepresentationModel
)是用于单个项目。这些类型可以组合在一起。如果你知道集合中每个项目的链接,请使用 CollectionModel<EntityModel<String>>
(或任何核心域类型而不是 String
)。这样做可以让你组装每个项目的链接以及整个集合的链接。
CollectionModel
is for a collection, while EntityModel
— or the more general class RepresentationModel
— is for a single item. These types can be combined. If you know the links for each item in a collection, use CollectionModel<EntityModel<String>>
(or whatever the core domain type is rather than String
). Doing so lets you assemble links for each item as well as for the whole collection.
在此示例中,组合路径为 RepositoryRestConfiguration.getBasePath()
+ /scanners/search/producers
。
In this example, the combined path is RepositoryRestConfiguration.getBasePath()
+ /scanners/search/producers
.
Obtaining Aggregate References
对于接收 PUT
和 POST
请求的自定义控制器,请求正文通常包含一个 JSON 文档,该文档将使用 URI 来表示对其他资源的引用。对于 GET
请求,这些引用通过请求参数提交。
For custom controllers receiving PUT
and POST
requests, the request body usually contains a JSON document that will use URIs to express references to other resources.
For GET
requests, those references are handed in via a request parameter.
从 Spring Data REST 4.1 开始,我们提供了 AggregateReference<T, ID>
,可用作处理程序方法参数类型,以捕获此类引用并将其解析为引用的聚合标识符、聚合本身或 jMolecules Association
。你只需要声明一个该类型的 @RequestParam
,然后消耗标识符或完全解析的聚合。
As of Spring Data REST 4.1, we provide AggregateReference<T, ID>
to be used as handler method parameter type to capture such references and resolve them into either the referenced aggregate’s identifier, the aggregate itself or a jMolecules Association
.
All you need to do is declare an @RequestParam
of that type and then consume either the identifier or the fully resolved aggregate.
@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
中提取要用于聚合解析的标识符值。
In case you are using jMolecules, AssociationAggregateReference
also allows you to obtain an Association
.
While both of the abstraction assume the value for the parameter to be a URI matching the scheme that Spring Data REST uses to expose item resources, that source value resolution can be customized by calling ….withIdSource(…)
on the reference instance to provide a function to extract the identifier value to be used for aggregate resolution eventually from the UriComponents
obtained from the URI received.
@RepositoryRestController
VS. @BasePathAwareController
如果你对与实体相关的操作不感兴趣,但仍希望在 basePath
下构建自定义操作,例如 Spring MVC 视图、资源和其他操作,请使用 @BasePathAwareController
。如果你在自定义控制器上使用 @RepositoryRestController
,它只会在你的请求映射融合到储存库使用的 URI 空间中时处理请求。它还将对控制器方法应用以下额外功能:
If you are not interested in entity-specific operations but still want to build custom operations underneath basePath
, such as Spring MVC views, resources, and others, use @BasePathAwareController
.
If you’re using @RepositoryRestController
on your custom controller, it will only handle the request if your request mappings blend into the URI space used by the repository.
It will also apply the following extra functionality to the controller methods:
-
CORS configuration according as defined for the repository mapped to the base path segment used in the request mapping of the handler method.
-
Apply an
OpenEntityManagerInViewInterceptor
if JPA is used to make sure you can access properties marked as to be resolved lazily.
如果你将 @Controller
或 @RestController
用于任何内容,则该代码完全超出 Spring Data REST 的作用范围。这会延伸到请求处理、消息转换器、异常处理和其他用途。
If you use @Controller
or @RestController
for anything, that code is totally outside the scope of Spring Data REST. This extends to request handling, message converters, exception handling, and other uses.