覆寫 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
請求的自訂控制器,請求body通常包含一個 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
VS. @BasePathAwareController
如果您對特定於實體的操作不感興趣,但仍然想在 basePath
下方建立自訂操作,例如 Spring MVC 視圖、資源和其他項目,請使用 @BasePathAwareController
。如果您在自訂控制器上使用 @RepositoryRestController
,則只有當您的請求映射融入 repository 使用的 URI 空間時,它才會處理請求。它還將對控制器方法應用以下額外功能
-
根據為處理器方法的請求映射中使用的基礎路徑段映射的 repository 定義的 CORS 設定。
-
如果使用 JPA,則應用
OpenEntityManagerInViewInterceptor
,以確保您可以存取標記為延遲解析的屬性。
如果您對任何項目使用 @Controller 或 @RestController ,則該程式碼完全在 Spring Data REST 的範圍之外。這延伸到請求處理、訊息轉換器、例外處理和其他用途。 |