攔截器在概念上和servlet過濾器或JDKs代理類一樣。攔截器允許橫切功能在動(dòng)作和框架中單獨(dú)實(shí)現(xiàn)。你可以使用攔截器實(shí)現(xiàn)下面的內(nèi)容:
在動(dòng)作被調(diào)用之前提供預(yù)處理邏輯。
在動(dòng)作被調(diào)用之后提供預(yù)處理邏輯。
Struts 2 框架提供的許多功能都是使用攔截實(shí)現(xiàn)的;例如包括異常處理,文件上傳,生命周期回調(diào)和驗(yàn)證等。事實(shí)上,由于 Struts 2 是許多攔截器功能的基礎(chǔ),所以每次動(dòng)作不是不可能有 7 個(gè)或 8 個(gè)攔截器被分配。
Struts 2 框架提供了一列開箱即用的攔截器來預(yù)先設(shè)定和準(zhǔn)備使用。下面列出了幾個(gè)重要的攔截器:
序號(hào) | 攔截器及描述 |
---|---|
1 |
alias
允許參數(shù)有不同的跨請(qǐng)求的別名。 |
2 |
checkbox
通過為沒有被檢查的復(fù)選框添加一個(gè)參數(shù)值 false 來協(xié)助管理復(fù)選框。 |
3 |
conversionError
把從字符串轉(zhuǎn)化為參數(shù)類型的錯(cuò)誤信息放置到動(dòng)作的字段錯(cuò)誤中。 |
4 |
createSession
如果不存在 HTTP 會(huì)話,則自動(dòng)創(chuàng)建一個(gè) HTTP 會(huì)話。 |
5 |
debugging
為開發(fā)人員提供幾種不同的調(diào)試屏幕。 |
6 |
execAndWait
當(dāng)動(dòng)作在后臺(tái)執(zhí)行的時(shí)侯,把用戶定向到一個(gè)中間的等待頁面。 |
7 |
exception
映射動(dòng)作拋出的異常到一個(gè)結(jié)果中,通過重定向允許自動(dòng)異常處理。 |
8 |
fileUpload
有利于簡(jiǎn)單的文件上傳。 |
9 |
i18n
在用戶的會(huì)話期間,跟蹤選定的語言環(huán)境。 |
10 |
logger
通過輸出被執(zhí)行的動(dòng)作的名稱提供簡(jiǎn)單的日志。 |
11 |
params
設(shè)置動(dòng)作的請(qǐng)求參數(shù)。 |
12 |
prepare
它通常是用來做預(yù)處理工作,如設(shè)置數(shù)據(jù)庫連接。 |
13 |
profile
|
14 |
scope
在會(huì)話或應(yīng)用程序的范圍中存儲(chǔ)和檢索動(dòng)作的狀態(tài)。 |
15 |
ServletConfig
為行動(dòng)提供了各種基于 servlet 信息的訪問。 |
16 |
timer
以動(dòng)作需要多長(zhǎng)時(shí)間執(zhí)行的形式提供了簡(jiǎn)單的配置信息。 |
17 |
token
為有效的標(biāo)記檢查動(dòng)作用來防止重復(fù)地表單提交。 |
18 |
validation
為動(dòng)作提供了驗(yàn)證支持。 |
關(guān)于上面提到的攔截器的完整信息,請(qǐng)查看 Struts 2 的文檔。但是我會(huì)告訴你通常如何在你的 Struts 應(yīng)用程序中使用一個(gè)攔截器。
讓我們來看看如何在我們的 “Hello World” 程序中使用已存在的攔截器。我們將使用 timer 攔截器,它的目的是測(cè)量它多長(zhǎng)時(shí)間執(zhí)行一個(gè)動(dòng)作的方法。同時(shí)我使用 params 攔截器,它的目的是給動(dòng)作發(fā)送請(qǐng)求參數(shù)。你可以嘗試在你的例子中不使用這個(gè)攔截器,你將會(huì)發(fā)現(xiàn) name 屬性沒有被設(shè)置,因?yàn)閰?shù)是無法達(dá)到動(dòng)作中的。
我們將保留 HelloWorldAction.java,web.xml,HelloWorld.jsp 和index.jsp 文件,因?yàn)樗麄円呀?jīng)在 Examples 章節(jié)被創(chuàng)建了,但是讓我們修改 struts.xml 文件,添加一個(gè)攔截器,如下所示:
<?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.devMode" value="true" /> <package name="helloworld" extends="struts-default"> <action name="hello" class="com.tutorialspoint.Struts 2.HelloWorldAction" method="execute"> <interceptor-ref name="params"/> <interceptor-ref name="timer" /> <result name="success">/HelloWorld.jsp</result> </action> </package> </struts>
右鍵單擊項(xiàng)目名稱,并且單擊 Export > WAR File 來創(chuàng)建一個(gè) War 文件。然后在 Tomcat 的 webapps 目錄下部署這個(gè) WAR。最后,啟動(dòng) Tomcat 服務(wù)器和嘗試訪問 URL http://localhost:8080/HelloWorldStruts 2/index.jsp
. 將會(huì)給出下面的畫面:
http://wiki.jikexueyuan.com/project/struts-2/images/helloworldstruts4.jpg" alt="" />
現(xiàn)在,在給定的文本框中輸入任何單詞,并且單擊 Say Hello 按鈕執(zhí)行已定義的動(dòng)作?,F(xiàn)在,如果你查看生成的日志,就會(huì)發(fā)現(xiàn)下面的文字:
INFO: Server startup in 3539 ms
27/08/2011 8:40:53 PM
com.opensymphony.xwork2.util.logging.commons.CommonsLogger info
INFO: Executed action [//hello!execute] took 109 ms.
在這里最后一行是因?yàn)?timer 攔截器生成長(zhǎng)的,它告訴動(dòng)作被執(zhí)行的時(shí)間的 109ms。
在你的應(yīng)用程序中使用自定義的攔截器是一種提供橫切的應(yīng)用功能的簡(jiǎn)潔的方式。創(chuàng)建一個(gè)自定義的攔截器是很容易的,需要擴(kuò)展的接口是下面的 Interceptor 接口:
public interface Interceptor extends Serializable{
void destroy();
void init();
String intercept(ActionInvocation invocation)
throws Exception;
}
正如名稱所顯示的,init() 方法提供了一種初始化攔截器的方法,而destroy() 方法提供了一種清理攔截器的工具。與動(dòng)作不同的是,攔截器在請(qǐng)求之間被重用,而且需要是線程安全的,尤其是 intercept() 方法。
ActionInvocation 對(duì)象提供運(yùn)行時(shí)環(huán)境的訪問。它允許訪問動(dòng)作本身和方法來調(diào)用該動(dòng)作,并判定動(dòng)作是否已經(jīng)被調(diào)用。
如果你不需要初始化或清理代碼,可以擴(kuò)展 AbstractInterceptor 類。它提供了一個(gè)對(duì) init() 和 destroy() 方法的默認(rèn)的無操作實(shí)現(xiàn)。
讓我們?cè)?Java Resources > src 文件夾中創(chuàng)建下面的MyInterceptor.java:
package com.tutorialspoint.Struts 2;
import java.util.*;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class MyInterceptor extends AbstractInterceptor {
public String intercept(ActionInvocation invocation)throws Exception{
/* let us do some pre-processing */
String output = "Pre-Processing";
System.out.println(output);
/* let us call action or next interceptor */
String result = invocation.invoke();
/* let us do some post-processing */
output = "Post-Processing";
System.out.println(output);
return result;
}
}
如你注意到的,實(shí)際的動(dòng)作將通過使用攔截器調(diào)用 invocation.invoke() 來執(zhí)行。所以,你可以根據(jù)你的需求做一些預(yù)處理和一些后處理。
這個(gè)框架本身通過第一次調(diào)用 ActionInvocation 對(duì)象的 invoke() 來啟動(dòng)過程。每次 invoke() 被調(diào)用,ActionInvocation 查詢它的狀態(tài),并且執(zhí)行接下來的攔截器。當(dāng)所有已配置的攔截器已經(jīng)被配置時(shí),invoke() 方法將引發(fā)這個(gè)動(dòng)作本身被執(zhí)行。下面的圖通過請(qǐng)求流顯示了相同的概念:
http://wiki.jikexueyuan.com/project/struts-2/images/actioninvocation.jpg" alt="" />
讓我們?cè)?Java Resources > src 中名為 com.tutorialspoint.Struts 2 的包下創(chuàng)建一個(gè) java 文件HelloWorldAction.java,它的內(nèi)容在下面給出。
package com.tutorialspoint.Struts 2;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorldAction extends ActionSupport{
private String name;
public String execute() throws Exception {
System.out.println("Inside action....");
return "success";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
我們已經(jīng)在前面的例子中看到這個(gè)相同的類。我們對(duì)于 “name” 屬性有標(biāo)準(zhǔn)的 getters 和 setters 方法,還有返回字符串 “success” 的 execute 方法。
讓我們?cè)?eclipse 項(xiàng)目的 WebContent 文件夾中創(chuàng)建下面的 jsp 文件 helloWorld.jsp。
<%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>Hello World</title> </head> <body> Hello World, <s:property value="name"/> </body> </html>
我們還需要在 WebContent 文件夾中創(chuàng)建 index.jsp。這個(gè)文件將作為初始動(dòng)作 URL,用戶可以點(diǎn)擊它告訴 Struts 2 框架調(diào)用HelloWorldAction 類定義的方法,并且呈現(xiàn) HelloWorld.jsp 視圖。
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Hello World</title> </head> <body> <h1>Hello World From Struts 2</h1> <form action="hello"> <label for="name">Please enter your name</label><br/> <input type="text" name="name"/> <input type="submit" value="Say Hello"/> </form> </body> </html>
上面的視圖文件中定義的 hello 動(dòng)作將使用 struts.xml 文件映射到 HelloWorldAction 類和它的 execute 方法中。
現(xiàn)在,我們需要注冊(cè)我們的攔截器,然后調(diào)用它,就如我們已經(jīng)在前面的例子中調(diào)用了默認(rèn)的攔截器一樣。為了注冊(cè)一個(gè)新定義的攔截器,可以把
<?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.devMode" value="true" /> <package name="helloworld" extends="struts-default"> <interceptors> <interceptor name="myinterceptor" class="com.tutorialspoint.Struts 2.MyInterceptor" /> </interceptors> <action name="hello" class="com.tutorialspoint.Struts 2.HelloWorldAction" method="execute"> <interceptor-ref name="params"/> <interceptor-ref name="myinterceptor" /> <result name="success">/HelloWorld.jsp</result> </action> </package> </struts>
應(yīng)該注意的是,你可以在
web.xml 文件需要在 WebContent 的 WEB-INF 文件夾下創(chuàng)建,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>Struts 2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>Struts 2</filter-name>
<filter-class>
org.apache.Struts 2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>Struts 2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
右鍵單擊項(xiàng)目名稱,并且單擊 Export > WAR File 來創(chuàng)建一個(gè) War文件。然后在 Tomcat 的 webapps 目錄下部署這個(gè) WAR。最后,啟動(dòng)Tomcat 服務(wù)器和嘗試訪問 URL http://localhost:8080/HelloWorldStruts 2/index.jsp/
將會(huì)給出下面的畫面:
http://wiki.jikexueyuan.com/project/struts-2/images/helloworldstruts4.jpg" alt="" />
現(xiàn)在,在給定的文本框中輸入任何單詞,并且單擊 Say Hello 按鈕執(zhí)行已經(jīng)定義的動(dòng)作?,F(xiàn)在,如果你查看生成的日志,就會(huì)在底部發(fā)現(xiàn)下面的文字:
Pre-Processing
Inside action....
Post-Processing
可想而知,為每個(gè)動(dòng)作配置多個(gè)攔截器很快就會(huì)變得非常難以管理。為此,攔截器用攔截器棧進(jìn)行管理。這兒有一個(gè)例子,直接來自 struts-default.xml 文件:
<interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servlet-config"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
上面的棧被稱為 basicStack,它可以用在你的配置中,如下所示。這個(gè)配置節(jié)點(diǎn)被放置在
我們已經(jīng)看到了如何應(yīng)用攔截器到動(dòng)作中,應(yīng)用攔截器棧是沒有什么不同的。實(shí)際上,我們完全使用相同的標(biāo)簽:
<action name="hello" class="com.tutorialspoint.Struts 2.MyAction">
<interceptor-ref name="basicStack"/>
<result>view.jsp</result>
</action
上述注冊(cè)的 “basicStack” 將完整地注冊(cè)所有帶有 hello 動(dòng)作的 6 個(gè)攔截器。應(yīng)該指出的是,攔截器按照已配置的順序執(zhí)行。例如,在上述情況下,將首先執(zhí)行異常,第二個(gè)執(zhí)行的是 servlet 配置等等。