Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。 将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(InterceptorChain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。
过滤器器可以拦截抱任何请求信息,包括静态的资源也可以拦截, 而拦截器只可以对controller中的请求方法进行拦截,不可以拦截静态资源
①创建拦截器类实现HandlerInterceptor接口 ②配置拦截器 ③测试拦截器的拦截效果
1) Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter 适配器类
① preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。
如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false。
② postHandle():这个方法在业务处理器处理完请求后,但是DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求request进行处理。
③ afterCompletion():这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
编写拦截器:
/** * 手动实现拦截器必须实现HandlerInterceptor接口和它的方法 */ public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("我是拦截器的目标执行方法前的"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("我是拦截器目标方法执行后,视图返回前的"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("拦截器的最后方法,我在所有的方法都执行完后执行"); } }
配置:在SpringMVC的配置文件中配置
然后去springMvc.xml中配置你的拦截器
<!-- 配置拦截器--> <!-- 将mvc的命名空间导入后配置拦截器--> <mvc:annotation-driven /> <mvc:interceptors> <mvc:interceptor> <!-- 对那些资源进行操作--> <mvc:mapping path="/**"/> <bean class="com.springMvc.Interceptor.MyInterceptor"/><!--指定你的拦截器的具体是谁--> </mvc:interceptor> </mvc:interceptors>
编写测试程序测试:
编写Controller,发请求到controller,跳转页面
@RequestMapping("/test") @Controller public class TargetControlle { @RequestMapping("/target") public ModelAndView target(ModelAndView modelAndView){ System.out.println("目标资源执行....."); modelAndView.addObject("name","目标资源"); modelAndView.setViewName("target"); return modelAndView; } }
切忌在编写拦截器的时候一定要仔细查看手动实现的拦截器重写的preHandle方法是不是return true只有返回的true才可以进行下面的流程的执行
多个拦截器的使用:
其实可以理解为python的装饰器,层层执行,从上到下依次执行的,
比如有拦截器1和拦截器2就是拦截器1将拦截器2和目标方法包裹住了
请求的流程图如下:(从上到下依次执行)
定义拦截器1
MyInterceptor
/** * 手动实现拦截器必须实现HandlerInterceptor接口和它的方法 */ public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("我是拦截器1的目标执行方法前的preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("我是拦截器1的postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("拦截器1的最后方法"); } } Interceptor
定义拦截器2:
public class MyInterceptorTwo implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("我是拦截器2的preHandle方法,我应该在目标方法执行前和拦截器1的preHandle方法后执行"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("我是拦截器2的postHandle方法,我应该在目标资源执行后和方法1的postHandle方法执行前"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("我是拦截器2的afterCompletion方法我在目标方法执行后,拦截器1的postHandle方法后执行"); } } MyInterceptorTwo
在springMvc.xml中配置拦截器(拦截器的先后执行就是在此处配置的)
<!-- 配置拦截器--> <!-- 将mvc的命名空间导入后配置拦截器--> <mvc:annotation-driven /> <mvc:interceptors> <mvc:interceptor> <!-- 对那些资源进行操作--> <mvc:mapping path="/**"/> <bean class="com.springMvc.Interceptor.MyInterceptor"/><!--指定你的拦截器的具体位置--> </mvc:interceptor> </mvc:interceptors> <!-- 配置拦截器2--> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.springMvc.Interceptor.MyInterceptorTwo"/> </mvc:interceptor> </mvc:interceptors>
目标方法
@RequestMapping("/test") @Controller public class TargetControlle { @RequestMapping("/target") public ModelAndView target(ModelAndView modelAndView){ System.out.println("目标资源执行....."); modelAndView.addObject("name","目标资源"); modelAndView.setViewName("target"); return modelAndView; } }
执行的结果为;
我是拦截器1的目标执行方法前的preHandle 我是拦截器2的preHandle方法,我应该在目标方法执行前和拦截器1的preHandle方法后执行 目标资源执行..... 我是拦截器2的postHandle方法,我应该在目标资源执行后和方法1的postHandle方法执行前 我是拦截器1的postHandle 我是拦截器2的afterCompletion方法我在目标方法执行后,拦截器1的postHandle方法后执行 拦截器1的最后方法
我们可以利用拦截器的方法来进行方法的判断和资源信息展示的更改:
拦截器1:来进行携带参数和跳转界面的判断
/** * 手动实现拦截器必须实现HandlerInterceptor接口和它的方法 */ public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("我是拦截器1的目标执行方法前的preHandle"); String param = request.getParameter("username"); if("laowang".equals(param)){ // 判断是否携带参数username,它的值是laowang return true; // 返回true代表放行 }else { request.getRequestDispatcher("/WEB-INF/views/error.jsp").forward(request,response); return false; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("我是拦截器1的postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("拦截器1的最后方法"); } }
拦截器2:利用postHandle来更改界面返回的参数
public class MyInterceptorTwo implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("我是拦截器2的preHandle方法,我应该在目标方法执行前和拦截器1的preHandle方法后执行"); return true; //返回true代表放行,返回false代表不放行 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { modelAndView.addObject("name","我是拦截器2修改后的参数"); System.out.println("我是拦截器2的postHandle方法,我应该在目标资源执行后和方法1的postHandle方法执行前"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("我是拦截器2的afterCompletion方法我在目标方法执行后,拦截器1的postHandle方法后执行"); } }
拦截器的配置
<!-- 配置拦截器--> <!-- 将mvc的命名空间导入后配置拦截器--> <mvc:annotation-driven /> <mvc:interceptors> <mvc:interceptor> <!-- 对那些资源进行操作--> <mvc:mapping path="/**"/> <bean class="com.springMvc.Interceptor.MyInterceptor"/><!--指定你的拦截器的具体位置--> </mvc:interceptor> </mvc:interceptors> <!-- 配置拦截器2--> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.springMvc.Interceptor.MyInterceptorTwo"/> </mvc:interceptor> </mvc:interceptors>
结论:
当拦截器的preHandle方法返回true则会执行目标资源,如果返回false则不执行目标资源 多个拦截器情况下,配置在前的先执行,配置在后的后执行 拦截器中的方法执行顺序是:preHandler-------目标资源----postHandle---- afterCompletion