SpringMVC - 拦截器
SpringMVC提供了拦截器(HandlerInterceptor),
效果和JavaWeb的过滤器(Filter)很像:
允许在后端控制器方法运行之前进行拦截做其他工作,
或者在后端控制器方法运行之后进行一些其他处理。
1. 概述
SpringMVC的拦截器(HandlerInterceptor)是个接口,提供三个方法:
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
- void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception;
- void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception;
preHandle()方法:在后端控制器方法运行之前调用,
返回true的话就放行,相当于过滤器(Filter)的chain.doFilter()方法。
返回false的话就不放行;
postHandle()方法:在后端控制器方法运行之后调用;
afterCompletion()方法:响应请求之后调用。
2. 自定义拦截器
2.1 使用方式
我们可以实现SpringMVC提供的拦截器接口,
重写上面提到的三个方法来进行自定义功能。
2.2 配置自定义拦截器
applicationContext.xml:
<!-- 拦截器配置 -->
<mvc:interceptors>
<!-- 此方式配置的拦截器默认拦截所有请求 -->
<bean class="pers.dyj123.controller.interceptor.MyInterceptor"/>
<!-- 详细方式配置拦截器 -->
<mvc:interceptor>
<!-- 拦截哪些请求 -->
<mvc:mapping path="/handle1"/>
<!-- 使用哪个拦截器 -->
<bean class="pers.dyj123.controller.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
2.3 拦截流程
2.3.1 正常流程
后端控制器方法:
@RequestMapping("/handle")
public String handle() {
System.out.println("handle");
return "success";
}
拦截器:
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
前端代码:
<body>
<%System.out.println("success");%>
</body>
执行效果:
preHandle
handle
postHandle
success
afterCompletion
从执行效果可以看出正常流程是:
拦截器的preHandle方法执行 -> 控制器方法执行 ->
拦截器的postHandle方法执行 -> 来到页面 ->
拦截器的afterCompletion方法执行
2.3.2 拦截器不放行流程
后端控制器方法:
@RequestMapping("/handle")
public String handle() {
System.out.println("handle");
return "success";
}
拦截器:
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
前端代码:
<body>
<%System.out.println("success");%>
</body>
执行效果:
preHandle
从执行效果可以看出拦截器若不放行时只会执行preHandle方法。
2.3.3 控制器方法出现错误/异常
后端控制器方法:
@RequestMapping("/handle")
public String handle() {
System.out.println("handle");
int i = 1/0;
return "success";
}
拦截器:
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
前端代码:
<body>
<%System.out.println("success");%>
</body>
执行效果:
preHandle
handle
afterCompletion
从执行效果可以看出当控制器方法出现问题时,
拦截器的preHandle方法和最终的afterCompletion方法会执行。
总结可以得到:
只要拦截器不放行就只会执行preHandle方法,没有以后的流程;
只要拦截器放行,afterCompletion方法都会执行。
3. 多拦截器
3.1 概述
多拦截器的运行流程和单拦截器相似,但也有几个不同点:
- 拦截器遵循先用后出原则,先执行某个拦截器的preHandle方法,
则这个拦截器的postHandle方法和afterCompletion方法后执行; - 首个不放行的拦截器前的拦截器的afterCompletion方法都会执行;
- 配置拦截器时,谁在前面谁优先执行。
3.2 举个栗子
拦截器1:
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器1的preHandle方法");
// 拦截器1放行
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的afterCompletion方法");
}
}
拦截器2:
public class MyInterceptor2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器2的preHandle方法");
// 拦截器2不放行
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器2的postHandle方法");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("拦截器2的afterCompletion方法");
}
}
配置文件:
<mvc:interceptors>
<!-- 拦截器1在前 -->
<bean class="xxx.controller.interceptor.MyInterceptor"/>
<!-- 拦截器2在后 -->
<bean class="xxx.controller.interceptor.MyInterceptor2"/>
</mvc:interceptors>
执行结果:
拦截器1的preHandle方法
拦截器2的preHandle方法
拦截器1的afterCompletion方法
从执行结果可以看出首个不放行的拦截器前的拦截器的afterCompletion方法都会执行。