本节课对SpringBoot2.0以及之前版本的拦截器进行讲解
在SpringBoot1.x的版本中实现拦截器,首先写一个自定义拦截器实现addInterceptors接口,实现其三个方法:
package com.qzsun.springbootdemo.intecpter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class LoginIntercepter implements HandlerInterceptor{
/**
* 进入controller方法之前
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("LoginIntercepter------->preHandle");
// String token = request.getParameter("access_token");
//
// response.getWriter().print("fail");
return HandlerInterceptor.super.preHandle(request, response, handler);
}
/**
* 调用完controller之后,视图渲染之前
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("LoginIntercepter------->postHandle");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
/**
* 整个完成之后,通常用于资源清理
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("LoginIntercepter------->afterCompletion");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
然后写一个配置类继承WebMvcConfigurerAdapter,然后重写其addInterceptors()方法,并将刚刚写的拦截器注册进去,并加上拦截规则:
package com.qzsun.springbootdemo.intecpter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @author sunqizheng
* @Title: CustomOldWebMvcConfigurer
* @ProjectName springbootdemo
* @Description: 2.0版本之前拦截器,方法过时了
* @date 2019/1/3113:34
*/
//@Configuration
public class CustomOldWebMvcConfigurer extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/api/");
super.addInterceptors(registry);
}
}
但是该写法在2.0版本中已经过时了,我们点进源码查看发现其已被@Deprecated掉了,原因在源码的注释上已经写清楚了:
@deprecated从Spring5.0开始{@link WebMvcConfigurer}具有默认方法(由Java 8基线实现),可以直接实现而无需此适配器
下面我们进行新版本拦截器的实现,第一步也是写一个自定义拦截器,就沿用刚刚写的拦截器,然后写一个配置类实现WebMvcConfigurer接口,重写addInterceptors()方法,注意加上注解@Configuration纳入容器管理,然后在里面注册之前写好的LoginIntercepter,然后加上拦截路径,注意:如果是拦截所有的话就是":
/**
* @author sunqizheng
* @Title: CustomWebMvcConfigurer
* @ProjectName springbootdemo
* @Description: 拦截器配置,类似于以前mvc项目的Spring配置文件中配置拦截器
* @date 2019/1/3113:57
*/
@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//拦截器最后路径一定要 “/**”, 如果是目录的话则是 /*/
//如果是拦截所有的话就是"/**"
registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/api/*/**");
WebMvcConfigurer.super.addInterceptors(registry);
}
}
然后在controller中加一个接口供测试使用:
@RequestMapping("/api/test/intercepter")
public String intercepter(){
System.out.println("--------测试拦截器-----");
return "index";
}
启动并访问http://localhost:8081/api/test/intercepter
拦截器起作用了, preHandle()在进入controller方法之前调用,postHandle()在调用完controller之后,视图渲染之前调用
,afterCompletion()在整个请求完成之后,通常用于资源清理
如果是两个拦截器,他们的顺序是先定义的先拦截,下面我们再自定义一个拦截器,并注册到配置类中:
package com.qzsun.springbootdemo.intecpter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class TwoIntercepter implements HandlerInterceptor{
/**
* 进入对应的controller方法之前
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("TwoIntercepter------>preHandle");
return HandlerInterceptor.super.preHandle(request, response, handler);
}
/**
* controller处理之后,返回对应的视图之前
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("TwoIntercepter------>postHandle");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
/**
* 整个请求结束后调用,视图渲染后,主要用于资源的清理
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("TwoIntercepter------>afterCompletion");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//拦截器最后路径一定要 “/**”, 如果是目录的话则是 /*/
//如果是拦截所有的话就是"/**"
registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/api/*/**");
registry.addInterceptor(new TwoIntercepter()).addPathPatterns("/api/*/**");
WebMvcConfigurer.super.addInterceptors(registry);
}
}
启动运行,我们发现果真是先定义的先执行,但是在执行完handle方法之后就是先定义的后执行了,就像两个同心圆,handle方法在最里面,外面一层是拦截器2,最外面一层是拦截器1。
补充:我们可以使用.excludePathPatterns()方法排除掉不需要拦截的路径:
Filter与Intercepter的区别:
Filter
是基于函数回调 doFilter(),而Interceptor则是基于AOP思想
Filter在只在Servlet前后起作用,而Interceptor够深入到方法前后、异常抛出前后等
依赖于Servlet容器即web应用中,而Interceptor不依赖于Servlet容器所以可以运行在多种环境。
在接口调用的生命周期里,Interceptor可以被多次调用,而Filter只能在容器初始化时调用一次。
Filter和Interceptor的执行顺序
过滤前->拦截前->action执行->拦截后->过滤后
源码地址:https://gitee.com/xuxinsunqizheng/SpringBoot2.0.git