SpringMVC(七)拦截器
SpringMVC(七)拦截器
当请求来到DispatcherServlet
时,它会根据HandlerMapping
的机制找到处理器,这样就返回一个HandlerExecutionChain
对象,这个对象包含处理器和拦截器。这里的拦截器会对处理器进行拦截,这样通过拦截器就可以增强处理器的功能。
拦截器的设计
所有拦截器都要实现HandlerInterceptor
接口。
HandlerInterceptor
源码
public interface HandlerInterceptor {
//处理器执行前方法
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
//处理器处理后方法
void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
//处理器完成后方法
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
}
拦截器流程
具体的流程如下
- 执行
preHandler
方法,该方法会返回一个布尔值。如果为false,就结束所有流程;如果为true,则执行下一步 - 执行处理器的逻辑,它包含控制器的功能
- 执行postHandler方法
- 执行视图解析和视图模型
- 执行
afterCompetion
方法
开发拦截器
通过实现HandlerInterceptor
接口来写一个简单的拦截器
MyInterceptor
package com.lay.mvc.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Description: 简单的拦截器
* @Author: lay
* @Date: Created in 14:07 2018/11/15
* @Modified By:IntelliJ IDEA
*/
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("处理器前方法");
//返回true,不会拦截后续的处理
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("处理完成方法");
}
}
这里重写了HandlerInterceptor
的三个拦截器方法,在中间打印了一些信息。
有了这个拦截器,spring mvc并不会发现它,它还需要进行注册才能够拦截处理器,为此需要在配置文件中实现WebMmcConfigurer
接口,并覆盖addInterceptors
方法进行注册拦截器。
InterceptorCofig 拦截器注册
package com.lay.mvc.config;
import com.lay.mvc.interceptor.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Description:拦截器配置
* @Author: lay
* @Date: Created in 14:18 2018/11/15
* @Modified By:IntelliJ IDEA
*/
@Configuration
public class InterceptorCofig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册拦截器到Spring MVC机制,然后它会返回一个拦截器注册
InterceptorRegistration ir = registry.addInterceptor(new MyInterceptor());
//指定拦截匹配模式,限制拦截器拦截请求
ir.addPathPatterns("/interceptor/*");
}
}
这里指定了拦截器的模式,所以它只会拦截与正则式"/interceptor/*"
匹配的请求。
接着创建一个用于测试的控制器
InterceptorController
package com.lay.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Description: 拦截器控制器
* @Author: lay
* @Date: Created in 14:23 2018/11/15
* @Modified By:IntelliJ IDEA
*/
@Controller
@RequestMapping("/interceptor")
public class InterceptorController {
@GetMapping("/start")
public String start(){
System.out.println("执行处理器逻辑");
return "/welcome";
}
}
这里写了处理器逻辑,并且返回一个视图
welcome.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<h1>welcome</h1>
</body>
</html>
控制台出如下
处理器前方法
执行处理器逻辑
处理后方法
处理完成方法
多个拦截器
注册顺序
registry.addInterceptor(new MyInterceptor1());
registry.addInterceptor(new MyInterceptor2());
registry.addInterceptor(new MyInterceptor3());
打印日志
【MyInterceptor1】处理器前方法
【MyInterceptor2】处理器前方法
【MyInterceptor3】处理器前方法
执行处理器逻辑
【MyInterceptor3】处理后方法
【MyInterceptor2】处理后方法
【MyInterceptor1】处理后方法
【MyInterceptor3】处理完成方法
【MyInterceptor2】处理完成方法
【MyInterceptor1】处理完成方法
可以看到多个拦截器同时作用的时候,遵循责任链式规则。对于处理器前方法采用先注册限制性,而处理器后方法和完成方法则是先注册后执行的规则。但这也只是测试了所有拦截器前方法都返回true
的场景。如果我们将MyInterceptor2
的前方法preHandler
返回值改为false
【MyInterceptor1】处理器前方法
【MyInterceptor2】处理器前方法
【MyInterceptor1】处理完成方法
从日志可以看出,处理器前方法会执行,但是一旦返回false,则后续的拦截器、处理器和所有的拦截器的处理器后方法都不会执行。完成方法afterCompletion
则不一样,它只会执行返回true
的拦截器的完成方法,而且顺序是先注册后执行。