覆蓋 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 | 此處理器使用底層 repository 獲取資料,但在向客戶端返回最終資料集之前會進行某種形式的後處理。 |
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
。雖然這兩個抽象都假設引數的值是一個 URI,並且該 URI 匹配 Spring Data REST 用來暴露專案資源的模式,但透過在引用例項上呼叫 ….withIdSource(…)
可以定製源值的解析方式,以提供一個函式從接收到的 URI 中獲得的 UriComponents
中提取最終用於聚合解析的識別符號值。
@RepositoryRestController
對比 @BasePathAwareController
如果你對特定於實體的操作不感興趣,但仍想在 basePath
下構建自定義操作,例如 Spring MVC 檢視、資源等,請使用 @BasePathAwareController
。如果你在自定義控制器上使用 @RepositoryRestController
,它只會在你的請求對映與 repository 使用的 URI 空間融合時處理請求。它還會對控制器方法應用以下額外功能:
-
根據 handler 方法請求對映中使用的基礎路徑段所對映的 repository 定義的 CORS 配置。
-
如果使用 JPA,應用一個
OpenEntityManagerInViewInterceptor
,以確保你可以訪問標記為延遲解析的屬性。
如果你使用 @Controller 或 @RestController 執行任何操作,那麼這段程式碼完全不在 Spring Data REST 的範圍之內。這包括請求處理、訊息轉換器、異常處理以及其他用途。 |