1、拦截器概述
1.1 什么是拦截器?
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),但是比过滤器的功能更加强大,它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。要使用Spring MVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义: 1. 通过实现HandlerInterceptor接口,或继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来定义。 2. 通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。

2、自定义拦截器
以实现HandlerInterceptor接口方式为例,自定义拦截器类的代码如下:
package com.xust.iot.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyFirstInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("1.执行目标方法之前......");
//返回true表示放行,可以去执行目标方法,否者表示不允许执行目标方法
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("3.执行目标方法之后......");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("5.来到页面之后......");
}
}
上述代码中,自定义拦截器实现了HandlerInterceptor接口,并实现了接口中的三个方法:
- preHandle():在目标方法执行之前回执行,有个boolean类型的返回值,当返回true表示放行,即允许执行目标方法;当返回false,表示不放行,即不运行执行目标方法,此时会中断以后的所有过程
- postHandle():在目标方法执行结束后会执行,且解析视图之前执行
- afterCompletion():在请求到达页面,即视图渲染完成后执行
开发拦截器就像开发servlet或者filter一样,都需要在配置文件进行配置,配置代码如下:
<!--拦截器-->
<mvc:interceptors>
<!--这样配置的拦截器默认拦截所有请求-->
<bean id="myInterceptor" class="com.xust.iot.interceptor.MyFirstInterceptor"/>
</mvc:interceptors>
上面的代码中,<mvc:interceptors>
元素用于配置一组拦截器,子元素<bean>
中定义的是全局拦截器,它会拦截所有的请求;而也可以使用<mvc:interceptor>
元素中定义指定路径的拦截器,它会对指定路径下的请求生效。<mvc:interceptor>
元素的子元素<mvc:mapping>
用于配置拦截器作用的路径,该路径在其属性path 中定义。如果在请求路径中包含不需要拦截的内容,还可以通过<mvc:exclude-mapping>
元素进行配置。 注意:<mvc:interceptor>
中的子元素必须按照上述代码中的配置顺序进行编写,即<mvc:mapping> <mvc:exclude-mapping> <bean>
,否则文件会报错。
下面写一个控制器来测试一下正常情况下单个拦截器的工作流程:
package com.xust.iot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IntercrtorTestController {
@RequestMapping(value = "/test01")
public String handler01(Model model){
System.out.println("2.执行了目标方法......");
model.addAttribute("msg","你好啊!!!");
return "success";
}
}
目标页面success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>成功</title>
</head>
<body>
<%
System.out.println("4.来到了success.jsp页面");
%>
${msg}
</body>
</html>
测试结果

2.1 单个拦截器正常情况下的工作流程:
- 拦截器preHandle方法执行,返回true继续以后的过程
- 控制器目标方法执行
- 拦截器postHandle方法执行
- 页面渲染完成来到页面
- 拦截器afterCompletion方法执行

单个拦截器非正常情况下的工作流程: 单个拦截器的非正常情况分为两种情况: 1、拦截器中的preHandler方法返回false; 2、虽然preHandler方法返回了true,但是其中有一个过程“炸了”,比如发生了异常没有处理 接下来通过代码来测试: - 第一种情况:preHandler返回false
package com.xust.iot.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyFirstInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("1.执行目标方法之前......");
//返回true表示放行,可以去执行目标方法,否者表示不允许执行目标方法
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("3.执行目标方法之后......");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("5.来到页面之后......");
}
}
测试结果:

- 第二种情况:preHandle方法放行了,但是有一个过程“炸了”,比如我们在控制器目标方法中制造一个异常:
package com.xust.iot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IntercrtorTestController {
@RequestMapping(value = "/test01")
public String handler01(Model model){
int i=30/0;
System.out.println("2.执行了目标方法......");
model.addAttribute("msg","你好啊!!!");
return "success";
}
}
测试结果:



- 多个拦截器是有执行的先后顺序的,这个顺序就是定义的先后顺序
- 拦截器的preHandle方法:按照定义顺序顺序执行的
- 拦截器的postHandle方法:按照定义顺序逆序执行的
- 拦截器的preHandle方法:按照定义顺序顺逆序执行的



- 当preHandler返回了true,但是中间过程发生异常,会直接结束以后的流程但是afterCompetion总会执行
3.2 多个拦截器的执行顺序
- 正常情况

- 有拦截器返回false
