Struts 2框架内建了大量的拦截器,这些拦截器可以在Struts 2的配置文件struts-default.xml中查看。
Struts 2框架给出了这么多的拦截器,下面简要介绍它们的作用。
<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
<interceptor name="autowiring"
class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
<interceptor name="conversionError"
class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
<interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
<interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="externalRef"
class="com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor"/>
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception"
class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
<interceptor name="modelDriven"
class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
<interceptor name="scopedModelDriven"
class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="staticParams"
class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
<interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
<interceptor name="sessionAutowiring"
class="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor"/>
<interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation"
class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
<interceptor name="workflow"
class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
<interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
<interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
<interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />l alias:实现在不同请求中相似参数别名的转换。
l autowiring:这是个自动装配Spring,主要用于当Struts 2和Spring整合时,Struts 2可以使用自动装配的方式来访问Spring容器中的Bean。
l chain:构建一个Action链,使当前Action可以访问前一个Action的属性,一般和<result type="chain"/>一起使用。
l conversionError:这是一个负责处理类型转换错误的拦截器,它负责将类型转换错误从ActionContext中取出,并转换成Action的FieldError错误。
l createSession:该拦截器负责创建一个HttpSession对象,主要用于那些需要有HttpSession对象才能正常工作的拦截器。
l debugging:当使用Struts 2的开发模式时,这个拦截器会提供更多的调试信息。
l execAndWait:后台执行Action,负责将等待画面发送给用户。
l exception:这个拦截器负责处理异常,它将异常映射为结果。
l fileUpload:这个拦截器主要用于文件上传,它负责解析表单中文件域的内容。
l il8n:这是支持国际化的拦截器,它负责把所选的语言、区域放入用户Session中。
l logger:这是一个负责日志记录的拦截器,主要是输出Action的名字。
l model-driven:这是一个用于模型驱动的拦截器,当某个Action类实现了ModeiDriven接口时,它负责把getModel()方法的结果堆入ValueStack中。
l scoped-model-driven:如果一个Action实现了一个ScopedModeiDriven接口,该拦截器负责从指定生存范围中找出指定的Model,并将通过setModel方法将该Model传给Action实例。
l params:这是一个最基本的拦截器,它负责解析HTTP请求中的参数,并将参数值设置成Action对应的属性值。
l prepare:如果action实现了Preparable接口,将会调用该拦截器的prepare()方法。
l static-params:这个拦截器负责将xml中<action>标签下<param>标签中的参数传入action。
l scope:这是范围转换拦截器,它可以将Action状态信息保存到HttpSession范围,或者保存到ServletContext范围内。
l servlet-config:如果某个Action需要直接访问Servlet API,可以通过这个拦截器实现。
l roles:这是一个JAAS(Java Authentication and Authorization Service,Java授权和认证服务)拦截器,只有当浏览者取得合适的授权后,才可以调用被该拦截器拦截的Action。
l timer:这个拦截器负责输出Action的执行时间,在分析该Action的性能瓶颈时比较有用。
l token:这个拦截器主要用于阻止重复提交,它检查传到Action中的token,防止多次提交。
l token-session:这个拦截器的作用与前一个基本类似,只是它把token保存在HttpSession中。
l validation:通过执行在xxxAction-validation.xml中定义的校验器,完成数据校验。
l workflow:这个拦截器负责调用Action类中的validate方法,如果校验失败,则返回input的逻辑视图。
拦截器的配置是在struts.xml中完成的,定义一个拦截器使用<interceptor…/>标签,其格式如下:
<interceptor name="拦截器名" class="拦截器实现类"></interceptor>
这种情况的应用非常广。有的时候,如果需要在配置拦截器时就为其传入拦截器参数,只要在<interceptor..>与</interceptor>之间配置<param…/>标签即可传入相应的参数。其格式如下:
<interceptor name="拦截器名" class="拦截器实现类 ">
<param name="参数名">参数值</param>
...//如果需要传入多个参数,可以一并设置
</interceptor>
如果在其他的拦截器配置中出现了同名的参数,则前面配置的参数将被覆盖掉。
在struts.xml中可以配置多个拦截器,它们被包在<interceptors></interceptors>之间,例如下面的配置:
<?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>
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="拦截器名1" class="拦截器类1"></interceptor>
<interceptor name="拦截器名2" class="拦截器类2"></interceptor>
...
<interceptor name="拦截器名n" class="拦截器类n"></interceptor>
</interceptors>
...//action配置
</package>
</struts>
可以看出,拦截器是配置在包下的。在包下配置了一系列的拦截器,但仅仅是配置在该包下,并没有得到应用。如果要应用这些拦截器,就需要在<action>配置中引用这些拦截器,一个<action>需要应用多个拦截器,就不免要有多条引用语句(引用拦截器用标签<interceptor-ref.../>),所以Struts 2给出了拦截器栈的使用,一个拦截器栈中可以包含多个拦截器,配置拦截器栈的格式为。
<?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>
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="拦截器名1" class="拦截器类1"></interceptor>
<interceptor name="拦截器名2" class="拦截器类2"></interceptor>
<interceptor name="拦截器名n" class="拦截器类n"></interceptor>
<interceptor-stack name="拦截器栈名">
<interceptor-ref name="拦截器名1"></interceptor-ref>
<interceptor-ref name="拦截器名2"></interceptor-ref>
...//这里还可以配置很多拦截器,但是前提是这些拦截器已经配置存在
</interceptor-stack>
</interceptors>
</package>
</struts>其实,在Struts 2框架中也配置有很多拦截器栈,在Struts 2的struts-default.xml中可以发现有如下拦截器栈的配置。
<!-- Basic stack -->
<interceptor-stack name="basicStack">
<interceptor-ref name="exception" />
<interceptor-ref name="servletConfig" />
<interceptor-ref name="prepare" />
<interceptor-ref name="checkbox" />
<interceptor-ref name="params" />
<interceptor-ref name="conversionError" />
</interceptor-stack>
<!-- Sample validation and workflow stack -->
<interceptor-stack name="validationWorkflowStack">
<interceptor-ref name="basicStack" />
<interceptor-ref name="validation" />
<interceptor-ref name="workflow" />
</interceptor-stack>
<!-- Sample file upload stack -->
<interceptor-stack name="fileUploadStack">
<interceptor-ref name="fileUpload" />
<interceptor-ref name="basicStack" />
</interceptor-stack>
<!-- Sample model-driven stack -->
<interceptor-stack name="modelDrivenStack">
<interceptor-ref name="modelDriven" />
<interceptor-ref name="basicStack" />
</interceptor-stack>
<!-- Sample action chaining stack -->
<interceptor-stack name="chainStack">
<interceptor-ref name="chain" />
<interceptor-ref name="basicStack" />
</interceptor-stack>
<!-- Sample i18n stack -->
<interceptor-stack name="i18nStack">
<interceptor-ref name="i18n" />
<interceptor-ref name="basicStack" />
</interceptor-stack>
<interceptor-stack name="paramsPrepareParamsStack">
<interceptor-ref name="exception" />
<interceptor-ref name="alias" />
<interceptor-ref name="params" />
<interceptor-ref name="servletConfig" />
<interceptor-ref name="prepare" />
<interceptor-ref name="i18n" />
<interceptor-ref name="chain" />
<interceptor-ref name="modelDriven" />
<interceptor-ref name="fileUpload" />
<interceptor-ref name="checkbox" />
<interceptor-ref name="staticParams" />
<interceptor-ref name="params" />
<interceptor-ref name="conversionError" />
<interceptor-ref name="validation">
<param name="excludeMethods">
input,back,cancel
</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">
input,back,cancel
</param>
</interceptor-ref>
</interceptor-stack>
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception" />
<interceptor-ref name="alias" />
<interceptor-ref name="servletConfig" />
<interceptor-ref name="prepare" />
<interceptor-ref name="i18n" />
<interceptor-ref name="chain" />
<interceptor-ref name="debugging" />
<interceptor-ref name="profiling" />
<interceptor-ref name="scopedModelDriven" />
<interceptor-ref name="modelDriven" />
<interceptor-ref name="fileUpload" />
<interceptor-ref name="checkbox" />
<interceptor-ref name="staticParams" />
<interceptor-ref name="params">
<param name="excludeParams">dojo..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError" />
<interceptor-ref name="validation">
<param name="excludeMethods">
input,back,cancel,browse
</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">
input,back,cancel,browse
</param>
</interceptor-ref>
</interceptor-stack>
<interceptor-stack name="completeStack">
<interceptor-ref name="defaultStack" />
</interceptor-stack>
<interceptor-stack name="executeAndWaitStack">
<interceptor-ref name="execAndWait">
<param name="excludeMethods">
input,back,cancel
</param>
</interceptor-ref>
<interceptor-ref name="defaultStack" />
<interceptor-ref name="execAndWait">
<param name="excludeMethods">
input,back,cancel
</param>
</interceptor-ref>
</interceptor-stack>在struts-default.xml文件的最后还有这样一句代码:
<default-interceptor-ref name="defaultStack"/>
拦截器或拦截器栈配置完成后就可以在<action>中对其引用了,一个action引用拦截器或拦截器栈的格式如下:
<action name="Action名" class="Action类">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="拦截器1"></interceptor-ref>
<interceptor-ref name="拦截器2"></interceptor-ref>
</action>
可以看出,在为action指定拦截器时,配置了
<interceptor-ref name="defaultStack"></interceptor-ref>
5.3 自定义拦截器类
Struts 2提供了一些接口或类供程序员自定义拦截器。例如,Struts 2提供了com.opensymphony.xwork2.interceptor.Interceptor接口,程序员只要实现该接口就可完成自定义拦截器类的编写。该接口的代码如下:
public interface Interceptor extends Serializable{
void init();
String intercept(ActionInvocation invocation) throws Exception;
void destroy();
}
该接口中有如下三种方法。
l init():该方法在拦截器被实例化之后、拦截器执行之前调用。该方法只被执行一次,主要用于初始化资源。
l intercept(ActionInvocation invocation):该方法用于实现拦截的动作。该方法有个参数,用该参数调用invoke()方法,将控制权交给下一个拦截器,或者交给Action类的方法。
l destroy():该方法与init()方法对应,拦截器实例被销毁之前调用。用于销毁在init()方法中打开的资源
除了Interceptor接口之外,Struts 2框架还提供了AbstractInterceptor类,该类实现了Interceptor接口,并提供了init()方法和destroy()方法的空实现。在一般的拦截器实现中,都会继承该类,因为一般实现的拦截器是不需要打开资源的,故无须实现这两种方法,继承该类会更简洁。该类的代码实现为:
public interface AbstractInterceptor implements Interceptor{
public AbstractInterceptor();
public void init();
public void destroy();
public abstract String intercept(ActionInvocation invocation) throws Exception;
}
5.3.1 实例说明自定义拦截器的应用
首先创建项目(InterceptorTest)、加载Struts 2类库及修改web.xml,创建自定义拦截器类“MyInterceptor.java”,编写代码如下:
package org.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class MyInterceptor extends AbstractInterceptor{
public String intercept(ActionInvocation arg0) throws Exception {
System.out.println("我在Action前执行---->");
String result=arg0.invoke();
System.out.println("我在Action后执行---->");
return result;
}
}
创建Action类“TestAction.java”,编写代码如下:
package org.action;
import com.opensymphony.xwork2.ActionSupport;
public class TestAction extends ActionSupport{
public String execute() throws Exception {
System.out.println("我在Action中执行---->");
return NONE; //不做任何跳转
}
}
在struts.xml中配置action配置及拦截器配置,代码如下:
<?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>
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="myInterceptor" class="org.interceptor.MyInterceptor"/>
</interceptors>
<action name="test" class="org.action.TestAction">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="myInterceptor"></interceptor-ref>
</action>
</package>
</struts>
做这些简单的工作后,部署项目并启动服务器,在浏览器中输入“http://localhost:8080/InterceptorTest/test.action”请求,再查看控制台,
出现如图5.1所示的界面,可见,自定义拦截器起了作用,在Action执行前后分别输出了一句话
5.3.2 应用拦截器处理重复提交
创建项目(本书将该项目命名为TokenInterceptor),加载Struts 2类库,修改web.xml文件,修改index.jsp作为登录页面:
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>登录界面</title>
</head>
<body>
<s:form action="login" method="post">
<!-- 该标签在标签库中已做解释 -->
<s:token></s:token>
<s:textfield name="username" label="用户名"></s:textfield>
<s:password name="password" label="密码"></s:password>
<s:submit value="提交"></s:submit>
</s:form>
</body>
</html>
Action类LoginAction.java为:
package org.action;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport{
private String username;
private String password;
//省略上述属性的get和set方法
public String execute() throws Exception {
return SUCCESS;
}
}
在struts.xml中配置action及拦截器如下:
<?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>
<package name="default" extends="struts-default">
<action name="login" class="org.action.LoginAction">
<result>/welcome.jsp</result>
<result name="invalid.token">/wrong.jsp</result>
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="token"></interceptor-ref>
</action>
</package>
</struts>
成功返回界面welcome.jsp:
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>欢迎界面</title>
</head>
<body>
欢迎您!<s:property value="username"/>
</body>
</html>
重复提交的提示错误界面wrong.jsp:
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>错误界面</title>
</head>
<body>
对不起,请不要重复提交,单击<a href="index.jsp">这里</a>返回登录页面
</body>
</html>
部署运行该项目,登录界面如图5.2所示;输入用户名和密码进入成功界面,如图5.3所示