Struts 2 攔截器之攔截器的使用
一旦定義了攔截器和攔截器棧后,就可以使用這個攔截器或攔截器棧來攔截器Action了。攔截器的攔截行為將會在Action的execute方法執行之前執行。
一、實現攔截器類
雖然Struts 2框架提供了許多攔截器,這些攔截器也實現了Struts 2的大部分功能。但是用戶仍然可以開發自己的攔截器。
實現自己的攔截器,應該實現com.opensymphoney.xwork2.interceptor.Interceptor接口
該接口包含三個方法:init() 、destroy()、interceptor(ActionInvocation invocation);
init():在該攔截器被實例化之后,在該攔截器執行攔截之前,系統將會回調該方法。該方法主要用于初始化資源。對于每一個攔截器而言,其init()方法只會執行一次。
destroy():該方法在攔截器實例被銷毀之前被系統回調。該方法用于銷毀init()方法里打開的資源
interceptor(ActionInvocation invocation):該方法是用戶需要實現的攔截動作。該方法會返回一個字符串,系統將會跳轉到該邏輯視圖對應的實際視圖資源,不會調用被攔截的Action。
Struts 2還提供了一個AbstractInterceptor類,該類提供了一個init和destroy方法的空實現,如果我們實現的攔截器不需要打開資源,則可以無須實現這兩個方法。由此可見,繼承AbstractInterceptor類來實現自定義攔截器會更加簡單。
下面實現一個簡單的攔截器:
public class SimpleInterceptor extends AbstractInterceptor { // 簡單攔截器的名字 private String name; public void setName(String name) { this.name = name; } @Override public String intercept(ActionInvocation invocation) throws Exception { //取得被攔截的Action實例 LoginAction action = (LoginAction) invocation.getAction(); //打印執行開始的實現 System.out.println(name+"攔截器的動作----------開始執行登錄Action的時間:"+new Date()); //取得開始執行Action的時間 long start = System.currentTimeMillis(); //執行該攔截器的后一個攔截器 //如果該攔截器沒有其他攔截器,則直接執行Action的execute方法 String result = invocation.invoke(); //打印執行結束的時間 System.out.println(name+"攔截器的動作----------執行完登錄Action的時間:"+new Date()); long end = System.currentTimeMillis(); System.out.println(name+"攔截器的動作----------執行完該Action的事件為:"+(end-start)+"毫秒"); return result; } }
當我們實現interceptor方法時,可以獲得ActionInvocation參數,這個參數可以獲得被攔截的Action實例,一旦取得了Action實例,幾乎獲得了全部的控制權。
二、使用攔截器
實現了攔截器類后,就是配置攔截器,使用攔截器。使用攔截器需要以下兩個步驟:
1、通過<interceptor.../>元素來定義攔截器。
2、通過<interceptor-ref.../>元素來使用攔截器。
攔截器的配置如下:
<package name="mystruts" extends="struts-default"> <!-- 應用所需使用的攔截器都在改元素下配置 --> <interceptors> <!-- 配置沒有simple攔截器 --> <interceptor name="mysimple" class="com.app.interceptor.SimpleInterceptor"> <!-- 為該攔截器指定參數值 --> <param name="name">簡單攔截器</param> </interceptor> </interceptors> <action name="login" class="com.app.action.LoginAction"> <result name="error">/error.jsp</result> <result name="success">/welcome.jsp</result> <!-- 配置系統的默認攔截器 --> <interceptor-ref name="defaultStack"></interceptor-ref> <!-- 應用自定義的mysimple攔截器 --> <interceptor-ref name="mysimple"> <param name="name">改名后的攔截器</param> </interceptor-ref> </action> </package>
這個攔截器只是一個簡單地在控制臺打印一些文本,獲取被攔截方法的執行時間信息。
當瀏覽者在瀏覽器中對該Action發送請求時,該攔截器將會攔截該Action的execute方法,將會在控制臺看到如下結果:
三、攔截方法的攔截器
在默認情況下,如果我們為某個Action定義了攔截器,則這個攔截器會攔截該Action內所有方法,但是有時我們不需要攔截所有方法,只需要攔截指定的方法。此時需要使用Struts 2攔截器的方法過濾特性。
為了實現方法的過濾的特性,Struts 2提供了一個MethodFilterInterceptor類,該類是AbstractInterceptor類的子類如果用戶需要自己實現的攔截器支持方法過濾特性,則應該繼承MethodFilterInterceptor。并且需要重寫doIntercept(ActionInvocation invocation)方法。
實際上實現方法過濾的攔截器與實現普通攔截器并沒沒什么區別。所以這里就不展示代碼了。
在MethodFilterInterceptor類中,增加了如下兩個方法:
1、public void setExcludeMethods(String excludeMethods):排除需要過濾的方法,所有在 excludeMethods字符串中列出的方法都不會被攔截
2、public void setIncludeMethods(String includeMethods):設置需要過濾的方法,所有在includeMethods字符串中列出的方法都會被攔截。
注:如果一個方法同時在excludeMethods和includeMethods中列出,則該方法會被攔截。
通過上面兩個方法,我們可以在配置文件中指定需要被攔截,或者不被攔截的方法。
如下:
<interceptor-ref name="myfilter"> <!-- 指定execute方法不需要被攔截 --> <param name="excludeMethods">execute</param> <!-- 指定login方法需要被攔截 --> <param name="includeMethods">login</param> </interceptor-ref>
如果需要同時指定多個方法不需要被攔截器攔截,則多個方法之間以英文逗號隔開
如下:
<interceptor-ref name="myfilter"> <!-- 指定execute方法和login方法不需要被攔截 --> <param name="excludeMethods">execute,login</param> </interceptor-ref>
如果excludeMethods參數和includeMethods參數同時知道指定了一個方法名,則該方法會被攔截器攔截。
如下:
<interceptor-ref name="myfilter"> <!-- 指定execute方法和login方法不需要被攔擊 --> <param name="excludeMethods">execute,login</param> <!-- 指定login方法需要被攔截 --> <param name="includeMethods">login</param> </interceptor-ref>
上面的配置中通過excludeMethods參數指定execute和login方法不需要被攔截,includeMethods參數指定login方法需要被攔截,則攔截器會攔截login方法。
四、攔截器的執行順序
隨著系統中配置攔截器的順序不同,系統執行攔截器的順序也會不同。通常認為:先配置的攔截器,會先獲得執行機會,但是有時候也會存在一些特殊的情況。
有如下的配置文件:
<package name="mystruts" extends="struts-default"> <!-- 應用所需使用的攔截器都在改元素下配置 --> <interceptors> <!-- 配置沒有simple攔截器 --> <interceptor name="mysimple" class="com.app.interceptor.SimpleInterceptor"> <!-- 為該攔截器指定參數值 --> <param name="name">簡單攔截器</param> </interceptor> </interceptors> <action name="login" class="com.app.action.LoginAction"> <result name="error">/error.jsp</result> <result name="success">/welcome.jsp</result> <!-- 配置系統的默認攔截器 --> <interceptor-ref name="defaultStack"></interceptor-ref> <!-- 應用自定義的mysimple攔截器 --> <interceptor-ref name="mysimple"> <param name="name">第一個</param> </interceptor-ref> <interceptor-ref name="mysimple"> <param name="name">第二個</param> </interceptor-ref> </action> </package>
通過上面的配置文件中我們可以看到,對于上面的名為login的Action,有兩次使用了mysimple攔截器攔截該Action。兩個攔截器名分別為:第一個、第二個。
當用戶再瀏覽器中向該Action發送請求時,就會看到如下效果:
從上面的效果中可以看到,對于在execute方法之前的動作,第一個攔截器會先起作用,也就是說配置在前面的攔截器會先起作用;對于在execute方法之后的動作,則第二個攔截器先起作用,也就是說,配置在后的攔截器會先起作用。
所有可以得到如下結論:在Action的控制方法執行之前,位于攔截器鏈前面的攔截器會先起作用。在Action控制方法執行之后,位于攔截器鏈后面的攔截器會先起作用。
讀李剛《輕量級Java EE企業應用實戰》