本文來自:曹勝歡部落格專欄。轉載請註明出處:http://blog.csdn.net/csh624366188
在上一篇部落格中,我們一起看了攔截器的具體實現原理,並且看了一下源碼(細談struts2(八)攔截器的實現原理及源碼剖析),這一篇部落格,我即將帶領大家一起來看一下Struts2內建實現的攔截器和如何自訂我們自己的攔截器來達到我們想要實現的功能
四.Struts2內建攔截器
Struts2中內建類許多的攔截器,它們提供了許多Struts2的核心功能和可選的進階特性。這些內建的攔截器在struts-default.xml中配置。只有配置了攔截器,攔截器才可以正常的工作和運行。Struts 2已經為您提供豐富多樣的,功能齊全的攔截器實現。大家可以至struts2的jar包內的struts-default.xml查看關於預設的攔截器與攔截器鏈的配置。內建攔截器雖然在struts2中都定義了,但是並不是都起作用的。因為並不是所有攔截器都被加到預設攔截器棧裡了,只有被添加到預設攔截器棧裡的攔截器才起作用,看一下被加到預設攔截器棧的攔截器都有那些:
下面我們來學習一下如何在我們的應用中添加其他的攔截器,我們以timer攔截器為例,timer攔截器可以統計action執行的時間。我們可以修改package中預設的攔截器,那麼將替換掉struts-default中配置的defaultStack攔截器棧,導致Struts2無法正常運行,比如無法擷取表單的值等等。那麼該如何正確的配置呢?可以在添加新的攔截器的基礎上加入defaultStack攔截器棧,這樣就可以保證defaultStack攔截器棧的存在。
<package name="myStruts" extends="struts-default"> <interceptors> <interceptor-stack name="myInterceptor"> ① <interceptor-ref name="timer"/> <interceptor-ref name="defaultStack"/> </interceptor-stack> </interceptors> <default-interceptor-ref name="myInterceptor"/> ② <action name="userAction" class="com.kay.action.UserAction"> <result name="success">suc.jsp</result> <result name="input">index.jsp</result> <result name="error">err.jsp</result> </action></package>
① 添加一個自訂的攔截器棧,並在其中包含time攔截器和defaultStack攔截器棧。
② 設定當前的package的預設攔截器棧為自訂的攔截器棧。
修改package的預設攔截器會應用的package中的所有Action中,如果只想給其中一個Action添加攔截器,則可以不修改預設的攔截器棧,只在對應的Action添加:
<interceptor-ref name="timer"/>
<interceptor-ref name="defaultStack"/>
注意,此處一定不要忘記加<interceptor-ref name="defaultStack"/>,如果忘記的話,struts2的大部分的功能都實現不了了
五.定義自己的攔截器
雖然,Struts 2為我們提供如此豐富的攔截器實現,但是在某種情況下並不能滿足我們的需求,比如:存取控制的時候,在使用者每次訪問某個action時,我們要去校正使用者是否已經登入,如果沒有登入我們將在action執行之前就被攔截,此時我們就需要自訂攔截器;下面我們具體看一下,如何?自訂攔截器。
1.實現攔截器類
所有的Struts 2的攔截器都直接或間接實現介面com.opensymphony.xwork2.interceptor.Interceptor。該介面提供了三
個方法:
1) void init();在該攔截器被初始化之後,在該攔截器執行攔截之前,系統回調該方法。對於每個攔截器而言,此方法只執行一次。
2) void destroy();該方法跟init()方法對應。在攔截器執行個體被銷毀之前,系統將回調該方法。
3) String intercept(ActionInvocation invocation) throws Exception;該方法是使用者需要實現的攔截動作。該方法會返回一個字串作為邏輯視圖。
除此之外,繼承類com.opensymphony.xwork2.interceptor.AbstractInterceptor是更簡單的一種實現攔截器類的方式,因為此類提供了init()和destroy()方法的空實現,這樣我們只需要實現intercept方法。還有一種實現攔截器的方法是繼承MethodFilterInterceptor類,實現這個類可以實現局部攔截,即可以實現指定攔截某一個action的哪個方法,或者不攔截哪個方法
2.註冊自訂攔截器
自訂攔截器類實現了,現在就要在struts裡註冊這個攔截器;
1).註冊攔截器,在struts.xml中的package中註冊攔截器
<interceptors> <!-- name:攔截器的名稱,class:自訂攔截器的類 --> <interceptorname="攔截器名稱"class="自訂攔截器的class路徑"/> </interceptors>
2).使用攔截器,在需要使用自訂攔截器的action中定義如下代碼
<action> <interceptor-refname="攔截器名稱"/></action>
注意:因為struts2的很多功能都是根據攔截器實現的;如果此處只使用自訂的攔截器時,將失去struts2的很多核心功能;所以需要定義一個攔截器棧(由一個或多個攔截器組成)
3) 攔截器棧
<interceptor-stack name="攔截器棧的名稱"> <!--需要注意的是:系統預設的攔截器棧應要放在前面,在加入自訂攔截器; --> <interceptor-ref name="defaultState"/> <interceptor-ref name="自訂攔截器的名稱"/> </interceptor-stack>
4) 在action中使用棧
<action> <interceptor-refname="棧名稱或攔截器名稱"/> 。。。。。</action>
5) 如果此時需要所有的action都使用自訂攔截器時,此時就定義一個預設的攔截器
<default-interceptor-ref name="permissionStack"/>
注意:如果在某個action中又使用了另一個攔截器,此時預設的攔截器將失效,為了確保能夠使用預設的攔截器,又需要添加其他攔截器時,可以在action中加上其他攔截器
下面咱就以繼承MethodFilterInterceptor類來實現一個許可權控制的攔截器,別的頁面都不展示了,在此,展示出攔截器類和struts.xml的配置:
攔截器類AuthorInterceptor:
package com.bzu.intecepter;import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.apache.struts2.StrutsStatics;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;public class AuthorInterceptor extends MethodFilterInterceptor {@Overrideprotected String doIntercept(ActionInvocation invocation) throws Exception {// TODO Auto-generated method stubActionContext context = invocation.getInvocationContext();// 通過ActionContext來擷取httpRequestHttpServletRequest request = (HttpServletRequest) context.get(StrutsStatics.HTTP_REQUEST);// 也可以通過ServletActionContext來擷取httpRequest// HttpServletRequest request = ServletActionContext.getRequest();// 取得根目錄的絕對路徑String currentURL = request.getRequestURI();// 截取到訪問的相對路徑,可以通過這個和許可權表比較來進行相應的許可權控制String targetURL = currentURL.substring(currentURL.indexOf("/", 1),currentURL.length());System.out.println(currentURL + ".............." + targetURL);// 通過ActionContext擷取session的資訊,以Map形式返回Map session = context.getSession();// 擷取容器裡面的username值,如果存在說明該使用者已經登入,讓他執行操作,如果未登入讓他進行登入String username = (String) session.get("username");System.out.println(username+"username");if (username != null) {invocation.invoke();}return "login";}}
下面來看一下具體的struts.xml的配置:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts><constant name="struts.i18n.encoding" value="utf-8" /><package name="struts2" extends="struts-default"> <interceptors> <!-- 配置未登入進行操作的攔截器 --> <interceptor name="loginInterceptor" class="com.bzu.intecepter.AuthorInterceptor"> <param name="excludeMethods">login</param> </interceptor> <!-- 重新封裝一個預設的攔截器棧 --> <interceptor-stack name="myDefaultStack"> <interceptor-ref name="loginInterceptor" /> <interceptor-ref name="defaultStack" /> </interceptor-stack> </interceptors> <!-- 為這個包設定預設的攔截器棧 --> <default-interceptor-ref name="myDefaultStack" /> <global-results> <result name="login">/login.jsp</result> </global-results><action name="LoginAction" class="com.bzu.action.LoginAction" method="login" ><result name="success">success.jsp</result><result name="fail">fail.jsp</result><result name="input">login.jsp</result></action></package></struts>
以上就是一個簡單的許可權控制碼實現了。具體的原始碼:點擊下載
最後,大家一起來看一下攔截器與過濾器的區別:
攔截器和過濾器之間有很多相同之處,但是兩者之間存在根本的差別。其主要區別為以下幾點:
1)攔截器是基於JAVA反射機制的,而過濾器是基於函數回調的。
2)過濾器依賴於Servlet容器,而攔截器不依賴於Servlet容器
3)攔截器只能對Action請求起作用,而過濾器可以對幾乎所有的請求起作用。
4)攔截器可以訪問Action上下文、值棧裡的對象,而過濾器不能
5)在Action的生命週期中,攔截器可以多次被調用,而過濾器只能在容器初始化時被調用一次。