首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Struts 2 攔截器完整指南:原理、配置與自定義實戰

     編輯:Java 相關知識

攔截器核心機制

Struts 2 攔截器類似 Servlet Filter,在 Action 的 execute() 前後攔截請求。所有攔截器必須實現 com.opensymphony.xwork2.interceptor.Interceptor 介面:

public interface Interceptor extends Serializable {
    void destroy();                    // 銷毀時調用一次
    void init();                       // 初始化時調用一次
    String intercept(ActionInvocation invocation) throws Exception; // 核心邏輯,每次請求調用
}

intercept() 中調用 invocation.invoke() 繼續執行鏈路(下一個攔截器或 Action)。

預定義攔截器與 defaultStack

繼承 struts-default 套餐自動獲得一組預定義攔截器(timer、params、validation 等)。defaultStack 定義了默認攔截器鏈:

<interceptor-stack name="defaultStack">
  <interceptor-ref name="exception"/>
  <interceptor-ref name="alias"/>
  <interceptor-ref name="servletConfig"/>
  <interceptor-ref name="prepare"/>
  <interceptor-ref name="i18n"/>
  <interceptor-ref name="chain"/>
  <interceptor-ref name="debugging"/>
  <interceptor-ref name="profiling"/>
  <interceptor-ref name="scopedModelDriven"/>
  <interceptor-ref name="modelDriven"/>
  <interceptor-ref name="fileUpload"/>
  <interceptor-ref name="checkbox"/>
  <interceptor-ref name="staticParams"/>
  <interceptor-ref name="params"><param name="excludeParams">dojo/..*</param></interceptor-ref>
  <interceptor-ref name="conversionError"/>
  <interceptor-ref name="validation"><param name="excludeMethods">input,back,cancel,browse</param></interceptor-ref>
  <interceptor-ref name="workflow"><param name="excludeMethods">input,back,cancel,browse</param></interceptor-ref>
</interceptor-stack>

注意:Action 顯式引用任一攔截器後,defaultStack 失效,需手動重新引用所需攔截器。

常用內置攔截器實戰

1. timer - 執行耗時統計

<action name="first" class="action.FirstAction">
  <interceptor-ref name="timer"/>          <!-- 放前面:僅統計 execute -->
  <interceptor-ref name="logger"/>         <!-- 放後面:統計 logger + execute -->
</action>

輸出:Executed action [/test/first!execute] took 1000 ms. 需 commons-logging.jar。

2. params - 請求參數自動注入

自動將表單字段映射到 Action 的 setter(如 name → setName())。屬於 defaultStack,若自定義攔截器鏈必須顯式引用,否則參數注入失效。

3. static-params - 靜態參數注入

<action name="first" class="action.FirstAction">
  <param name="who">比爾</param>
  <interceptor-ref name="static-params"/>
</action>

自動調用 setWho("比爾")。

攔截器棧:複用攔截器組合

<package name="demo" extends="struts-default">
  <interceptors>
    <interceptor-stack name="mystack">
      <interceptor-ref name="timer"/>
      <interceptor-ref name="logger"/>
      <interceptor-ref name="params"/>
      <interceptor-ref name="static-params"/>
    </interceptor-stack>
  </interceptors>
  <action name="first" class="action.FirstAction">
    <param name="who">比爾</param>
    <interceptor-ref name="mystack"/>
  </action>
</package>

建議在自定義棧末尾加入 defaultStack,保留核心功能。

自定義攔截器實戰:多方法分發

基類:根據 action 參數調用同名方法

public class ActionInterceptor implements Interceptor {
    protected final String INVOKE = "##invoke";
    public void destroy() { System.out.println("destroy"); }
    public void init() { System.out.println("init"); }
    public String intercept(ActionInvocation invocation) throws Exception {
        HttpServletRequest request = ServletActionContext.getRequest();
        String action = request.getParameter("action");
        if (action != null) {
            try {
                Method method = this.getClass().getMethod(action);
                String result = (String) method.invoke(this);
                if (result != null) {
                    if (!result.equals(INVOKE)) return result;
                } else return null;
            } catch (Exception e) { }
        }
        return invocation.invoke();
    }
}

具體實現:test 繼續鏈路,print 終止鏈路

public class MultiMethodInterceptor extends ActionInterceptor {
    public String test() throws Exception {
        ServletActionContext.getResponse().getWriter().println("invoke test");
        return this.INVOKE; // 繼續執行後續攔截器/Action
    }
    public String print() throws Exception {
        ServletActionContext.getResponse().getWriter().println("invoke print");
        return null; // 直接返回,不再執行 Action
    }
}

配置與測試

<interceptors>
  <interceptor name="method" class="interceptor.MultiMethodInterceptor"/>
  <interceptor-stack name="methodStack">
    <interceptor-ref name="method"/>
    <interceptor-ref name="defaultStack"/> <!-- 重要!-->
  </interceptor-stack>
</interceptors>
<action name="interceptor" class="action.InterceptorAction" method="abcd">
  <interceptor-ref name="methodStack"/>
</action>
  • ?action=test → 輸出 "invoke test" + "invoke abcd"
  • ?action=print → 僅輸出 "invoke print"
  • ?action=aaa → 僅輸出 "invoke abcd"

攔截器參數:includeMethods / excludeMethods

繼承 MethodFilterInterceptor 自動支援:

public class MyFilterInterceptor extends MethodFilterInterceptor {
    private String name;
    // getter/setter
    @Override protected String doIntercept(ActionInvocation invocation) throws Exception {
        System.out.println("doIntercept: " + name);
        return invocation.invoke();
    }
}

配置:

<interceptor name="filter" class="interceptor.MyFilterInterceptor">
  <param name="includeMethods">abcd</param>  <!-- 僅 abcd 方法觸發 -->
  <param name="name">中國</param>
</interceptor>

移除 includeMethods 中的 abcd,Action 的 abcd() 將不被執行。

關鍵最佳實踐

  • 攔截器為單例,多線程共享,**類變量必須線程安全**。
  • 自定義攔截器棧務必包含 defaultStack,避免核心功能(參數注入、驗證、文件上傳等)失效。
  • 優先使用 MethodFilterInterceptor 簡化方法級過濾邏輯。
  • invocation.invoke() 必須調用,否則鏈路中斷。

總結

Struts 2 攔截器是 AOP 在 Web 層的具體實現。掌握 Interceptor 三大生命週期、defaultStack 組成、參數注入機制、攔截器棧複用、自定義攔截器開發模式,即可靈活控制請求處理流程,實現日誌、權限、計時、參數預處理等橫切關注點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved