知識庫 / Spring / Spring MVC RSS 訂閱

基於接口的控制器(Spring)

Spring MVC
HongKong
4
01:19 PM · Dec 06 ,2025

1. 引言

在本教程中,我們將探討 Spring MVC 的一項新特性,該特性允許我們使用標準的 Java 接口來指定 Web 請求。

2. 概述

通常,在 Spring MVC 中定義控制器時,我們會使用各種註解來裝飾其方法,這些註解指定了請求:端點的 URL、HTTP 請求方法、路徑變量等等。

例如,我們可以使用上述註解來裝飾一個普通的函數,引入 /save/{id} 端點。

@PostMapping("/save/{id}")
@ResponseBody
public Book save(@RequestBody Book book, @PathVariable int id) {
    // implementation
}

自然地講,當只有一個控制器處理請求時,這沒有任何問題。但當有多個控制器具有相同的類方法簽名時,情況就會發生變化。

例如,我們可能有兩個不同版本的控制器——由於遷移或其他原因——它們具有相同的類方法簽名。在這種情況下,我們將會擁有大量的與類方法定義相關的重複註解。這顯然會違反 DRY (不要重複自己) 原則。

如果這種情況發生在純 Java 類上,我們只需定義一個接口並使類實現該接口。在控制器中,類方法的負擔主要不是由於類方法簽名,而是由於類方法註解

Spring 5.1 引入了一個新特性:

控制器參數註解也會在接口上被檢測到:從而實現控制器接口中的完整映射合同。

讓我們研究一下如何利用這個特性。

3. 控制器接口

3.1. 環境搭建

我們通過一個非常簡單的 REST 應用來演示新功能,該應用管理圖書。該應用將只包含一個控制器,其中包含允許我們檢索和修改圖書的方法。

在教程中,我們僅關注與該功能相關的各個方面。應用程序的全部實現細節可以在我們的 GitHub 倉庫 中找到。

3.2. 接口

以下定義了一個典型的 Java 接口,其中不僅定義了方法的簽名,還指定了它們所處理的 Web 請求類型:

@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. 警告提示

當我們擁有一個接口以及實現它的各種控制器時,可能會出現一個請求被多個方法處理的情況。 這樣 Spring 框架會自動拋出異常。

Caused by: java.lang.IllegalStateException: Ambiguous mapping.

如果我們在控制器上使用 @RequestMapping 註解,可以降低歧義映射的風險。

4. 結論

在本教程中,我們探討了 Spring 5.1 中引入的新特性。現在,當 Spring MVC 控制器實現一個接口時,它們不僅以標準 Java 的方式進行,還繼承了接口中定義的所有與 Web 請求相關的功能。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.