概述
在开发一个网站时可能有这样的需求:某些页面只希望几个特定的用户浏览。对于这样的访问权限控制,应该如何实现呢?拦截器就可以实现上述需求。在 Struts 2 框架中,拦截器是其重要的组成部分,Spring MVC 框架也提供了拦截器功能。
Spring MVC 的拦截器(Interceptor)与 Java Servlet 的过滤器(Filter)类似,它主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。
- SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。
- 可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链 中的拦截器会按着定义的顺序执行。
- 拦截器和过滤器的功能比较类似,有区别
- 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
- 拦截器是SpringMVC框架独有的。
- 过滤器配置了/*,可以拦截任何资源。
- 拦截器只会对控制器中的方法进行拦截。
- 拦截器也是AOP思想的一种实现方式
- 想要自定义拦截器,需要实现HandlerInterceptor接口
自定义拦截器步骤
在 Spring MVC 框架中定义一个拦截器需要对拦截器进行定义和配置,定义一个拦截器可以通过两种方式:
一种是通过实现 HandlerInterceptor 接口或继承 HandlerInterceptor 接口的实现类来定义;
另一种是通过实现 WebRequestInterceptor 接口或继承 WebRequestInterceptor 接口的实现类来定义。
这里以实现 HandlerInterceptor 接口的定义方式为例自定义拦截器的使用方法
第一个拦截器
//实现HandlerInterceptor接口
public class MyInterceptor implements HandlerInterceptor {
/**
* Controller方法执行前,进行拦截的方法
* return true放行
* return false拦截
* 可以使用转发或者重定向直接跳转到指定的页面
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("MyInterceptor:preHandle方法在controller方法执行前执行");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor:postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("MyInterceptor:afterCompletion方法在控制器的处理请求放发执行完成后执行,即视图渲染结束之后执行");
}
}
第二个拦截器
//实现HandlerInterceptor接口
public class MyInterceptor2 implements HandlerInterceptor {
/**
* Controller方法执行前,进行拦截的方法
* return true放行
* return false拦截
* 可以使用转发或者重定向直接跳转到指定的页面
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("MyInterceptor2:preHandle方法在controller方法执行前执行");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor2:postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("MyInterceptor2:afterCompletion方法在控制器的处理请求放发执行完成后执行,即视图渲染结束之后执行");
}
}
在上述拦截器的定义中实现了 HandlerInterceptor 接口,并实现了接口中的 3 个方法。有关这 3 个方法的描述如下。
- preHandle 方法:该方法在控制器的处理请求方法前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作。
- postHandle 方法:该方法在控制器的处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步的修改。
- afterCompletion 方法:该方法在控制器的处理请求方法执行完成后执行,即视图渲染结束后执行,可以通过此方法实现一些资源清理、记录日志信息等工作。
在springmvc.xml中配置拦截器
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 全局拦截器,拦截所有请求 -->
<!-- <bean class="com.woniu.interceptor.MyInterceptor"/> -->
<!-- 指定路径拦截器 -->
<mvc:interceptor>
<!-- 配置拦截器作用的路径 -->
<mvc:mapping path="/**"/>
<!-- 配置不需要拦截的路径 -->
<mvc:exclude-mapping path=""/>
<!-- 注册拦截器对象 -->
<bean class="com.woniu.interceptor.MyInterceptor" />
</mvc:interceptor>
<!-- 配置多个拦截器,在编写一个MyInterceptor2拦截器的类 -->
<mvc:interceptor>
<!-- 配置拦截器作用的路径 -->
<mvc:mapping path="/demo01.do"/>
<!-- 注册拦截器对象 -->
<bean class="com.woniu.interceptor.MyInterceptor2" />
</mvc:interceptor>
</mvc:interceptors>
在以上示例代码中
<mvc:interceptors> 元素用于配置一组拦截器,其子元素 定义的是全局拦截器,即拦截所有的请求。
<mvc:interceptor> 元素中定义的是指定路径的拦截器,其子元素 <mvc:mapping> 用于配置拦截器作用的路径,该路径在其属性 path 中定义。
如上述示例代码中,path 的属性值“/**”表示拦截所有路径,“/demo01.do”表示拦截所有以“/demo01.do”结尾的路径。如果在请求路径中包含不需要拦截的内容,可以通过 <mvc:exclude-mapping> 子元素进行配置。
需要注意的是,<mvc:interceptor> 元素的子元素必须按照 <mvc:mapping…/>、<mvc:exclude-mapping…/>、<bean…/> 的顺序配置。
单个拦截器执行流程
都为true运行结果:
MyInterceptor:preHandle方法在controller方法执行前执行
rebody:sid=1&sname=zhangsan
MyInterceptor:postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行
MyInterceptor:afterCompletion方法在控制器的处理请求放发执行完成后执行,即视图渲染结束之后执行
多个拦截器的执行流程
都为true运行结果:
MyInterceptor:preHandle方法在controller方法执行前执行
MyInterceptor2:preHandle方法在controller方法执行前执行
rebody:sid=1&sname=zhangsan
MyInterceptor2:postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行
MyInterceptor:postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行
MyInterceptor2:afterCompletion方法在控制器的处理请求放发执行完成后执行,即视图渲染结束之后执行
MyInterceptor:afterCompletion方法在控制器的处理请求放发执行完成后执行,即视图渲染结束之后执行
总结:
1、从preHandle到postHandle是一个完整的执行链,preHandle在执行的时候有一个为false,后面的都不会执行
2、afterCompletion:任意一个拦截器的preHandle方法返回true,afterCompletion方法会压栈,对应的afterCompletion方法最后会执行
3、拦截器不会拦截页面,只拦截处理器方法,Servlet的Filter过滤器会拦截页面