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)。
繼承 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 失效,需手動重新引用所需攔截器。
<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。
自動將表單字段映射到 Action 的 setter(如 name → setName())。屬於 defaultStack,若自定義攔截器鏈必須顯式引用,否則參數注入失效。
<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,保留核心功能。
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();
}
}
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"繼承 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 組成、參數注入機制、攔截器棧複用、自定義攔截器開發模式,即可靈活控制請求處理流程,實現日誌、權限、計時、參數預處理等橫切關注點。