知識庫 / Spring / Spring Boot RSS 訂閱

為所有 Spring Boot 控制器添加前綴

Spring Boot
HongKong
9
12:16 PM · Dec 06 ,2025

1. 引言

在 Spring Boot 應用中,每個控制器都可以擁有自己的 URL 映射。這使得單個應用能夠輕鬆地在多個位置提供 Web 端點。例如,我們可以將我們的 API 端點分組到邏輯分組中,如內部和外部。

然而,在某些情況下,我們可能希望所有端點都位於一個通用的前綴下。在本教程中,我們將探討使用通用前綴為所有 Spring Boot 控制器提供不同方法。

2. Servlet 上下文

Spring 應用中負責處理 Web 請求的主要組件是 DispatcherServlet。 通過自定義該組件,我們對請求的路由擁有相當程度的控制權。

讓我們來看兩種自定義 DispatcherServlet 的方法,以便使我們應用程序的所有端點都可用在同一個 URL 前綴下。

2.1. Spring Bean

通過引入一個新的 Spring Bean 來實現:

@Configuration
public class DispatcherServletCustomConfiguration {

    @Bean
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }

    @Bean
    public ServletRegistrationBean dispatcherServletRegistration() {
        ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet(), "/api/");
        registration.setName(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
        return registration;
    }
}

在這裏,我們正在創建一個 ServletRegistrationBean,該類將 DispatcherServlet bean 包裝起來。請注意,我們提供了明確的基 URL 為 /api/這意味着所有我們的端點都必須通過該基 URL 前綴訪問

2.2. 應用屬性

我們可以僅通過使用應用屬性來達到相同的效果。在 Spring Boot 2.0.0 及更高版本中,我們只需將以下內容添加到我們的 <em >application.properties</em > 文件中:

server.servlet.contextPath=/api

在此版本之前,屬性名稱略有不同:

server.contextPath=/api

這種方法的一個優勢在於它僅使用標準的 Spring 屬性。 這意味着我們可以輕鬆地使用標準機制(如 profile 或外部屬性綁定)來更改或覆蓋我們的通用前綴

2.3. 優缺點

這些兩種方法的的主要優勢也是其主要缺點:它們會影響應用程序中的每一個端點。

對於某些應用程序而言,這可能完全可以接受。然而,某些應用程序可能需要使用標準端點映射來與第三方服務進行交互——例如,OAuth 交換。在這種情況下,像這樣全局的解決方案可能並不適用。

3. 註解

另一個添加前綴到 Spring 應用中所有控制器的辦法是使用註解。下面我們將探討兩種不同的方法。

3.1. SpEL

使用 Spring 表達式語言 (SpEL) 與標準 <em/>@RequestMapping 註解相結合的第一種方法。通過這種方法,我們只需為每個想要添加前綴的控制器添加一個屬性:

@Controller
@RequestMapping(path = "${apiPrefix}/users")
public class UserController {

} 

然後,我們只需在 application.properties 文件中指定屬性值:

apiPrefix=/api

3.2. 自定義標註

另一種實現此目的的方法是創建我們自己的標註:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
@RequestMapping("/api/")
public @interface ApiPrefixController {
    @AliasFor(annotation = Component.class)
    String value() default "";
}

然後,我們只需要將標註應用於我們想要添加前綴的每個控制器:

@Controller
@ApiPrefixController
public class SomeController {
    @RequestMapping("/users")
    @ReponseBody
    public String getAll(){
        // ...
    }
}

3.3. 優缺點

這兩種方法解決了前一種方法的主要問題:它們都提供了對哪些控制器獲得前綴的精細控制。我們可以僅對特定控制器應用註解,而不是影響應用程序中的所有端點。

4. 服務器端重定向

最後一種方法是使用服務器端重定向。 與重定向不同,重定向不涉及向客户端發送響應。這意味着我們的應用程序可以在不影響客户端的情況下,在端點之間傳遞請求。

為了開始,讓我們編寫一個簡單的控制器,其中包含兩個端點:

@Controller
class EndpointController {
    @GetMapping("/endpoint1")
    @ResponseBody
    public String endpoint1() {
        return "Hello from endpoint 1";
    }

    @GetMapping("/endpoint2")
    @ResponseBody
    public String endpoint2() {
        return "Hello from endpoint 2";
    }
}

接下來,我們創建一個基於我們想要的前綴的新控制器:

@Controller
@RequestMapping("/api/endpoint")
public class ApiPrefixController {

    @GetMapping
    public ModelAndView route(ModelMap model) {
        if(new Random().nextBoolean()) {
            return new ModelAndView("forward:/endpoint1", model);
        } 
        else {
            return new ModelAndView("forward:/endpoint2", model);
        }
    }
}

此控制器具有一個單一的端點,它充當路由器。在這種情況下,它基本上通過隨機選擇來將原始請求轉發到我們其他兩個端點之一。

我們可以通過發送幾個連續請求來驗證其功能:

> curl http://localhost:8080/api/endpoint
Hello from endpoint 2
> curl http://localhost:8080/api/endpoint
Hello from endpoint 1
> curl http://localhost:8080/api/endpoint
Hello from endpoint 1
> curl http://localhost:8080/api/endpoint
Hello from endpoint 2
> curl http://localhost:8080/api/endpoint
Hello from endpoint 2

這種方法的關鍵優勢在於其強大性。我們可以應用任何邏輯來確定如何處理請求:URL路徑、HTTP方法、HTTP頭等。

5. 結論

在本文中,我們學習瞭如何將常用前綴應用於 Spring 應用程序中的每個控制器。 就像大多數決策一樣,每種方法都有其優缺點,在實施之前應仔細考慮。

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

發佈 評論

Some HTML is okay.