知識庫 / Spring / Spring MVC RSS 訂閱

使用Handler攔截器修改Spring模型參數

Spring MVC
HongKong
12
02:48 PM · Dec 06 ,2025

1. 簡介

本教程將重點介紹 Spring MVC 的 HandlerInterceptor。 尤其是,我們將修改 Spring MVC 的模型參數,在處理請求之前和之後。

如果您想了解 HandlerInterceptor 的基本知識,請查看這篇文章。

2. Maven 依賴

為了使用 攔截器,您需要在您的 pom.xmldependencies 部分添加以下內容:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>6.2.1</version>
</dependency>

最新版本可以在這裏找到:這裏

該依賴僅涵蓋 Spring Web,請務必添加 spring-corespring-context 以構建完整的 Web 應用程序,並選擇您需要的日誌庫。

3. 自定義實現

`HandlerInterceptor 的一種使用場景是在模型中添加常見/用户特定的參數,這些參數將在生成的每個視圖中可用。

在我們的示例中,我們將使用自定義攔截器實現來為模型添加已登錄用户的用户名。在更復雜的系統中,我們還可以添加更具體的的信息,例如:用户頭像路徑、用户位置等。

讓我們首先定義我們的新 <em>Interceptor</em> 類:

public class UserInterceptor extends HandlerInterceptorAdapter {

    private static Logger log = LoggerFactory.getLogger(UserInterceptor.class);

    ...
}

我們擴展了 HandlerInterceptorAdapter,因為我們只希望實現 preHandle() postHandle() 方法。

正如我們之前提到的,我們希望將已登錄用户的姓名添加到模型中。首先,我們需要檢查用户是否已登錄。我們可以通過檢查 SecurityContextHolder 來獲取此信息。

public static boolean isUserLogged() {
    try {
        return !SecurityContextHolder.getContext().getAuthentication()
          .getName().equals("anonymousUser");
    } catch (Exception e) {
        return false;
    }
}

HttpSession 建立,但未登錄任何用户時,Spring Security上下文中用户名將等於 anonymousUser。接下來,我們繼續實現 preHandle():

3.1. 方法 preHandle()

在處理請求之前,無法訪問模型參數。為了添加用户名,需要使用 HttpSession 將參數設置好:

@Override
public boolean preHandle(HttpServletRequest request,
  HttpServletResponse response, Object object) throws Exception {
    if (isUserLogged()) {
        addToModelUserDetails(request.getSession());
    }
    return true;
}

如果我們在處理請求時使用這些信息,那麼這一點至關重要。正如我們所見,我們正在檢查用户是否已登錄,然後通過獲取其會話來向請求添加參數。

private void addToModelUserDetails(HttpSession session) {
    log.info("=============== addToModelUserDetails =========================");
    
    String loggedUsername 
      = SecurityContextHolder.getContext().getAuthentication().getName();
    session.setAttribute("username", loggedUsername);
    
    log.info("user(" + loggedUsername + ") session : " + session);
    log.info("=============== addToModelUserDetails =========================");
}

我們使用 SecurityContextHolder 來獲取 loggedUsername。 您可以覆蓋 Spring Security 的 UserDetails 實現以獲取電子郵件而不是標準用户名。

3.2. 方法 postHandle()

在處理請求後,我們的模型參數可用,因此我們可以訪問它們來修改或添加新的值。要執行此操作,我們使用重寫的 postHandle() 方法:

@Override
public void postHandle(
  HttpServletRequest req, 
  HttpServletResponse res,
  Object o, 
  ModelAndView model) throws Exception {
    
    if (model != null && !isRedirectView(model)) {
        if (isUserLogged()) {
        addToModelUserDetails(model);
    }
    }
}

讓我們來查看一下實現細節。

首先,最好檢查模型是否為 null。 這將防止我們遇到 NullPointerException

此外,我們還可以檢查一個 View 是否不是 RedirectView 的實例。

在請求處理和然後重定向後,無需添加/更改參數,因為新控制器將立即再次執行處理。 為了檢查視圖是否被重定向,我們引入了以下方法:

public static boolean isRedirectView(ModelAndView mv) {
    String viewName = mv.getViewName();
    if (viewName.startsWith("redirect:/")) {
        return true;
    }
    View view = mv.getView();
    return (view != null && view instanceof SmartView
      && ((SmartView) view).isRedirectView());
}

最後,我們再次檢查用户是否已登錄,如果是,則向 Spring 模型添加參數:

private void addToModelUserDetails(ModelAndView model) {
    log.info("=============== addToModelUserDetails =========================");
    
    String loggedUsername = SecurityContextHolder.getContext()
      .getAuthentication().getName();
    model.addObject("loggedUsername", loggedUsername);
    
    log.trace("session : " + model.getModel());
    log.info("=============== addToModelUserDetails =========================");
}

請注意,日誌記錄非常重要,因為這種邏輯在我們的應用程序“後台”運行。很容易忘記在每次更改模型參數時,在 View 中沒有正確地進行日誌記錄。

4. 配置

要將我們創建的 攔截器 添加到 Spring 配置中,我們需要在實現 WebMvcConfigurer 接口的 WebConfig 類中覆蓋 addInterceptors() 方法。

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new UserInterceptor());
}

我們可能通過編輯我們的 XML Spring 配置文件來達到相同的配置:

<mvc:interceptors>
    <bean id="userInterceptor" class="com.baeldung.web.interceptor.UserInterceptor"/>
</mvc:interceptors>

從此刻起,我們可以訪問所有生成視圖中的所有用户相關參數。

請注意,如果配置了多個 Spring Interceptors,則 preHandle() 方法的執行順序與配置順序相同,而 postHandle()afterCompletion() 方法的調用則相反。

5. 結論

本教程介紹了使用 Spring MVC 的 HandlerInterceptor 攔截 Web 請求,以便提供用户信息的實現方法。

在本示例中,我們重點添加了已登錄用户的詳細信息到 Web 應用程序的模型參數中。您可以通過添加更詳細的信息來擴展此 HandlerInterceptor 實現。

5.1. 系列文章

所有系列文章如下:

  • Spring MVC Handler Interceptor 簡介
  • 使用 Handler Interceptor 修改 Spring 模型參數(本篇)
user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.