拦截器,通俗来来将,就是我们将访问某个路径的请求给拦截下来,然后可以对这个请求做一些操作
基本使用
创建拦截器类
让类实现HandlerInterceptor接口,重写接口中的三个方法。
@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {
@Override
//原始方法调用前执行的内容
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle...");
// true 放行,false 拦截
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...");
}
}
配置拦截器类
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;
// 这个方法是用来配置静态资源的,比如html,js,css等等
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
}
// 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
@Override
protected void addInterceptors(InterceptorRegistry registry) {
//配置拦截器
registry.addInterceptor(projectInterceptor).addPathPatterns("/books" );
//配置不拦截路径 .excludePathPatterns("/login");
}
}
这里ProjectInterceptor拦截器也可以不注入,直接new一个该类
我们可以看到拦截器HandlerInterceptor的使用方法:
- 首先编写拦截器HandlerInterceptor,来写出拦截后要执行的逻辑
- 然后编写拦截器配置类,来 **注册拦截器 **,使之生效,并且可以配置需要 拦截的路径
三种拦截方式
- 前置处理方法 - preHandle - 进入controller方法之前
- 后置处理方法 - postHandle - 方法内部处理完成,页面渲染之前
- 完成处理方法 - afterCompletion - 方法内部处理完成,页面渲染之前
这三个方法中,最常用的是 **preHandle **, 在这个方法中可以通过返回值来决定是否要进行放行,我们可以把业务逻辑放在该方法中,如果满足业务则返回true放行,不满足则返回false拦截。
接下来我们来具体看一下这三种拦截方式对应的函数
拦截器参数
前置处理方法
原始方法之前运行preHandle
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
- request: 请求对象。使用request对象可以获取请求数据中的内容,如获取请求头的
Content-Type
- response: 响应对象
- handler: 被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装。使用handler参数,可以获取方法的相关信息(和反射中的class类一样)
后置处理方法
原始方法运行后运行,如果原始方法被拦截,则不执行
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
前三个参数和上面的是一致的。
modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整
因为咱们现在都是返回json数据,所以该参数的使用率不高。
完成处理方法
拦截器最后执行的方法,无论原始方法是否执行
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
System.out.println("afterCompletion");
}
前三个参数与上面的是一致的。
ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理
因为我们现在已经有全局异常处理器类,所以该参数的使用率也不高。
多个拦截器
写法
配置类和之前一样,只不过多注册了拦截器
@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {
@Autowired
private ProjectInterceptor projectInterceptor;
@Autowired
private ProjectInterceptor2 projectInterceptor2;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//配置多拦截器
registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");
}
}
执行顺序
拦截器执行的顺序是和配置顺序有关。就和前面所提到的运维人员进入机房的案例,先进后出。
- 当配置多个拦截器时,形成拦截器链
- 拦截器链的运行顺序参照拦截器添加顺序为准
- 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
- 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作
preHandle:与配置顺序相同,必定运行
postHandle:与配置顺序相反,可能不运行
afterCompletion:与配置顺序相反,可能不运行。
这个顺序不太好记,最终只需要把握住一个原则即可:以最终的运行结果为准
拦截器与过滤器
两者的区别
- 过滤器基于函数回调、拦截器基于反射;
- 过滤器几乎对所有请求起作用,拦截器只对目标执行方法起作用;
- 过滤器对请求进行预处理、再交给Servlet处理并且生成响应,最后Filter再对服务器响应进行后处理;拦截器可以在方法执行前调用(preHandle),方法执行后调用(postHandle),视图页面渲染后调用(afterCompletion)
如果大家有什么思考和问题,可以在评论区讨论,也可以私信我,很乐意为大家效劳。
好啦,今天的每日一题到这里就结束了,如果大家觉得有用,可以可以给我一个小小的赞呢,我们下期再见!