
public class AuthInterceptor extends MethodFilterInterceptor
{

protected String doIntercept(ActionInvocation invocation) throws Exception
{
Map session = invocation.getInvocationContext().getSession();
//如果session中存在username字段,且傳入Action實現了Authenticatable接口,且驗證成功
//當然這里只是舉例子,具體要根據業務邏輯來寫
if(session.containsKey("username")&& (invocation instanceof Authenticatable)

&& ((Authenticatable)invocation).validate((String)session.get("username"),(String)session.get("password")))
{
//將數據流轉給真正的Action
return invocation.invoke();

}else
{
//返回一個全局登錄失敗的result
return Action.LOGIN;
}
}
}
其中,if()邏輯內執行了從session中取用戶信息及驗證的邏輯,如果成功,則調用invocation.invoke()將邏輯交給Action,否則退出并返回一個全局的Login結果。
2.聲明攔截器
攔截器需要在struts.xml中聲明。在說明步驟之前,先介紹一下struts中攔截器的框架。
在struts中攔截器實際上分為攔截器和攔截器棧,攔截器棧可以包含一到多個攔截器或者攔截器棧。從上層看來,攔截器和攔截器棧實際上沒有什么區別(就像操作系統中的文件夾和文件)。struts在入口處遞歸的調用了<default-interceptor-ref>中定義的攔截器(棧)中的所有攔截器。
其實之前如果看過struts-default.xml的話,可以看到struts中內建了許多的攔截器,事實上,即便我們在struts.xml中什么都不聲明,程序也會在后臺執行缺省攔截器棧中定義的許多攔截器邏輯,比如說將頁面上的field映射到對應Action的同名屬性中、自動執行類型轉換、自動關聯驗證xml等等。這些攔截器會在每個沒有顯式聲明攔截器的Action執行前后被執行。
需要注意的是,正如上面一句所提到的,如果在Action中顯式聲明了一個攔截器,那么系統默認的攔截器將不會被調用。因此,如果直接將自定義的攔截器放入Action中的話,內建的那些攔截器將會被忽略,這會導致錯誤。所以我們需要在struts.xml的<package>元素下覆蓋缺省攔截器。像下面這樣:
<interceptors>
<interceptor-stack name="default-with-my-inteceptor">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="XXX-interceptor"/>
</interceptor-stack>
<interceptor name="XXX-interceptor" class="com.dev.interceptors.XXXInterceptor" />
</interceptors>

<default-interceptor-ref name="default-with-my-inteceptor"/>
這樣就將自定義攔截器加上了struts缺省攔截器形成新的缺省攔截器。
因為全局定義了攔截器,雖然攔截器在通過攔截的情況下會返回特定Action的result,但有時候比如權限驗證失敗等情況下,自定義攔截器會返回自定義的結果,不屬于任何特定Action,所以我們也需要定義一個全局result用以響應這個攔截器的返回值。
緊挨在<default-interceptor-ref>元素下面添加
<global-results>
<result name="" type="redirectAction">global_error.jsp</result>
</global-results>

注意到其result type為redirectAction重定向Action,這樣struts將以重定向方式處理該Action,并跳轉到global_error.jsp而不會顯示出最后一次執行的Action名字。順便,Action的result缺省是以dispatcher也就是請求轉發的方式處理的。
同時,按照業務邏輯,有些特定Action是不能執行自定義攔截器的。比如說,如果我們定義了一個全局的攔截器,它從session中取出用戶名和密碼進行驗證,驗證通過則繼續,不通過則返回到login.jsp頁面,那么很顯然login.jsp頁面提交的那個Action本身是不能使用該攔截器的,否則就沒有地方可以將用戶信息放入session了。
這種情況下,就要借助之前提到的“特定Action中定義的攔截器會覆蓋全局設置”這個特性了。在需要屏蔽該攔截器的個別Action中顯式的聲明defaultStack攔截器(也就是struts內建的攔截器棧),這樣,自定義攔截器在這個Action中就不會生效了。
小結一下:
寫了這么多,其實大部分都在講原理,如果理解了原理,這幾部做起來是否常容易的。所以重要的是掌握原理。
回憶一下,真正要做的只有三個地方:
(1)寫一個攔截器類(實現接口也好,繼承抽象類也好)
(2)修改struts.xml聲明新的缺省攔截器棧和全局result
(3)對于特定Action,顯式聲明defaultStack攔截器以屏蔽自定義攔截器
另外談一點自己的看法:
攔截器可以說是struts當之無愧的核心,無論是struts的實現原理還是我們基于struts搭建的應用擴展,攔截器都發揮了重要的作用。當然也有可能是我自己的理解不夠深入,但是有一點沒想明白,就是攔截器只能基于Action發揮效用,如果一些功能和Action無關,那么攔截器沒法發生效用。不知道struts底層實現細節中是否只開放了基于Action的攔截器,其實理論上來說,在web.xml中設置了struts作為filter,并攔截所有請求,攔截器在從頁面發送至服務器被struts filter到的那一刻起(準確地說是“前一刻起”),攔截器就能發揮作用了。比如說現在這種過濾器只能在頁面提交到Action時起作用,但無法防止用戶直接訪問JSP。