
4.4 Struts 2的拦截器
拦截器(Interceptor)是Struts 2的核心组成部分。拦截器动态拦截Action调用的对象,它提供了一种机制,使开发者可以定义一个特定的功能模块,这个模块可以在Action执行之前或者之后运行,也可以在一个Action执行之前阻止Action执行。拦截器分为两类:Struts 2提供的内建拦截器和用户自定义的拦截器。
对于Struts 2框架提供的内建的拦截器,可以完成框架所提供的相关功能和操作,例如,文件的上传和下载、国际化、转换器和数据校验等。对于Struts 2内建拦截器的应用将在4.5~4.7节给出。本节主要介绍Struts 2拦截器的自定义实现。
4.4.1 Struts 2拦截器的自定义实现
为了实现自定义拦截器,Struts 2提供了Interceptor接口,以及对该接口实现的一个抽象拦截器类(AbstractInterceptor)。创建拦截器类可以实现Interceptor接口,也可以直接继承AbstractInterceptor类;同时,Struts 2还提供了一个MethodFilterIntercepter类,该类是AbstractInterceptor类的子类,若要实现方法过滤,就需要继承MethodFilterIntercepter,设计方法拦截器。
1.拦截器接口与抽象拦截器类
Struts 2提供的Interceptor接口(Interceptor.java)的代码如下。
import com.opensymphony.xwork2.ActionInvocation; import java.io.Serializable; public interface Interceptor extends Serializable { void destroy(); //用于在拦截器执行完之后,释放init()方法里打开的资源 void init(); //由拦截器在执行之前调用,主要用于初始化系统资源 String intercept(ActionInvocation invocation) throws Exception; }
其中,String intercept(ActionInvocation invocation) throws Exception是拦截器的核心方法,用于实现具体的拦截操作,返回一个字符串作为逻辑视图。
另外,抽象拦截器类(AbstractInterceptor),是对接口Interceptor的一种实现。
2.自定义拦截器
用户自定义拦截器,首先通过实现Interceptor接口(或继承AbstractInterceptor或继承MethodFilterIntercepter)的类创建自定义拦截器类;然后,在struts.xml中注册自定义的拦截器;最后,在需要使用的Action中引用已经注册的拦截器。
(1)创建拦截器类
实现接口Intercepter(或继承AbstractInterceptor),并在interceptor方法中加入有关的处理代码,其格式示例如下。

(2)在Struts.xml中注册拦截器并引用拦截器
在struts.xml中注册声明拦截器,并在Action中引用拦截器,配置格式如下。

注意:一旦某个Action引用了自定义的拦截器,Struts 2默认的拦截器就不会再起作用了,为此,还需要引用默认拦截器栈。
3.自定义方法拦截器
Struts 2还提供了方法拦截器类MethodFilterInterceptor,该类继承AbstractInterceptor类,重写了intercept()方法,并提供了新的抽象方法doInterceptor()。通过该拦截器可以指定哪些方法需要被拦截,哪些方法不需要被拦截。其创建过程如下。
1)建立拦截器:继承MethodFilterInterceptor,创建一个拦截器。
2)在配置文件内注册拦截器:该类拦截器只能配置在Action内部,格式如下。

注意:
(1)exculdMethods:指定不被拦截的方法,若有多个方法以逗号分隔。
(2)includMethods:指定被拦截的方法,若有多个方法以逗号分隔。
4.在interceptor方法中,利用参数ActionInvocation可获取页面提交的信息

4.4.2 案例——文字过滤器的设计与应用
【例4-6】开发一个网上论坛过滤系统,如果网友发表的文字中有不文明的文字,将通过拦截器对不文明的文字进行自动替代。该示例只是给出了一种简单的过滤,过滤是否有“讨厌”文字,若有“讨厌”,则用“喜欢”代替要过滤的“讨厌”,形成新的文本内容并显示在论坛上。运行界面如图4-6所示。

图4-6 【例4-6】的运行界面
a) 提交页面b) 过滤后显示信息的页面
【分析】对于该案例,需要编写一个自定义拦截器(MyInterceptor.java),一个发表新闻评论的页面(news.jsp)及其对应的业务控制器PublicAction类,以及评论成功页面success.jsp。
【设计关键】该问题的关键是设计一个拦截器MyInterceptor.java,该拦截器的工作过程是:在页面提交后,获取所提交的请求参数信息,判定其是否含有“讨厌”文字,并进行处理,处理后重新修改请求参数值,然后再执行Action或下一个过滤器。
【实现】
1)建立工程:struts2_Interceptor,并在web.xml中配置核心控制器。
2)根据如图4-6所示的页面,设计评论页面(news.jsp),其代码如下。
<%@ page language="java" pageEncoding="UTF-8"%> <%@taglib prefix="s" uri="/struts-tags"%> <html> <head> <title>评论</title> </head> <body> 请发表你的评论!<hr> <s:form action="public" method="post"> <s:textfield name="title" label="评论标题" maxLength="36"/> <s:textarea name="content" cols="36" rows="6" label="评论内容"/> <s:submit value="提交"/> </s:form> </body> </html>
3)编写评论成功页面(success.jsp)。
<%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>评论成功</title> </head> <body> 评论如下:<hr> 评论标题:<s:property value="title"/> <br> 评论内容:<s:property value="content"/> </body> </html>
4)评论页面对应的业务控制器(PublicAction.java)。
package action; import com.opensymphony.xwork2.ActionSupport; public class PublicAction extends ActionSupport{ private String title; private String content; //属性的getter/setter方法 public String execute(){return SUCCESS; } }
5)编写自定义拦截器:MyInterceptor.java。
编写一个自定义拦截器用于对发表评论的内容进行过滤,代码如下。
package interceptor; //省略了import; public class MyInterceptor extends AbstractInterceptor { public String intercept(ActionInvocation ai) throws Exception { //获取页面提交的所有属性及属性值 Map<String, Object> parameters = ai.getInvocationContext().getParameters(); //对每对属性、属性值分别进行过滤,将过滤后的内容再保存到该属性中 for (String key : parameters.keySet()) { Object value = parameters.get(key); if ( value ! = null && value instanceof String[]) { String[] valueArray = (String[]) value; for (int i = 0; i < valueArray.length; i++) { if( valueArray[i] ! = null ){ //判断用户提交的评论内容是否有要过滤的内容 if(valueArray[i].contains("讨厌")) { //以“喜欢”代替要过滤的内容“讨厌” valueArray[i] =valueArray[i].replaceAll("讨厌", "喜欢"); //把替代后的评论内容设置为Action的评论内容 parameters.put(key, valueArray); } } } } } return ai.invoke(); //执行下一个拦截器或Action } }
6)在struts.xml中配置自定义拦截器和Action。
修改配置文件struts.xml,在配置文件中配置拦截器和Action。
<struts> <package name="default" namespace="/" extends="struts-default"> <interceptors> <! --文字过滤拦截器配置,replace是拦截器的名称--> <interceptor name="replace" class="interceptor.MyInterceptor" /> </interceptors> <action name="public" class="action.PublicAction"><! --文字过滤Action配置--> <result name="success">/success.jsp</result> <result name="login">/success.jsp</result> <interceptor-ref name="replace"/> <! --使用自定义拦截器--> <interceptor-ref name="defaultStack"/> <! --Struts 2系统默认拦截器--> </action> </package> </struts>
7)项目部署和运行。部署后,运行效果如图4-6所示。