攔截器(Interceptor)是Struts 2的核心組成部分。很多功能(Feature)都是構(gòu)建在攔截器基礎(chǔ)之上的,例如文件的上傳和下載、國際化、轉(zhuǎn)換器和數(shù)據(jù)校驗(yàn)等,Struts 2利用內(nèi)建的攔截器,完成了框架內(nèi)的大部分操作。
在Struts 2文檔中對攔截器的解釋為——攔截器是動態(tài)攔截Action調(diào)用的對象。它提供了一種機(jī)制,使開發(fā)者可以定義一個特定的功能模塊,這個模塊可以在Action執(zhí)行之前或者之后運(yùn)行,也可以在一個Action執(zhí)行之前阻止Action執(zhí)行。同時也提供了一種可以提取Action中可重用的部分的方式。
5.2 Struts 2攔截器
通過上一節(jié)的介紹,讀者會對攔截器的原理有了一個基本的理解,本節(jié)來介紹Struts 2架構(gòu)中的攔截器。
5.2.1 Struts 2攔截器原理
讀者可以通過Struts 2官方文檔說明來理解攔截器,如果讀者具有較強(qiáng)的英文閱讀能力,建議查閱官方使用文檔(http://struts./2.0.11/docs/interceptors.html)。如圖5.4所示,是攔截器在Struts 2中的示意圖。

圖5.4 Struts 2攔截器
從圖5.4所示內(nèi)容中可以看出,Struts 2架構(gòu)的Action被一個或者多個攔截器(攔截器棧)所包圍,所有的用戶請求都會被攔截器所攔截,然后交給Action處理,處理結(jié)果以邏輯視圖方式返回給用戶。而這個調(diào)用執(zhí)行流程,是由Struts 2的配置文件來實(shí)現(xiàn)的,后面會詳細(xì)介紹。攔截器是Struts 2核心部分之一。
當(dāng)用戶請求到達(dá)Struts 2的ServletDispatcher時,Struts 2會查找配置文件,并根據(jù)其配置實(shí)例化相對的攔截器對象,然后串成一個列表(List),最后一個一個地調(diào)用列表中的攔截器。攔截器時序圖如圖5.5所示。

圖5.5 Struts 2攔截器時序圖
在Struts 2架構(gòu)中,Action的調(diào)用都是通過攔截器來實(shí)現(xiàn)的。有的讀者可能會疑惑,前幾章的介紹中,沒有明確說明攔截器,為什么可以直接調(diào)用Action?那是因?yàn)?/span>Struts 2架構(gòu)如果不做顯式的攔截器配置,則系統(tǒng)會調(diào)用默認(rèn)的攔截器來調(diào)用Action,在用戶看來,好像沒有配置攔截器。系統(tǒng)默認(rèn)的攔截器筆者后面會詳細(xì)介紹。
5.2.2 HelloWorld攔截器
讀者可以按照筆者的步驟,一步一步建立第一個攔截器示例,來體驗(yàn)Struts 2框架中攔截器帶給讀者的驚喜。
(1) 在配置文件中增加攔截器定義和在Action中聲明攔截器。筆者建立了一個目錄ch5來對應(yīng)本章,ch5.xml配置文件內(nèi)容如代碼5.8所示。
<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts PUBLIC

"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

"http://struts./dtds/struts-2.0.dtd">

<struts>

<!-- 定義包-->

<package name="ch5" extends="struts-default" namespace="/ch5">

<!-- 定義攔截器-->

<interceptors>

<interceptor name="Myinterceptor"

class="ch5.Myintercepor">

</interceptor>

</interceptors>

<action name="Reg" class="ch5.Reg">

<result name="success">/ch5/success.jsp</result>

<result name="input">/ch5/reg.jsp</result>

<!-- 引用默認(rèn)攔截器-->

<interceptor-ref name="defaultStack"></interceptor-ref>

<!-- 引用自定義默認(rèn)攔截器-->

