在上一篇中介紹了Struts攔截器的原理在這一篇中我們將學習一下如何編寫自己的攔截器
攔截器的實現
實現一個攔截器非常簡單實際上一個攔截器就是一個普通的類只是這個類必須實現comopensymphonyxworkinterceptorInterceptor接口Interceptor接口有如下三個方法
publicinterfaceInterceptorextendsSerializable
{
voiddestroy();
voidinit();
Stringintercept(ActionInvocationinvocation)throwsException;
}
其中init和destroy方法只在攔截器加載和釋放(都由Struts自身處理)時執行一次而intercept方法在每次訪問動作時都會被調用Struts在調用攔截器時每個攔截器類只有一個對象實例而所有引用這個攔截器的動作都共享這一個攔截器類的對象實例因此在實現Interceptor接口的類中如果使用類變量要注意同步問題
下面我們來實現一個簡單的攔截器這個攔截器通過請求參數action指定一個攔截器類中的方法並調用這個方法(我們可以使用這個攔截器對某一特定的動作進行預處理)如果方法不存在或是action參數不存在則繼續執行下面的代碼如下面的URL
訪問上面的url後攔截器會就會調用攔截器中的test方法如果這個方法不存在則調用invocationinvoke方法invoke方法和Servlet過濾器中調用FilterChaindoFilter方法類似如果在當前攔截器後面還有其他的攔截器則invoke方法就是調用後面攔截器的intercept方法否則invoke會調用Action類的execute方法(或其他的執行方法)
下面我們先來實現一個攔截器的父類ActionInterceptor這個類主要實現了根據action參數值來調用方法的功能代碼如下
packageinterceptor;
importcomopensymphonyxworkActionInvocation;
importcomopensymphonyxworkinterceptorInterceptor;
importjavaxservlethttp*;
importorgapachestruts*;
publicclassActionInterceptorimplementsInterceptor
{
protectedfinalStringINVOKE=##invoke;
publicvoiddestroy()
{
Systemoutprintln(destroy);
}
publicvoidinit()
{
Systemoutprintln(init);
}
publicStringintercept(ActionInvocationinvocation)throwsException
{
HttpServletRequestrequest=ServletActionContextgetRequest();
Stringaction=requestgetParameter(action);
Systemoutprintln(thishashCode());
if(action!=null)
{
try
{
javalangreflectMethodmethod=thisgetClass()getMethod(action);
Stringresult=(String)methodinvoke(this);
if(result!=null)
{
if(!resultequals(INVOKE))
returnresult;
}
else
returnnull;
}
catch(Exceptione)
{
}
}
returninvocationinvoke();
}
}
從上面代碼中的intercept方法可以看出在調用action所指定的方法後來判斷返回值可能發生的情況有三種
返回值為null執行return null
返回值為INVOKE執行return invockationinvoke()
其他情況執行return resultresult表示指定方法的返回值如上面代碼所示
在實現完上面的攔截器父類後任何繼承於ActionInterceptor類的攔截器都可以自動根據action的參數值調用自身的相應方法下面我們來實現一個擁有兩個動作方法test和print的攔截器類代碼如下
packageinterceptor;
importjavaxservlethttpHttpServletResponse;
importorgapachestrutsServletActionContext;
publicclassMultiMethodInterceptorextendsActionInterceptor
{
publicStringtest()throwsException
{
HttpServletResponseresponse=ServletActionContextgetResponse();
responsegetWriter()println(invoketest);
returnthisINVOKE;
}
publicStringprint()throwsException
{
HttpServletResponseresponse=ServletActionContextgetResponse();
responsegetWriter()println(invokeprint);
returnnull;
}
}
est方法返回了INVOKE因此在執行完這個方法後Struts會接著調用其他攔截器的intercept方法或Action類的execute方法而print方法在執行完後只是返回了null而不再調用其他的方法了也就是訪問如下的url時動作的execute方法將不會執行
下面我們來實現一個Action類代碼如下
packageaction;
importorgapachestruts*;
importcomopensymphonyxworkActionSupport;
publicclassInterceptorActionextendsActionSupport
{
publicStringabcd()throwsException
{
ServletActionContextgetResponse()getWriter()
println(invokeabcd);
returnnull;
}
}
在這個Action類中只有一個abcd方法實際上這個方法相當於execute方法在下面會設置動作的method屬性為abcd下面我們來在strutsxml中定義攔截器類和動作代碼如下
<?xmlversion=encoding=UTF?>
<!DOCTYPEstrutsPUBLIC
//ApacheSoftwareFoundation//DTDStrutsConfiguration//EN
dtd>
<struts>
<packagename=demoextends=strutsdefaultnamespace=/test>
<interceptors>
<interceptorname=methodclass=interceptorMultiMethodInterceptor/>
<interceptorstackname=methodStack>
<interceptorrefname=method/>
<interceptorrefname=defaultStack/>
</interceptorstack>
</interceptors>
<actionname=interceptorclass=actionInterceptorActionmethod=abcd>
<interceptorrefname=methodStack/>
</action>
</package>
</struts>
在配置上面的methodStack攔截器時要注意最好在後面引用defaultStack否則很多通過攔截器提供的功能將失去
現在訪問如下的URL
在浏覽器中將會出現如下的字符串
invoke test
invoke abcd
而如果訪問將會只出現如下的字符串
invoke print
大家可以看出訪問這個url時並沒有調用abcd方法如果隨便指定的action值的話則只調用abcd方法如訪問就只會輸出invoke abcd
攔截器的參數
我們在使用很多Struts內置的攔截器時會發現有很多攔截器都帶參數當然我們自己做的攔截器也可以加上同樣的參數有兩個參數比較常用這兩個參數是includeMethods和excludeMethods其中includeMethods指定了攔截器要調用的Action類的執行方法(默認是execute)也就是說只有在includeMethods中指定的方法才會被Struts調用而excludeMethods恰恰相反在這個參數中指定的執行方法不會被Struts調用如果有多個方法中間用逗號()分隔在Struts中提供了一個抽象類來處理這兩個參數這個類如下
comopensymphonyxworkinterceptorMethodFilterInterceptor
如有繼承於這個類的攔截器類都會自動處理includeMethods和excludeMethods參數如下面的攔截器類所示
packageinterceptor;
importcomopensymphonyxworkActionInvocation;
importcomopensymphonyxworkinterceptor*;
publicclassMyFilterInterceptorextendsMethodFilterInterceptor
{
privateStringname;
publicStringgetName()
{
returnname;
}
publicvoidsetName(Stringname)
{
thisname=name;
}
@Override
protectedStringdoIntercept(ActionInvocationinvocation)throwsException
{
Systemoutprintln(doIntercept);
Systemoutprintln(name);
returninvocationinvoke();
}
}
MethodFilterInterceptor的子類需要實現doIntercept方法(相當於Interceptor的intercept方法)如上面代碼所示在上面的代碼中還有一個name屬性是為了讀取攔截器的name屬性而設置的如下面的配置代碼所示
<?xmlversion=
encoding=
UTF
?>
<!DOCTYPEstrutsPUBLIC
//ApacheSoftwareFoundation//DTDStrutsConfiguration
//EN
dtd
>
<struts>
<packagename=
demo
extends=
struts
default
namespace=
/test
>
<interceptors>
<interceptorname=
method
class=
interceptor
MultiMethodInterceptor
/>
<interceptorname=
filter
class=
interceptor
MyFilterInterceptor
>
<paramname=
includeMethods
>abcd</param>
<paramname=
name
>中國</param>
</interceptor>
<interceptor
stackname=
methodStack
>
<interceptor
refname=
method
/>
<interceptor
refname=
filter
/>
<interceptor
refname=
defaultStack
/>
</interceptor
stack>
</interceptors>
<actionname=
interceptor
class=
action
InterceptorAction
method=
abcd
>
<interceptor
refname=
methodStack
/>
</action>
</package>
</struts>
再次訪問 Struts就會調用MyFilterInterceptor的doIntercept方法來輸出name屬性值如果將上面的includeMethods參數值中的abcd去掉則Action類的abcd方法不會被執行
From:http://tw.wingwit.com/Article/program/Java/ky/201311/27899.html