当前位置 博文首页 > blackball1998的博客:添加拦截器
当我们需要在所有的请求处理之前,先做一些预处理,或者在请求处理之后做一些后续处理,或者在处理执行流程中如果有异常则执行一段出错逻辑,这时候我们可以使用Spring MVC的拦截器功能
事实上这个功能很常用,他的逻辑类似Spring的AOP,在所有的请求处理逻辑之上增加一些增强逻辑
首先创建一个拦截器类,并实现HandlerInterceptor
接口
public class MyInterceptor implements HandlerInterceptor {
}
实现了这个接口之后,我们可以看到可以重写三个方法
这三个方法都有默认实现,我们想要实现什么拦截效果,就重写对应的方法即可,首先介绍preHandle
方法
preHandle
方法是在请求处理方法之前执行的,他有一个布尔类型的返回参数,返回true则表示放行该请求,返回false则拦截该请求,我们常使用这个功能来做简单的鉴权功能
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("执行前置处理方法");
System.out.println(request.getRequestURI());
return true;
}
}
参数列表中的HttpServletRequest
类可以帮助获取到被拦截的请求的请求信息,用于定制拦截逻辑
当我们返回false值时,拦截器拦截该请求,这个时候浏览器会得到一个空白页面,这个时候可以用参数列表中的HttpServletResponse
类来设置页面转发或重定向到登录页面或者初始页面
创建完拦截器之后,我们需要在Spring MVC配置类中添加这个拦截器,这样拦截器才能生效
重写WebMvcConfigurer
接口中的addInterceptors
方法来注册拦截器,然后用addPathPatterns
方法来绑定需要拦截的请求,如果需要拦截所有的请求,可以使用/**
来表示
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
}
}
编写一个请求方法来测试拦截结果
@RestController
public class MyController {
@RequestMapping("/test")
public String test() {
System.out.println("执行请求处理方法");
return "SUCCESS";
}
}
测试结果如下,执行了拦截器中的preHandle
方法,也获取到了拦截到的uri
在绑定拦截的请求时,使用/**
来拦截所有请求,但是其中有某些请求我们又不想拦截时,可以使用excludePathPatterns
方法来过滤拦截请求,这种情况最常见的场景就是过滤静态资源请求,或者过滤登录页的请求
假如我有一张静态资源图片,而静态资源请求,一般是不需要拦截的
这时候可以先给静态资源的访问路径先加上一个请求前缀
spring:
mvc:
static-path-pattern: /static/**
这时候访问静态资源需要加上/static
这个前缀
然后在配置拦截器的时候过滤/static/**
请求就行了
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/static/**");
}
}
除了preHandle
方法,HandlerInterceptor
接口还有另外两个方法
postHandle
方法用于在请求方法执行结束后执行一段逻辑,afterCompletion
方法用于在视图渲染完成后执行一段逻辑
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方法");
}
}
发送一个测试请求
可以发现他们的执行先后顺序是
preHandle
方法postHandle
方法afterCompletion
方法当执行过程出现异常时,无论是preHandle
方法,请求处理方法,还是postHandle
方法出现了异常,都会触发afterCompletion
方法,并且可以通过afterCompletion
方法参数列表中的Exception
类来获取异常信息
public class MyInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("执行afterCompletion方法");
System.out.println(ex.getMessage());
}
}
我们在请求处理方法中模拟一个异常,测试结果
@RestController
public class MyController {
@RequestMapping("/test")
public String test() {
System.out.println("执行请求处理方法");
throw new RuntimeException("模拟异常");
}
}
可以看到在发生异常时,会触发afterCompletion
方法,并且可以获取到异常的信息
当有多个拦截器时,执行顺序如下图
preHandle
方法preHandle
方法返回true,执行下一个preHandle
方法preHandle
方法返回false,倒序执行所有已经执行过的拦截器的afterCompletion
方法preHandle
方法返回true,执行请求处理方法,否则不执行postHandle
方法afterCompletion
方法afterCompletion
方法