<interceptor-ref name="Myinterceptor"></interceptor-ref>

</action>

</package>

</struts>


★ 注意 ★
需要讀者在struts.xml文件中使用<include file="/ch5/ch5.xml"></include>將該配置文件包含進(jìn)去。
(2)在ch5包內(nèi)建立一個攔截器類Myintercepor,如代碼5.9所示。
代碼5.9 Helloworld攔截器類Myintercepor
package ch5;

import com.opensymphony.xwork2.ActionInvocation;

import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class Myintercepor extends AbstractInterceptor {

//攔截方法

public String intercept(ActionInvocation arg0) throws Exception {

Reg reg = (Reg) arg0.getAction();

System.out.println("攔截器信息:HelloWorld攔截器!");

//執(zhí)行Action或者執(zhí)行下一個攔截器

String result = arg0.invoke();

//提示Action執(zhí)行完畢

System.out.println("攔截器信息:Action執(zhí)行完畢!");

return result;

}

}


(3)在ch5包內(nèi)建立一個業(yè)務(wù)控制器Reg,如代碼5.10所示。
代碼5.10 HelloWorld攔截器示例的業(yè)務(wù)控制器
package ch5;

import java.util.Date;

import com.opensymphony.xwork2.ActionSupport;

public class Reg extends ActionSupport {

//定義用戶名屬性

private String username;

//定義處理信息:注意同http中的msg不同名稱

private String mymsg;

//定義密碼屬性

private String password1;

//定義確認(rèn)密碼

private String password2;

//定義生日屬性

private Date birthday;

public String execute() throws Exception {

if (username != null && getPassword1().equals(getPassword2())

&& !getUsername().trim().equals("")) {

//輸出調(diào)試信息

System.out.println("Action信息:正在執(zhí)行Actiion... ...");

return SUCCESS;

} else {

return INPUT;

}

}

//getter和setter方法

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getMymsg() {

return mymsg;

}

public void setMymsg(String mymsg) {

this.mymsg = mymsg;

}

public String getPassword1() {

return password1;

}

public void setPassword1(String password1) {

this.password1 = password1;

}

public String getPassword2() {

return password2;

}

public void setPassword2(String password2) {

this.password2 = password2;

}

public Date getBirthday() {

return birthday;

}

public void setBirthday(Date birthday) {

this.birthday = birthday;

}

}


(4)同樣在ch5包內(nèi),建立一個用戶注冊reg.jsp文件和一個用于顯示注冊成功信息的success.jsp文件。內(nèi)容分別如代碼5.11和代碼5.12所示。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%@ taglib prefix="s" uri="/struts-tags" %>

<html>

<head>

<title>注冊成功界面</title>

<s:head />

</head>

<body>

<table>

<h2>用戶名:<s:property value="username" /></h2>

<h2>密碼:<s:property value="password1" /></h2>

<h2>生日:<s:property value="birthday" /></h2>

</table>

</body>

</html>


(5) 啟動Tomcat服務(wù)器,在瀏覽器中輸入:http://localhost:8080/bookcode/ch5/reg.jsp,運(yùn)行界面如圖5.6所示。

圖5.6 HelloWorld攔截器的注冊界面
(6)讀者可以在“用戶名”、“密碼”、“確認(rèn)密碼”和“生日”輸入框中填入相關(guān)字符串,單擊“注冊”按鈕,會發(fā)現(xiàn)Tomcat控制臺輸出如下信息:
… …
信息: Detected AnnotationActionValidatorManager, initializing it...
攔截器信息:HelloWorld攔截器!
Action信息:正在執(zhí)行Actiion... ...
攔截器信息:Action執(zhí)行完畢!
… …
到此為止,第一個攔截器HelloWorld示例就建立成功了,讀者通過本示例,可以了解攔截器的基本功能。
★ 說明 ★
Struts 2框架提供的攔截器功能確實(shí)給項目開發(fā)提供了一個非常有用的手段。后面筆者將會逐步深入介紹Struts 2的攔截器。