拦截器顾名思义就是用于拦截访问请求的,我们可以在拦截器里对访问请求进行事先的处理,例如权限检查、记录日志、验证请求数据等等。说白了就是我们可以在请求到控制器之前对其进行一个处理。
拦截器基本上和过滤器是类似的,只不过拦截器提供的方法比较实用,参数也比较多,而且拦截器是受到spring容器的管理的。
实现拦截器很简单,只需要实现spring里的HandlerInterceptor接口并实现接口中的三个方法即可,如下示例:
package org.zero01.test;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TestInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("TestInterceptor--拦截器的preHandle方法被执行了");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
System.out.println("TestInterceptor--拦截器的postHandle方法被执行了");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println("TestInterceptor--拦截器的afterCompletion方法被执行了");
}
}
注:在springmvc4.x版本中这三个方法都是必须要实现的,而在springmvc5.x版本中则不是必须实现的。
关于这三个方法的执行顺序:
- preHandle方法在请求到控制器之前被执行,也就是预处理方法,该方法的返回值决定请求是否发送到控制器中,true是发送,类似于filter中的doFilter,false则是中断
- postHandle方法在控制器之后被执行,此时我们可以通过modelAndView参数对象对模型数据或对视图数据进行处理
- afterCompletion方法在整个请求处理完毕时执行,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源的清理
完成拦截器的编写后,在Spring配置文件中,装配这个拦截器:
<mvc:interceptors>
<bean class="org.zero01.test.TestInterceptor"/>
</mvc:interceptors>
然后编写控制器代码如下:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class TestController {
@RequestMapping("/test/test.do")
public String test(){
System.out.println("控制器--test方法被执行了");
return "index";
}
}
通过浏览器访问后,控制台打印结果如下:
TestInterceptor--拦截器的preHandle方法被执行了
控制器--test方法被执行了
TestInterceptor--拦截器的postHandle方法被执行了
TestInterceptor--拦截器的afterCompletion方法被执行了
注:拦截器是在DispatcherServlet之后的,如果DispatcherServlet报错的话,拦截器是不会被执行的。
以上是正常的流程,我们来看看中断的流程,把preHandle方法中的返回值改成false,如下:
...
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("TestInterceptor--拦截器的preHandle方法被执行了");
return false;
}
...
通过浏览器访问后,控制台打印结果如下:
TestInterceptor--拦截器的preHandle方法被执行了
从控制台的打印结果中可以看到,请求没有被发送到控制器上,而是在拦截器这里中断了。
springmvc里有个<mvc:mapping/>
标签,通过这个标签我们可以配置拦截器只拦截哪些路径下的请求:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/test/**"/>
<bean class="org.zero01.test.TestInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
如上配置,表示指定拦截器只拦截/test/
下的所有请求。如果是其他请求则不会触发拦截器。
除此之外,我们还可以通过<mvc:exclude-mapping/>
标签来指定哪个uri的请求不会被拦截器拦截,例如我们指定了拦截器拦截/test/
目录下的所有请求,但是我希望访问/test/test.do
的请求不被拦截器拦截,则可以使用这个标签进行配置,如下:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/test/**"/>
<mvc:exclude-mapping path="/test/test.do"/>
<bean class="org.zero01.test.TestInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
如上配置,表示访问/test/test.do
的请求不会触发拦截器。
原文地址:http://blog.51cto.com/zero01/2090702