拦截器的概念
Java 里的拦截器是动态拦截 action 调用的对象。它提供了一种机制可以使开发者可以定义在一个action 执行的前后执行的代码,也可以在一个action 执行前阻止其执行,同时也提供了一种可以提取action 中可重用部分的方式。在AOP(Aspect-OrientedProgramming)中拦截器用于在某个方法或字段被访问之前进行拦截,然后在之前或之后加入某些操作。
拦截器的原理
大部分时候,拦截器方法都是通过代理的方式来调用的。Struts2的拦截器实现相对简单。当请求到达Struts2的ServletDispatcher时,Struts2 会查找配置文件,并根据配置实例化相对的拦截器对象,然后串成一个列表(List),最后一个一个的调用列表中的拦截器。Struts2的拦截器是可 插拔的,拦截器是AOP的一个实现。Struts2拦截器栈就是将拦截器按一定的顺序连接成一条链。在访问被拦截的方法或者字段时,Struts2拦截器链 中的拦截器就会按照之前定义的顺序进行调用。
自定义拦截器的步骤 第一步:自定义一个实现了Interceptor接口的类,或者继承抽象类AbstractInterceptor。 第二步:在配置文件中注册定义的拦截器。 第三步:在需要使用Action中引用上述定义的拦截器,为了方便也可以将拦截器定义为默认的拦截器,这样在不加特殊说明的情况下,所有的 Action都被这个拦截器拦截。
过滤器与拦截器的区别 过滤器可以简单的理解为“取你所想取”,过滤器关注的是web请求;拦截器可以简单的理解为“拒你所想拒”,拦截器关注的是方法调用,比如拦截 敏感词汇。 1,拦截器是基于java反射机制来实现的,而过滤器是基于函数回调来实现的。(有人说,拦截器是基于动态代理来实现的) 2,拦截器不依赖servlet容器,过滤器依赖于servlet容器。 3,拦截器只对Action起作用,过滤器可以对所有请求起作用。 4,拦截器可以访问Action上下文和值栈中的对象,过滤器不能。 5,在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时调用一次。
看下HandlerInterceptor
package org.springframework.web.servlet.handler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public abstract class HandlerInterceptorAdapter implements HandlerInterceptor{ // 在业务处理器处理请求之前被调用 public boolean preHandle(HttpServletRequest request, HttpServletResponseresponse, Object handler) throws Exception{ return true; } // 在业务处理器处理请求完成之后,生成视图之前执行 public void postHandle(HttpServletRequest request,HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception{ } // 在DispatcherServlet完全处理完请求之后被调用,可用于清理资源 public void afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex) throws Exception{ } }
下面,我们利用Spring框架提供的HandlerInterceptorAdapter抽过类,来实现一个自定义的拦截器。
首先再配置文件中配置拦截器:
<mvc:interceptors>
<bean class="com.test.core.interceptor.LoginInterceptor"/>
</mvc:interceptors>
public class LoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String str = request.getRequestURI();
String uri = str.split("\\?")[0];
/**
* 接口不拦截
*/
if (uri.startsWith("/service/")) {
return super.preHandle(request, response, handler);
}
//首页 登录 验证码 js css gif png jpg 不拦截
if (uri.endsWith("login") ||
uri.endsWith("registVerfyCode") ||
uri.equals("/errorBrowser") ||
uri.endsWith(".js") ||
uri.endsWith(".css") ||
uri.endsWith(".gif") ||
uri.endsWith(".png") ||
uri.endsWith(".jpg") ||
uri.endsWith(".ico") ||) {
return super.preHandle(request, response, handler);
} else {
//获取session
HttpSession session = request.getSession();
if (null != session.getAttribute(SessionKeysConstant.LOGIN_USER)) {
return super.preHandle(request, response, handler);
} else {
if (request.getHeader("x-requested-with") != null && request.getHeader("x-
requested-with").equalsIgnoreCase("XMLHttpRequest")) { //如果是ajax请求响应头会有,x-requested-withresponse.setHeader("sessionstatus", "timeout");//在响应头设置session状态
} else {
response.sendRedirect("/login");
}
return false;
}
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
super.afterCompletion(request, response, handler, ex);
}
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
super.afterConcurrentHandlingStarted(request, response, handler);
}
}
拦截器实现的两种方式:
第一种:继承HandlerInterceptor
第二种:继承WebRequestInterceptor
这两种的区别:对于prehandler而言,第一种有返回值,能终止请求,第二种没有返回值,不能终止请求。