拦截器的定义:
在访问某个Action或者Action的某个方法的时候,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP的一种实现。
拦截器栈的定义:
Struts2拦截器栈就是拦截器按一定的顺序联结成一条链,在访问被拦截方法或者字段的时候,struts2拦截器链中的拦截器就会按其之前的顺序被调用。
拦截器的原理:
当请求到达ServletDispatcher的时候,Struts2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表list,最后一个个的调用列表中的拦截器。这些都是由于动态代理的使用。动态代理是代理对象根据客户的需求做出不同的处理,对于客户来说,只要知道一个代理对象即可。当Action请求到来的时候,会由系统的代理生成一个Action的代理对象,由这个代理对象调用Action的execute或者指定的方法,并在struts.xml中查找与该Action对应的拦截器,如果有对应的拦截器,就在Action的方法执行前或者后调用这些拦截器,如果没有对应的拦截器则执行Action的方法,其中拦截器的调用是通过ActionInvocation来实现的。
Struts2的拦截器的具体配置文件在struts-default.xml,比如上传文件的拦截器、国际化的拦截器等等,请见以下struts2-core的jar包的文件。
拦截器和Action并没有直接的发生关联,完全是通过代理组织与Action协同工作的。
接口Interceptor中仅仅有三个方法,分别是destroy、init、和核心方法intercept。
例子:
在登录中判断权限,使用拦截器,
首先在struts.xml中配置声明拦截器,并且加上全局的配置。代码如下:
<interceptors>
<!-- 声明一个拦截器 -->
<interceptor name="checkePrivilege" class="cn.itcast.oa.interceptor.CheckPrivilegeInterceptor"></interceptor>
<!-- 重新定义defaultStack拦截器栈,需要先判断权限 -->
<interceptor-stack name="defaultStack">
<interceptor-ref name="checkePrivilege" />
<interceptor-ref name="defaultStack" />
</interceptor-stack>
</interceptors>
<!-- 配置全局的Result -->
<global-results>
<result name="loginUI">/WEB-INF/jsp/userAction/loginUI.jsp</result>
<result name="noPrivilegeError">/noPrivilegeError.jsp</result>
</global-results>
具体实现是继承AbstractInterceptor,判断权限的代码:
package cn.itcast.oa.interceptor;
import cn.itcast.oa.domain.User;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class CheckPrivilegeInterceptor extends AbstractInterceptor {
public String intercept(ActionInvocation invocation) throws Exception {
// System.out.println("-----> 之前");
// String result = invocation.invoke(); // 放行
// System.out.println("-----> 之后");
// return result;
// 获取当前用户
User user = (User) ActionContext.getContext().getSession().get("user");
// 获取当前访问的URL,并去掉当前应用程序的前缀(也就是 namespaceName + actionName )
String namespace = invocation.getProxy().getNamespace();
String actionName = invocation.getProxy().getActionName();
String privilegeUrl = null;
if (namespace.endsWith("/")) {
privilegeUrl = namespace + actionName;
} else {
privilegeUrl = namespace + "/" + actionName;
}
// 要去掉开头的'/'
if (privilegeUrl.startsWith("/")) {
privilegeUrl = privilegeUrl.substring(1);
}
// 如果未登录用户
if (user == null) {
if (privilegeUrl.startsWith("userAction_login")) { // userAction_login, userAction_loginUI
// 如果是正在使用登录功能,就放行
return invocation.invoke();
} else {
// 如果不是去登录,就转到登录页面
return "loginUI";
}
}
// 如果已登录用户(就判断权限)
else {
if (user.hasPrivilegeByUrl(privilegeUrl)) {
// 如果有权限,就放行
return invocation.invoke();
} else {
// 如果没有权限,就转到提示页面
return "noPrivilegeError";
}
}
}
}
这样就可以轻松的在登录的时候实现权限问题了。