Struts2.0第04章Interceptor_第1頁
Struts2.0第04章Interceptor_第2頁
Struts2.0第04章Interceptor_第3頁
Struts2.0第04章Interceptor_第4頁
Struts2.0第04章Interceptor_第5頁
已閱讀5頁,還剩14頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、.第四章 InterceptorInterceptor(攔截器)顧名思義就是在某個事件發(fā)生之前將其攔截,并插入相應的處理過程。從這點上來看,攔截器類似于在Servelet規(guī)范中定義的Filter,但是Struts2的攔截器完全獨立于Servelet的Filter,而且兩者有著截然不同的實現(xiàn)。Interceptor將很多通用的功能從Action中獨立出來,大大減少了Action中重復的代碼量,通過組裝Interceptor可以使得通用的邏輯按照順序執(zhí)行,并且當業(yè)務邏輯順序發(fā)生變化的時候也不需要重新編寫代碼,只需重新組裝Interceptor即可,從而降低web應用的耦合性。在開發(fā)Web應用的過程

2、中,會碰到很多可以復用的模塊,如果不采取任何策略,無疑會增加應用的重復代碼量。Interceptor就是Struts2對這些可復用的應用模塊加以管理的策略。通過Interceptor可以把通用的模塊從Action中提取出來,供應用中的其它Action應用,甚至是供其它項目復用。4.1 Interceotor基礎對于攔截器而言,最主要就是要清楚攔截器在什么時候開始被調用,以及Struts2中是如何實現(xiàn)攔截器,最后還要清楚Struts2中自帶的攔截器有哪些,只有了解這些,才可以為以后使用攔截器打下基礎。4.1.1 Interceptor何時調用讓我們來看看Interceptor到底在什么時候被調用

