1、理解Struts2拦截器
a) 拦截器体系是Struts2框架的重要组成部分,我们可以把Struts2理解成一个空容器,而大量的内建拦截器完成了该框架的大部分操作。比如,
n params拦截器负责解析HTTP请求的参数,并设置Action的属性,
n fileUpload拦截器则负责解析请求参数中的文件域,并将一个文件域设置成Action的三个属性等这些操作都是通过Struts2的内建拦截器完成的。
b) Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP(面向切面编程,使用动态代码模式实现)的一种实现.一些需要统一处理的问题可以使用拦截器。比如 :如果需要处理action中文乱码问题就可以写一个中文乱码问题处理的拦截器,写好拦截器类后在我们action 配置中(就是struts.xml 中的<action>节点)加入该拦截器就可以了。引入拦截器的方式等下在拦截器配置中进行详细说明。
c) 拦截器栈(Interceptor Stack)。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。
2、Struts2拦截器执行流程
Struts2拦截器的执行流程类似于servlet的filter,在struts2容器启动时并根据其配置实例化并调用init方法,每次请求action时会根据action的配置调用相应的拦截器进行拦截调用拦截器的intercept方法并传入ActionInvocation对象,当所有的拦截器都执行完成后才调用action的方法(默认是execute), 这里需要注意拦截器的intercept方法如果不要终断业务逻辑必须调用ActionInvocation的invoke()方法(表示继续调用下一个intercept),action处理完成业务逻辑后会再次回到拦截执行ActionInvocation.invoke()方法后的代码逻辑。
下图为strut2拦截器的执行流程图:
拦截器时序图:
3、拦截器接口说明
a) Interceptor接口 filter
每一个拦截器都必须实现com.opensymphony.xwork2.interceptor.Interceptor接口,该接口在xwork-core的jar包中。Interceptor 接口类似于servlet的Filter接口内部有三个方法,下图为拦截器的方法清单:
方法名 | 参数 | 说明 |
init | 无 | 当struts2容器实例化拦截器类的时候会调用拦截器的init方法,用于对拦截器类进行些初始化的工作,进行一些资源的初始化。 |
destroy | 无 | 当struts2容器关闭并销毁拦截器时会调用该方法,进行资源释放。 |
intercept | ActionInvocation | Intercept是拦截器的主要拦截方法,如果需要调用后续的Action或者拦截器,只需要在该方法中调用invocation.invoke()方法即可,在该方法调用的前后可以插入Action调用前后拦截器需要做的方法。如果不需要调用后续的方法,则返回一个String类型的对象即可,例如Action.SUCCESS。 |
接口常用方法说明
方法名称 | 参数 | 说明 |
invoke | 无 | 调用该方法表示执行下一个拦截器,如果需要让流程继续,并将请求传送到action必须调用该方法。 |
getAction | 无 | 得到当前请求的action实例,可用于修改action的属性值,比方说可以对action的复杂数据类型进行组装 |
getInvocationContext | 无 | 返回ActionContext实例,可以通过该实例获取到当前请求的请求参数等。 |
a) ActionInvocation接口
该接口我们称之为Action调度者, 我在这里需要指出的是一个很重要的方法invocation.invoke()。这是ActionInvocation中的方法,这个方法具备以下2层含义
1. 如果拦截器堆栈中还有其他的Interceptor,那么invocation.invoke()将调用堆栈中下一个Interceptor的执行。
2. .如果拦截器堆栈中只有Action了,那么invocation.invoke()将调用Action执行。params
l 整个拦截器的核心部分是invocation.invoke()这个函数的调用位置。事实上,我们也正是根据这句代码的调用位置,来进行拦截类型的区分的。
在Struts2中,Interceptor的拦截类型,分成以下两类:
//代码。。
System.out.println(“before”);
invock. invoke();
System.out.println(“after”);
//代码
1. before
before拦截,是指在拦截器中定义的代码,它们存在于invocation.invoke()代码执行之前。这些代码,将依照拦截器定义的顺序,顺序执行。
2. after
after拦截,是指在拦截器中定义的代码,它们存在于invocation.invoke()代码执行之后。这些代码,将依照拦截器定义的顺序,逆序执行。
一、 拦截器配置
要使用拦截器.必须在struts的配置文件中进行配置
1、配置示例
<interceptors>
<interceptor name="testInter" class="com.itjob.struts.action.MyInteseptor">
</ interceptor >
<interceptor-stack name="mystack">
<interceptor-ref name="testInter">
<param name="encode">utf-8</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="mystack"/>
<action name="test" class="com.itjob.struts.action.TimeInterTest">
<result name="success">/index.jsp</result>
</action>
2、节点说明:
a) Interceptors:
配置一个拦截器集。可以在其中定义拦截器和拦截器栈,注意该节点必须包含在<package>节点中。其中可以包含多个<interceptor>和<interceptor-stack>子节点
b) Interceptor:
配置自定义的拦截器,其中有两个属性 name 属性表示拦截器的名称,如果某个action需要被该拦截器拦截,可通过name属性引用。Class属性表示一个实现了Interceptor接口的类的全限定类名。
c) interceptor-stack:
拦截器栈包含若干拦截器的引用,其中可以包含一个name属性,表示拦截器的名称,同interceptor的name属性相同。该节点可以包含多个子节点,每个子节点表示引用一个拦截器或者拦截器栈。
如果需要自定义几个拦截器可以将它们引用到该节点组成一个拦截器栈,那么在需要使用这些拦截器的action中只要引用这个拦截器栈即可,这样的话action将会被拦截器栈中的所有拦截器拦截。
【注意】:这里必须要引用struts2的默认拦截器栈defaultStack要不然启动会报错。
【注意】:拦截的执行顺序跟栈中的位置一致
d) interceptor-ref
该节点表示引用一个拦截器或者拦截器栈,name属性指定要引用的拦截器或者拦截器栈的名称(对应拦截器或拦截器栈定义标签中的name属性),该节点可以包含多个子节点<param>等下会详解介绍。
e) default-interceptor-ref
该节点用于配置package的默认拦截器或者拦截器栈,表示package中所有的action都会被所配置的拦截器拦截。该节点属于package的子节点
注意:该节点必须在配置在action节点的前面。否则会报错
f) param
该节点用于配置拦截器的参数。每一个拦截器都可以配置参数,有两种方式配置参数,该 节点包含一个name属性表示参数名,拦截器中只需定义一个名称一致并且有get,set方法的全局变量就可以得到param标签的本体内容的值(示例中的红色部分)
一是针对每一个拦截器定义参数,二是针对一个拦截器堆栈统一定义所有的参数,拦截器中只需要定认name属性,属于<interceptor-ref>
例如:
<interceptor-ref name="validation">
<param name="excludeMethods">myValidationExcudeMethod</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">myWorkflowExcludeMethod</param>
</interceptor-ref>
或者
<interceptor-ref name="defaultStack">
<param name="validation.excludeMethods">myValidationExcludeMethod</param>
<param name="workflow.excludeMethods">myWorkflowExcludeMethod</param>
</interceptor-ref>
注意:param的值只有在拦截action的时候才会注入,所以说在拦截器的init方法中不能得到param的值
三、Struts2(XWork)提供的拦截器的功能说明:
拦截器 | 名字 | 说明 |
Alias Interceptor | alias | 在不同请求之间将请求参数在不同名字间转换,请求内容不变 |
Chaining Interceptor | chain | 让前一个Action的属性可以被后一个Action访问,现在和chain类型的result(<result type=”chain”>)结合使用。 |
Checkbox Interceptor | checkbox | 添加了checkbox自动处理代码,将没有选中的checkbox的内容设定为false,而html默认情况下不提交没有选中的checkbox。 |
Cookies Interceptor | cookies | 使用配置的name,value来是指定cookies |
Conversion Error Interceptor | conversionError | 将错误从ActionContext中添加到Action的属性字段中。 |
Create Session Interceptor | createSession | 自动的创建HttpSession,用来为需要使用到HttpSession的拦截器服务。 |
Debugging Interceptor | debugging | 提供不同的调试用的页面来展现内部的数据状况。 |
Execute and Wait Interceptor | execAndWait | 在后台执行Action,同时将用户带到一个中间的等待页面。 |
Exception Interceptor | exception | 将异常定位到一个画面 |
File Upload Interceptor | fileUpload | 提供文件上传功能 |
I18n Interceptor | i18n | 记录用户选择的locale |
Logger Interceptor | logger | 输出Action的名字 |
Message Store Interceptor | store | 存储或者访问实现ValidationAware接口的Action类出现的消息,错误,字段错误等。 |
Model Driven Interceptor | model-driven | 如果一个类实现了ModelDriven,将getModel得到的结果放在Value Stack中。 |
Scoped Model Driven | scoped-model-driven | 如果一个Action实现了ScopedModelDriven,则这个拦截器会从相应的Scope中取出model调用Action的setModel方法将其放入Action内部。 |
Parameters Interceptor | params | 将请求中的参数设置到Action中去。 |
Prepare Interceptor | prepare | 如果Acton实现了Preparable,则该拦截器调用Action类的prepare方法。 |
Scope Interceptor | scope | 将Action状态存入session和application的简单方法。 |
Servlet Config Interceptor | servletConfig | 提供访问HttpServletRequest和HttpServletResponse的方法,以Map的方式访问。 |
Static Parameters Interceptor | staticParams | 从struts.xml文件中将<action>中的<param>中的内容设置到对应的Action中。 |
Roles Interceptor | roles | 确定用户是否具有JAAS指定的Role,否则不予执行。 |
Timer Interceptor | timer | 输出Action执行的时间 |
Token Interceptor | token | 通过Token来避免双击 |
Token Session Interceptor | tokenSession | 和Token Interceptor一样,不过双击的时候把请求的数据存储在Session中 |
Workflow Interceptor | workflow | 调用Action的validate方法,一旦有错误返回,重新定位到INPUT页面 |
Parameter Filter Interceptor | N/A | 从参数列表中删除不必要的参数 |
Profiling Interceptor | profiling | 通过参数激活profile |
四、自定义拦截器
自定义拦截器非常简单。
只需要简单三步:
1、 写一个java类并且实现Interceptor 或者继承AbstractInterceptor类,AbstractInterceptor抽象类比较简单只提供了init和destroy方法的空实现和一个抽象的intercept方法。如果我们的拦截器不需要初始化可以考虑继承自这个类。
public abstract class AbstractInterceptor implements Interceptor {
public void init() {
}
public void destroy() {
}
public abstract String intercept(ActionInvocation invocation) throws Exception;
}
2、 在struts.xml的Interceptors节点中配置拦截器在拦截器配置中有比较详细的介绍
<interceptors>
<interceptor name="testInter" class="com.itjob.struts.action.MyInteseptor"/>
</interceptors>
3、 在需要被拦截的
action
的配置中引用拦截器
<action name="point" class="com.itjob.struts.action.PointAction">
<result name="success">/index.jsp</result>
<interceptor-ref name="pointInterceptor"/>
</action>
五、拦截器案例params
使用自定义拦截器模拟自动注入请求参数到action,在action中定义一个Point类其中有x和y两个属性,通过拦截器将界面表单的x和y表单域的值注入到action的point对象中。
1、 实现思路:
在拦截的intercept 方法,通过invocation.getAction()方法得到当前请求的action实例,再通过invocation.getInvocationContext().get(ServletActionContext.HTTP_REQUEST);得到HttpServletRequest实例,注意因为get方法返回的是Object类型所以这里必须进行类型强转。然后将request中的值设置到action中。因为在一次请求当中action的实例是同一个所以action中的point对象就有x和y的值了。实现方式,在point.jsp界面点击提交后提交到PointAction在Action中不作任何处理只是跳转到index.jsp在index.jsp中通过action中的point属性将x和y显示出来。
2、 代码示例:
Point类:
package com.itjob.struts.pojo;
public class Point {
private int x;
private int y;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
Index.jsp
<body>
<form action="point" method="post">
<input type="text" name="x">
<input type="text" name="y">
<input type="submit" />
</form>
</body>
PointAction.java
package com.itjob.struts.action;
import com.itjob.struts.pojo.Point;
import com.opensymphony.xwork2.Action;
public class PointAction {
private Point point = new Point();
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
}
public String execute(){
return Action.SUCCESS;
}
}
Struts.xml
<action name="point" class="com.itjob.struts.action.PointAction">
<result name="success">/index.jsp</result>
</action>
Index.jsp
<body>
x:${point.x }y:${point.y }
</body>
PointInterceptor.java
public class PointInteseptor implements Interceptor {
public void destroy() {
}
public void init() {
}
public String intercept(ActionInvocation invocation) throws Exception {
//得到request对象
HttpServletRequest req = (HttpServletRequest)invocation.getInvocationContext().get(ServletActionContext.HTTP_REQUEST);
//获取请求参数
String x = req.getParameter("x");
String y = req.getParameter("y");
//得到当前的action实例
Object action = invocation.getAction();
//判断是否是PointAction类型
if(action instanceof PointAction){
//类型强转
PointAction pa = (PointAction)action;
//将实例化一个Point对象 并且将请求参数中的x和y设置到action实例
Point p = new Point();
p.setX(Integer.parseInt(x));
p.setY(Integer.parseInt(y));
pa.setPoint(p);
}
return invocation.invoke();
}
}