Struts2拦截器运作
拦截器是AOP思想的一种实现,可以将大问题分解成多个小问题。自己做的一个小项目用到struts2的拦截器,那么此处就回顾一下Struts2的拦截器知识。
拦截器(Interceptor)
拦截器是Struts2的核心组件,数据校验(validate,validateX)、国际化、文件上载下载等,这些都靠拦截器。Struts2定义的拦截器是按功能分开的,若要使用某个功能,就在某个控制器(Action)上,或在整个包(struts.xml里的package)里的Action上,加入拦截器。那么与Filter过滤器比起来,这就像插件了。
Filter作用的范围广,针对url过滤。Interceptor则围绕Action和Result。为什么这么说呢?这得看Struts2的工作流程,看图:
如图,一个来自浏览器的request,请求Action时,首先会经过多重拦截器,Action执行完,返回Result,Result会原路经过拦截器。
- Request发送给StrutsPrepareAndExecuteFilter。
StrutsPrepareAndExecuteFilter调用Action映射器ActionMapper,ActionMapper根据请求的URL来查找是否有对应的action可调用。
若是,返回一个描述了这个action的ActionMapper给StrutsPrepareAndExecuteFilter;
否,返回null。
有可用的action,那么StrutsPrepareAndExecuteFilter把请求交给ActionProxy,是开发人员编写的Action的代理类。
- ActionProxy创建一个ActionInvocation实例,并进行初始化。
执行Action前,一系列拦截器就被调用了。
ActionInvocation持有拦截器、Action实例、结果映射、ActionContext
- Action调用结束之后,会根据struts.xml文件中action的result配置对象,得到对应的返回结果。调用execute方法之后,对返回结果进行渲染。
- 再次执行拦截器,逆序的。
- 结果response返回到浏览器。
使用拦截器
使用拦截器,需要在struts.xml配置,并编写XXXInterceptor类
1.配置拦截器
可以定义一个拦截器:
<interceptor name="permission" class="com.interceptor.AuthorizationInterceptor"/>
若定义时,需要传入参数:
<interceptor name="permission" class="com.interceptor.AuthorizationInterceptor">
<param name="param">param</param>
</interceptor>
定义多个拦截器,则使用拦截器栈,使用拦截器时指定参数的话,会覆盖默认参数:
<package name="default" extends="rest-default,json-default">
<interceptors>
<interceptor name="permission" class="com.interceptor.AuthorizationInterceptor"/>
<interceptor-stack name="myStack">
<interceptor-ref name="permission">
//使用拦截器时,该包下的action,不拦截以下方法,多个方法,逗号隔开
<param name="excludeMethods">valid,logout,index</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
//对整个包下的action执行该拦截,这句别忘了,否则根本就不拦截了
<default-interceptor-ref name="myStack" />
<global-results>
<result name="error">/WEB-INF/content/error.jsp</result>
</global-results>
</package>
2.编写XXXInterceptor类
有三种方式
- 实现xwork2的Interceptor接口,init(),destory(),intercept()方法
- 继承AbstractInterceptor类,提供了init(),destory()的空实现,需重写intercept()方法
- 继承MethodFilterInterceptor类,该类本身也继承了AbstractInterceptor类。不同的是,用该方法编写的拦截器,在struts.xml配置时,可以有excludeMethods,includeMethods两个参数,表示不拦截的方法,和需要拦截的方法。
第二,第三种用得多,以第三种为例,需重写doIntercept()方法
import java.util.Map;
import org.springframework.stereotype.Component;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
public class AuthorizationInterceptor extends MethodFilterInterceptor {
private static final long serialVersionUID = 1L;
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
ActionContext context = ActionContext.getContext();
Map<String,Object> session = context.getSession();
Object user = session.get("user");
if(user==null) {
return "login";
}
return invocation.invoke();
}
}
小结
从这次的项目看,当需要自定义拦截器拦截范围时,可以考虑一下分开不同的package,尤其是用struts2的rest plugin时。
拦截器和过滤器很类似,Interceptor在struts.xml配置,拦截action请求,Filter在web.xml配置,拦截一切对象,范围广,更强大。