覆寫 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

取得聚合參考

對於接收 PUTPOST 請求的自訂控制器,請求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 空間時,它才會處理請求。它還將對控制器方法應用以下額外功能

  1. 根據為處理器方法的請求映射中使用的基礎路徑段映射的 repository 定義的 CORS 設定。

  2. 如果使用 JPA,則應用 OpenEntityManagerInViewInterceptor,以確保您可以存取標記為延遲解析的屬性。

如果您對任何項目使用 @Controller@RestController,則該程式碼完全在 Spring Data REST 的範圍之外。這延伸到請求處理、訊息轉換器、例外處理和其他用途。