Springのインターフェイス駆動型コントローラー

1. 前書き

このチュートリアルでは、通常のJavaインターフェースを使用してWeb要求を指定できるSpring MVCの新機能を検討します。

2. 概要

通常、Spring MVCでコントローラーを定義する場合、リクエストを指定するさまざまなアノテーション(エンドポイントのURL、HTTPリクエストメソッド、パス変数など)でメソッドを修飾します。
たとえば、それ以外の場合は単純なメソッドで上記の注釈を使用して、__ / save / \ {id} __endpointを導入できます。
@PostMapping("/save/{id}")
@ResponseBody
public Book save(@RequestBody Book book, @PathVariable int id) {
    // implementation
}
当然、リクエストを処理するコントローラーが1つしかない場合、これはまったく問題になりません。 同じメソッドシグネチャを持つさまざまなコントローラーがある場合、状況は少し変わります。
たとえば、移行などのために、同じメソッドシグネチャを持つ2つの異なるバージョンのコントローラーがある場合があります。 その場合、メソッド定義に付随するかなりの量の重複した注釈があります。 明らかに、それはDRY(_自分を繰り返さない_)の原則に違反するでしょう。
この状況が純粋なJavaクラスで発生する場合は、単にインターフェイスを定義し、クラスにこのインターフェイスを実装させます。 コントローラーでは、*メソッドの主な負担はメソッドのシグネチャによるものではなく、メソッドの注釈によるものです*。
ただし、Spring 5.1では、新しいhttps://github.com/spring-projects/spring-framework/wiki/What%27s-New-in-Spring-Framework-5.x#general-web-revision-1 [特徴:]
______________________________________________________________________________________________________________________________________コントローラーパラメーターアノテーションもインターフェイスで検出されます:コントローラーインターフェイスで完全なマッピングコントラクトを許可します。 ______________________________________________________________________________________________________________________________________
この機能の使用方法を調べてみましょう。

3. コントローラーのインターフェース

3.1. コンテキスト設定

本を管理する非常にシンプルなRESTアプリケーションの例を使用して、新しい機能を説明します。 書籍を取得および変更できるメソッドを備えた1つのコントローラーのみで構成されます。
チュートリアルでは、機能に関連する問題のみに集中します。 アプリケーションの実装に関するすべての問題は、https://github.com/eugenp/tutorials/tree/master/spring-5-mvc/ [GitHubリポジトリ]で確認できます。

3.2. インタフェース

メソッドのシグネチャだけでなく、メソッドが処理するWebリクエストのタイプも定義する通常のJavaインターフェースを定義しましょう。
@RequestMapping("/default")
public interface BookOperations {

    @GetMapping("/")
    List<Book> getAll();

    @GetMapping("/{id}")
    Optional<Book> getById(@PathVariable int id);

    @PostMapping("/save/{id}")
    public void save(@RequestBody Book book, @PathVariable int id);
}
メソッドレベルの注釈だけでなく、クラスレベルの注釈もあることに注意してください。 これで、このインターフェイスを実装するコントローラーを作成できます。
@RestController
@RequestMapping("/book")
public class BookController implements BookOperations {

    @Override
    public List<Book> getAll() {...}

    @Override
    public Optional<Book> getById(int id) {...}

    @Override
    public void save(Book book, int id) {...}

}
*クラスレベルの注釈_ @ RestController_または_ @ Controller_をコントローラーに追加する必要があります。*この方法で定義されたコントローラーは、Web要求のマッピングに関連するすべての注釈を継承します。
コントローラーが期待どおりに動作することを確認するために、アプリケーションを実行し、対応するリクエストを作成して_getAll()_メソッドをヒットしましょう:
curl http://localhost:8081/book/
コントローラーがインターフェースを実装していても、Webリクエストの注釈を追加することで、さらに微調整することができます。 インターフェイスに対して行ったのと同じ方法で、クラスレベルまたはメソッドレベルでそれを行うことができます。 実際、コントローラーを定義するときにこの可能性を使用しました。
@RequestMapping("/book")
public class BookController implements BookOperations {...}
コントローラにWebリクエストアノテーションを追加すると、それらはインターフェースのアノテーションよりも優先されます。 つまり、* Springは、Javaが継承を処理する方法と同様の方法でコントローラーインターフェイスを解釈します。*
インターフェースですべての一般的なWeb要求プロパティを定義しますが、コントローラーでは常に微調整できます。

3.3. 注意事項

インターフェイスとそれを実装するさまざまなコントローラがある場合、Webリクエストが複数のメソッドで処理される可能性があります。 当然、Springは例外をスローします。
Caused by: java.lang.IllegalStateException: Ambiguous mapping.
コントローラーを_ @ RequestMapping_で装飾すると、あいまいなマッピングのリスクを減らすことができます。

4. 結論

このチュートリアルでは、Spring 5.1で導入された新しい機能を検討しました。 これで、Spring MVCコントローラーがインターフェイスを実装するとき、標準のJavaの方法だけでなく、インターフェイスで定義されたすべてのWebリクエスト関連機能も継承します。
いつものように、https://github.com/eugenp/tutorials/tree/master/spring-5-mvc [GitHub repository]で対応するコードスニペットを見つけることができます。