本文來自:曹勝歡博客專欄。轉載請註明出處: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>
<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:自定義攔截器的類 -->
- <interceptornameinterceptorname="攔截器名稱"class="自定義攔截器的class路徑"/>
- </interceptors>
<interceptors>
<!-- name:攔截器的名稱,class:自定義攔截器的類 -->
<interceptorname="攔截器名稱"class="自定義攔截器的class路徑"/>
</interceptors>
2).使用攔截器,在需要使用自定義攔截器的action中定義如下代碼
- <action>
- <interceptor-refnameinterceptor-refname="攔截器名稱"/>
- </action>
<action>
<interceptor-refname="攔截器名稱"/>
</action>
注意:因爲struts2的很多功能都是根據攔截器實現的;如果此處只使用自定義的攔截器時,將失去struts2的很多核心功能;所以需要定義一個攔截器棧(由一個或多個攔截器組成)
3) 攔截器棧
- <interceptor-stack name="攔截器棧的名稱">
- <!--需要注意的是:系統默認的攔截器棧應要放在前面,在加入自定義攔截器; -->
- <interceptor-ref name="defaultState"/>
- <interceptor-ref name="自定義攔截器的名稱"/>
- </interceptor-stack>
<interceptor-stack name="攔截器棧的名稱">
<!--需要注意的是:系統默認的攔截器棧應要放在前面,在加入自定義攔截器; -->
<interceptor-ref name="defaultState"/>
<interceptor-ref name="自定義攔截器的名稱"/>
</interceptor-stack>
4) 在action中使用棧
- <action>
- <interceptor-refnameinterceptor-refname="棧名稱或攔截器名稱"/>
- 。。。。。
- </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 {
- @Override
- protected String doIntercept(ActionInvocation invocation) throws Exception {
- // TODO Auto-generated method stub
- ActionContext context = invocation.getInvocationContext();
- // 通過ActionContext來獲取httpRequest
- HttpServletRequest 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";
- }
- }
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 {
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
// TODO Auto-generated method stub
ActionContext context = invocation.getInvocationContext();
// 通過ActionContext來獲取httpRequest
HttpServletRequest 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的配置:
- <SPAN style="FONT-SIZE: 18px"><?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>
- </SPAN>
<?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的生命週期中,攔截器可以多次被調用,而過濾器只能在容器初始化時被調用一次。