3、,又是如何被調用。首先讓我們來分析com.opensymphony.xwork2.DefaultActionInvocation源代碼看看一般的Action調用流程,注意下面的代碼片斷。DefaultActionInvoation.java/*省略其他方法*/ public String invoke() throws Exception if (executed) throw new IllegalStateException(Action has already executed); if (interceptors.hasNext() InterceptorMapping interce

4、ptor = (InterceptorMapping) interceptors.next(); resultCode = interceptor.getInterceptor().intercept(this); else resultCode = invokeActionOnly(); /*省略語句*/ 在執(zhí)行Action之前,Struts2會檢查Action是否配置有攔截器,如果有,遍歷所有攔截器并且執(zhí)行之,如果對應的Action沒有配置攔截器,那么Struts2將只執(zhí)行Action。但是似乎并沒有看到Action和Interceptor的執(zhí)行的先后次序,別著急,讓我們看看其它的代碼里有

5、沒有關于Interceptor的執(zhí)行先后次序。Xwork的攔截器都必須實現(xiàn)Interceptor接口,但是實際上大部分的攔截器都是通過繼承抽象類AbstractInterceptor實現(xiàn)攔截器的功能。下面來了解下AbstractInterceptor類的具體代碼。AbstractInterceptor.javapackage erceptor;import com.opensymphony.xwork2.ActionInvocation;public abstract class AbstractInterceptor implements

6、 Interceptor public void init() public void destroy() public abstract String intercept(ActionInvocation invocation) throws Exception;在這個抽象類中沒有實現(xiàn)任何方法,就是一個簡單Interceptor接口的實現(xiàn)。那么攔截器要在Action之前執(zhí)行,那么只有在繼承這個類時,通過實現(xiàn)它的抽象方法intercept()來完成攔擊器的功能。也就是說在intercept()方法中會先執(zhí)行攔截器想要完成的任務,然后再轉向Action執(zhí)行,一般函數(shù)最后會加上這句代碼:Strin

7、g result = invocation.invoke();通過上面的介紹,不難發(fā)現(xiàn),Interceptor的本質也是一個Action,畢竟其產(chǎn)生的目的就是為了提高Action代碼的復用性,降低Action的耦合性。但是Interceptor又是一種特殊的Action,因為其執(zhí)行于指定Action或之前,或之后完成可復用的模塊化業(yè)務邏輯。Interceptor能夠攔截Action的執(zhí)行,它的出現(xiàn)使得開發(fā)者能夠在Action執(zhí)行之前或者之后執(zhí)行一段業(yè)務邏輯。它們同時也可以阻止Action的執(zhí)行,使得開發(fā)者對一段通用的業(yè)務邏輯進行封裝,然后用在其它地方。下面通過對Interceptor的源代碼中

8、的類和接口的展示,希望能夠使讀者對Interceptor的本質有更深一層次的認識。4.1.2 Interceptor接口攔截器是一個Struts2框架很好的特性,它的使用十分靈活,同時框架為了滿足特定的需要實現(xiàn)了一些特定的API,用戶可以根據(jù)自己的需要選用。表4-1 Interceptor提供的預定義接口Interceptor定義的接口描述Interceptorinterceptor 是采用 interceptor 模式的一種無狀態(tài)類NoParameters這個接口通常由不需要參數(shù)附加的Action實現(xiàn)ParameterNameAware這個接口通常由需要參數(shù)附加的Action實現(xiàn)PreRes

9、ultListener實現(xiàn)這個接口可以獲得一個在Action之后但是結果之前的回調n Interceptor:是所有攔截器必須實現(xiàn)的一個接口。n NoParameters:這個標記接口應該由那些不想要任何參數(shù)附加的Action來實現(xiàn),這種情況通常是這樣的,用戶在使用Action標簽,不想框架附加任何參數(shù)給次Action,而是想要手動的來設置這些參數(shù)。n ParameterNameAware:這個接口通常由那些需要參數(shù)附加的Action實現(xiàn),通常和ParametersInterceptor配合起來實現(xiàn)參數(shù)的附加,例如Action可能有這樣一份參數(shù)的白名單和黑名單,前者列出的參數(shù)是允許用戶設置的,

10、而后者列出的則拒絕用戶的設置。n PreResultListener:實現(xiàn)這個接口的Action可以獲得一個在Action執(zhí)行之后但是結果執(zhí)行之前的回調。4.1.3 Interceptor相關類在進行Interceptor編寫的時候,同Action的編寫一樣,Struts2也提供了一些框架支持的類,這些類的使用,可以大大便利我們進行相關的攔截器的開發(fā)。讀者可以在實際的應用中根據(jù)自己需要使用這些類。表4-2 Interceptor 提供的相關類類描述AbstractLifecycleInterceptor提供了before(),after() 以及result之前的攔截AliasIntercep

11、tor為類似的Action 的類似參數(shù)提供別名服務AroundInterceptor提供了before(),after() 攔截ChainingInterceptor將值棧中所有的對象拷貝到當前對象,當前對象實現(xiàn)unchainable()接口的除外ConversionErrorInterceptor如果Action執(zhí)行了ValidationAware()接口,那么將所有轉換錯誤添加到域錯誤表DefaultWorkflowInterceptor在允許ActionChain繼續(xù)執(zhí)行之前完成一些基本的操作如校驗ExceptionHolder對Exception的簡單封裝,方便使用ExceptionM

12、appingInterceptor次攔截器是異常處理的核心I18nInterceptor設置ActionRequest國際化的本地信息LoggingInterceptor記錄Action執(zhí)行的日志攔截器MethodFilterInterceptor可以包含和排除一些方法執(zhí)行的攔截器ModelDrivenInterceptor觀察modelDriven的Action執(zhí)行情況并將其添加到值棧ParameterFilterInterceptor參數(shù)過濾的攔截器ParametersInterceptor將所有參數(shù)設置到值棧PrefixMethodInvocationUtil一個執(zhí)行一些固定方法的工具類

13、PrepareInterceptor調用實現(xiàn)了preparable接口方法的Action的prepare()方法TimerInterceptor記錄以秒為單位的時間日志仔細的分析這些類可以發(fā)現(xiàn),其涉及了Struts2 Interceptor的全部。類的功能涉及了Action執(zhí)行的方方面面。幾乎在Action執(zhí)行的任何時刻,都可以找到適合的攔截器截斷Action的執(zhí)行。使其完成想要的業(yè)務邏輯功能。靈活的運用這些類,那么我們幾乎就掌握了Action執(zhí)行的每一個方面,就能夠對Action的執(zhí)行進行精準的控制。4.2使用預定義的InterceptorStruts2預先設計了很多通用性很強的Interc

14、eptor供用戶使用。靈活的使用這些攔截器,不僅可以更好的設計更具通用性的業(yè)務模塊,而且可以增加Web應用的可測試性,使得Web應用的開發(fā)和維護變得更為便捷。4.2.1預定義Interceptor類攔截器的使用,可以抽取系統(tǒng)的各個方面的可復用代碼。當然在實際的開發(fā)中可能有一些模塊是經(jīng)常使用到的,或者說是每一個進行Web應用開發(fā)的程序員都要使用到的,Struts2考慮到了這樣的情況,并且預先抽取了這些復用性很強的模塊。那么Struts2自帶的攔截器的配置在struts-default.xml都有配置,在struts-2.0.9-all.zip壓縮包的src目錄下。通過搜索,在路徑struts-2

15、.0.9-allstruts-2.0.9srccoresrcmainresources下可以找到這個文件,打開之后下面是其關于攔截器配置部分的代碼:struts-default.xml/*省略其他配置語句*/ /*省略其他配置語句*/配置文件中指出了每個自帶攔截器對應的類以及它們的名字,那么它們具體的功能可以通過閱讀類的源代碼知道,表4-3中提供一些常用攔截器實現(xiàn)的功能表4-3 Struts2框架預定義的攔截器名稱描述chain將參數(shù)從一個Action復制到另一個Actioncomponent為Action應用IoC的邏輯處理conversionError如果出現(xiàn)類型轉換錯誤,則增加對應字段錯

16、誤execAndWait生成一個獨立的線程來執(zhí)行ActionfileUpload設置上傳文件為Action文件logger記錄Action執(zhí)行的起始時間model-driven將Action模型壓入值棧params將HTTP參數(shù)應用于Actionprepare調用Action的prepare()方法servlet-config提供對通用HTTP對象的訪問static-params將Action映射設定的參數(shù)應用到Action實例中timer控制Action的定時執(zhí)行token防止表單重復提交的基本實現(xiàn)token-session防止表單重復提交的高級實現(xiàn)validation校驗Action中的字

17、段值workflow如果發(fā)生錯誤則自動返回INPUT這個返回類型例如校驗攔截器validation這個攔截器就對表單的校驗提供了極大的便利,這一點在以后的章節(jié)中,將繼續(xù)講解。為了方便初學者的使用,Struts2框架還預定義了若干攔截器棧,所謂的攔截器棧就是將攔截器一個接一個的組裝起來,這些裝配好的攔截器棧往往有著特殊的用途,讓我們大致了解一下這些棧??纯催@些組合在一起的攔截器又將為開發(fā)帶來什么樣的便捷特性。攔截器棧的相關配置也是在struts-default.xml實現(xiàn)的,下面是這個文件中關于攔截器棧的配置部分。struts-default.xml/*省略其他配置語句*/ /*省略其他配置語句

18、*/上面的攔截器棧的配置只是所有攔截器棧的一部分,讀者可以自己找到這個文件,找出所有棧的配置。表4-4中列出部分常用攔截器棧的功能。表4-4 Struts2 框架預定義的攔截器棧名稱描述defaultStack基本的攔截器棧validationWorkflowStack配置了validation和workflow攔截的棧fileUploadStack配置了fileupload的攔截器棧componentStack配置了反轉控制的攔截器棧modelDrivenStack配置了modelDriven的攔截器棧chainStack配置了chain的攔截器棧execAndWaitStack配置了exe

19、cAndWait的攔截器棧completeStack配置了所有攔截器的攔截器棧這里面的攔截棧其實是在實際的開發(fā)過程中經(jīng)常要用到的,例如文件上傳攔截棧,這個攔截棧的定義,使得在開發(fā)有關文件上傳的組件的時候,就不必考慮文件上傳的細節(jié)了,而是可以把精力集中在業(yè)務邏輯上,又如攔截棧,這個框架定義的攔截棧,是用戶在使用框架定義的攔截器,不可或缺的一個部分。4.2.2 LoggingInterceptor示例這一節(jié)我們使用框架為我們定義的日志攔截器(LoggingInterceptor)為我們的Action記錄日志??蚣軐崿F(xiàn)的這個攔截器的功能很簡單,下面讓首先來看看這個例子。LoggingAction.j

20、avapackage example;import com.opensymphony.xwork2.Action;public class LoggingAction implements Actionpublic String execute()delay();return SUCCESS;private void delay()for ( int i=0;i10000;i+);這個Action簡單的做一個延遲,(后面為了計算Action的執(zhí)行時間),然后轉向success頁面。它的確是夠簡單,因為這里要重點演示的是Interceptor。struts.xml 在這個文件里面,我們配置了一個

21、Struts2框架預定義的日志攔截器,名稱為logger然后在action里面引用了這個攔截器,指示這個攔截器和這個Action裝配,對這個Action起作用。這樣當Struts2框架發(fā)現(xiàn)了這個裝配的攔截器之后,在調用Action之前就會去調用這個攔截器,從而達到預期的目的。這個例子的目錄圖如圖4-1所示:圖4-1例子的完整目錄如果配置正確的話,部署到Tomcat下,然后在瀏覽器地址欄輸入:http:/localhost:8080/Logging/logging.action頁面會有一個“result null not found”的信息,是因為我們沒有配置返回頁面,但是可以在控制臺得到這樣的

22、輸出:圖4-2 LoggingAction的對應輸出可以看到,在控制器執(zhí)行的前后,日志攔截器分別截獲了控制器的執(zhí)行,并輸出了對應的日志新日,如“/logging”這個Interceptor好像完成的工作也并不是很多,讓我們看看它到底是如何工作的。該文件在erceptor.LoggingInterceptor中。LoggingInterceptor.java/省略導入包public class LoggingInterceptor extends AbstractInterceptor private static final Log log

23、 = LogFactory.getLog(LoggingInterceptor.class); private static final String FINISH_MESSAGE = Finishing execution stack for action ; private static final String START_MESSAGE = Starting execution stack for action ; public String intercept(ActionInvocation invocation) throws Exception logMessage(invoc

24、ation, FINISH_MESSAGE); /記錄結束信息 String result = invocation.invoke(); logMessage(invocation, START_MESSAGE);/記錄開始信息 return result; private void logMessage(ActionInvocation invocation, String baseMessage) if (log.isInfoEnabled() StringBuffer message = new StringBuffer(baseMessage); String namespace =

25、invocation.getProxy().getNamespace(); if (namespace != null) & (namespace.trim().length() 0) message.append(namespace).append(/); message.append(invocation.getProxy().getActionName(); (message.toString(); 這個是框架實現(xiàn)的一個日志攔截器,通過對源代碼的分析,用戶可以在編寫自己的模塊的時候可以參考Struts2的源代碼,比如下面的記時攔截器就是參考了這里的日志攔截器。通過對源代碼

26、的分析,我們還可以了解到攔截器的具體實現(xiàn)方式,并編寫自己的攔截器去實現(xiàn)Interceptor接口。參考源代碼,發(fā)現(xiàn)原來也可以通過繼承這樣的基類AbstractInterceptor來實現(xiàn)interceptor接口從而實現(xiàn)自己的攔截器,同時這樣做一個好處就是代碼的邏輯很清楚,在執(zhí)行Action之前,首先執(zhí)行l(wèi)ogMessage()函數(shù)在控制臺有一個輸出,在Action執(zhí)行結束后又有一個信息輸出,在兩個信息輸出之間通過ActionInvocation類可以獲得當前要執(zhí)行的Action有關的信息,然后執(zhí)行Action相關操作。掌握了攔截器的這幾個方面那么用戶就可以對攔截器的執(zhí)行進行粒度很小的控制。4

27、.3使用自定義的Interceptor閱讀了框架的Logging攔截器的源代碼,可以發(fā)現(xiàn)一個攔截器的實現(xiàn)也很簡單,下面模仿框架的日志攔截器設計一個記時攔截器,這個攔截器不僅記錄Action的執(zhí)行時間,而且同時還輸出執(zhí)行日志。大致可以分為一下幾個步驟:1. 定義自己的攔截器邏輯2. 配置自己的攔截器3. 將自定義的攔截器裝配到對應的控制器進行攔截4. 運行實例查看效果4.3.1自定義Interceptor的配置Interceptor的配置大同小異,注意struts.xml中的粗體顯示的片斷。struts.xml 這些地方就是用戶在框架中配置攔截器的地方。從上面的配置文件的代碼我們也可以看出,首先

28、我們是先定義了一個自定義的攔截器,然后在對應的要使用的控制器中使用了這個攔截器,通過這樣的配置,攔截器和控制器的裝配工作就完成了,下面看看這個攔截器的具體內容。4.3.2實現(xiàn)自己的Interceptor本小節(jié)使用一個自定義的Interceptor,對Action執(zhí)行前和執(zhí)行后進行計時,并且在Action執(zhí)行結束后向控制臺輸出對應的日志信息。同時在Action執(zhí)行完成之后使用這兩個時間計算出整個Action的運行時間。LogAndTime.javapackage example;import mons.logging.Log;import mons.logging.LogFactory;impo

29、rt com.opensymphony.xwork2.ActionInvocation;import erceptor.AbstractInterceptor;SuppressWarnings(serial)public class LogAndTime extends AbstractInterceptor private static final Log log = LogFactory.getLog(LogAndTime.class); private static final String FINISH_MESSAGE = Syst

30、em Administrator Finishing execution stack for action ; private static final String START_MESSAGE = System Administrator Starting execution stack for action ; /設定了一些輸出信息字符串 private long startTime; /聲明了開始時間 private long executeTime; / 聲明了執(zhí)行時間 private void logMessage(ActionInvocation invocation, Strin

31、g baseMessage) if (log.isInfoEnabled() StringBuffer message = new StringBuffer(baseMessage); String namespace = invocation.getProxy().getNamespace(); if (namespace != null) & (namespace.trim().length() 0) message.append(namespace).append(/); message.append(invocation.getProxy().getActionName(); log.

32、info(message.toString(); /記錄日志信息 Overridepublic String intercept(ActionInvocation invocation) throws Exception logMessage(invocation, START_MESSAGE); startTime = System.currentTimeMillis(); String result = invocation.invoke(); logMessage(invocation, FINISH_MESSAGE); executeTime = System.currentTimeM

33、illis() - startTime; /執(zhí)行時間,等于當前時間-開始時間。當前時間是控制器的Execute()方法執(zhí)行后 String TIMESTRING=The Action: +invocation.getProxy().getActionName()+has executed +executeTime+ MilliSeconds;/設定時間信息 System.out.println(TIMESTRING); /獲得當前的執(zhí)行時間付給開始執(zhí)行時間return result;在這個interceptor的實現(xiàn)里面,使用了框架對Interceptor的支持類。使用這些支持類的好處是:這樣

34、可以更加方便,便捷的構建自己想要的攔截器。在這個例子中在Action執(zhí)行的前后都對Action進行了攔截,在Action執(zhí)行前,將其攔截,記錄下此時的時間,然后輸出一行控制信息到控制臺,表明已經(jīng)執(zhí)行到Action之前。然后Interceptor會喚醒Action繼續(xù)執(zhí)行,執(zhí)行完之后,Interceptor會繼續(xù)將Action捕獲,獲得此時的時刻,和執(zhí)行開始前的一比較,便得出了整個Action執(zhí)行所耗費的時間,同時向控制臺輸出信息表明已經(jīng)執(zhí)行完這個Action了。那么再看下這個例子的目錄,如圖4-3所示:圖4-3例子的完整目錄如果配置無誤,在瀏覽器地址欄輸入:http:/localhost:80

35、80/Logging/logging.action 那么將得到下面的結果:圖4-4自定義攔截器的輸出結果首先要注意的一點就是這里的所有的控制信息都是在標準輸出(控制臺)輸出的,而不是在相應的頁面。本例中的結果是輸出在eclipse的控制臺的。從輸出的結果可以看出編寫的攔截器成功的執(zhí)行了,首先在Action執(zhí)行前,攔截器記錄當前的時間并輸出日志”.starting execution.”然后在Action執(zhí)行之后,又輸出日志信息”.fininshing execution.”同時記錄當前的執(zhí)行時間,并計算除整個Action的執(zhí)行時間(執(zhí)行后-執(zhí)行前)。輸出執(zhí)行時間。4.4 Interceptor

36、應用實例在前面學習的知識,在這一節(jié)將完成一個綜合的Interceptor例子。這個例子中既會用到自定義的攔截器也會使用Struts2提供的預定義的攔截器。完成頁面等待的效果,由于某個Action要執(zhí)行較長的一段時間,在頁面跳轉到另一個頁面之前,先會進入一個等待的頁面,等待頁面裝載。其實在互聯(lián)網(wǎng)上這種頁面等待的效果會經(jīng)常被用到,現(xiàn)在就借用Struts2的攔截器來實現(xiàn)這個功能。自定義攔截器部分將會使用第二章最后小節(jié)的自定義攔截器,即GreetingInterceptor。為了達到頁面等待的效果,要借助Struts2提供execAndWait攔截器,這個攔截器的功能在前面的表中可以查到,就是生成一個獨立的線程來執(zhí)行Action。為什么選擇這個攔截器,將會在下面的源碼分析部分詳細解釋。有了這兩個攔截器就可以完成這個實例。整個流程是這樣的:輸入訪問地址之后,首先會出現(xiàn)一個等待的頁面,大概等待10秒之后,跳入一個輸入頁面,用戶輸入姓名提交之后,根據(jù)當前的時間生成特定的問候語。為了讓讀者能夠正確阿使用Struts2提供e

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論