Sping mvc使用拦截器和Spring boot使用拦截器区别

1前言

最近在温习spring全家桶的时候,突然想起来之前面试的时候,遇到过一个面试官问了一个问题,具体问题不记得的了,就是拦截器方面的,当时没有回答上来,实际工作上也没有接触过,但是使用频率很高,最近有空就学习了一下。

2 拦截器

2.1 概念

Java 里的拦截器是动态拦截action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。在 AOP(Aspect-Oriented Programming,面向切面编程)中拦截器用于在某个方法(包括构造器)或字段被访问之前进行拦截,然后在之前或之后加入某些操作。特别地,现阶段 Spring 自身仅支持基于方法的拦截操作!如果基于方法的拦截操作不能满足需求,可以使用 AspectJ 与 Spring 进行集成,以实现更细粒度或更多方面的拦截操作。

2.2 原理

拦截器Interceptor的拦截功能是基于 Java 的动态代理来实现的,具体可以参考博文「用 Java 实现拦截器 Interceptor 的拦截功能 」,也可以通过阅读 Spring 源代码来了解更为权威的实现细节。

3 实现方法

在 Spring 框架之中,我们要想实现拦截器的功能,主要通过两种途径,第一种是实现HandlerInterceptor接口,第二种是实现WebRequestInterceptor接口。接下来,我们分别详细的介绍两者的实现方法。

3.1 HandlerInterceptor 接口

HandlerInterceptor接口中,定义了 3 个方法,分别为preHandle()、postHandle()和afterCompletion(),我们就是通过复写这 3 个方法来对用户的请求进行拦截处理的。因此,我们可以通过直接实现HandlerInterceptor接口来实现拦截器的功能。不过在 Spring 框架之中,其还提供了另外一个接口和一个抽象类,实现了对HandlerInterceptor接口的功能扩展,分别为:AsyncHandlerInterceptor和HandlerInterceptorAdapter.

在实际应用中,我们一般都是通过实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter抽象类,复写preHandle()、postHandle()和afterCompletion()这 3 个方法来对用户的请求进行拦截处理的。下面,我们就详细介绍这个 3 个方法。

preHandle(HttpServletRequest request, HttpServletResponse response, Object handle)方法,该方法在请求处理之前进行调用。Spring MVC 中的Interceptor是链式调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor。每个Interceptor的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor中的preHandle方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求做一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔(Boolean)类型的,当它返回为false时,表示请求结束,后续的Interceptor和控制器(Controller)都不会再执行;当返回值为true时,就会继续调用下一个Interceptor的preHandle方法,如果已经是最后一个Interceptor的时候,就会是调用当前请求的控制器中的方法。 postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)方法,通过preHandle方法的解释,我们知道这个方法包括后面要说到的afterCompletion方法都只能在当前所属的Interceptor的preHandle方法的返回值为true的时候,才能被调用。postHandle方法在当前请求进行处理之后,也就是在控制器中的方法调用之后执行,但是它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对控制器处理之后的ModelAndView对象进行操作。postHandle方法被调用的方向跟preHandle是相反的,也就是说,先声明的Interceptor的postHandle方法反而会后执行。 afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)方法,也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。因此,该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行,这个方法的主要作用是用于进行资源清理,记录日志的工作。

具体实现代码:

3.spring MVC中实现拦截器功能

3.1实现HandlerInterceptor 接口

package com.ali.interceptor;
​
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
​
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
​
public class Myinterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("执行Myinterceptor拦截器之preHandle方法");
        return true;
    }
​
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("执行Myinterceptor拦截器之postHandle方法");
    }
​
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("执行Myinterceptor拦截器之afterCompletion方法");
    }
}

3.2在springMVC配置文件中配置相应的bean

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/test3"/> //这个是指定拦截器只能拦截指定路径的处理器/test4是在controller层方法中@RequestMapping中的路径,如果这个路径不配置的话就会全局路径拦截
        <bean class="com.ali.interceptor.Myinterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

3.3书写controller层

@RequestMapping("/test3")
public String test3(HttpServletRequest httpServletRequest, ModelMap map){
​
​
    // httpServletRequest.setAttribute("msg","test2");
    map.put("msg","test3");
    System.out.println("执行控制层方法");
    return "/hello.jsp";
}

在浏览器在访问http://localhost:8080/test3的时候的工作台执行结果:

执行Myinterceptor拦截器之preHandle方法
执行控制层方法
执行Myinterceptor拦截器之postHandle方法
执行Myinterceptor拦截器之afterCompletion方法

4.在springBoot中使用拦截器

4.1实现HandlerInterceptor接口

在项目中和控制层相同的路径创建包interceptor包,创建自己的拦截器

package com.qli.interceptor;
​
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
​
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class Myinterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("执行Myinterceptor拦截器之preHandle方法");
        return true;
    }
​
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("执行Myinterceptor拦截器之postHandle方法");
    }
​
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("执行Myinterceptor拦截器之afterCompletion方法");
    }
}

4.2创建配置类

配置类只要是用来指定拦截器拦截的路径是哪些,需要实现WebMvcConfigurer接口,然后重写addInterceptors来实现指定路径的任务

package com.qli.interceptor;
​
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
​
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer{
    @Autowired
    Myinterceptor interceptor;
​
//注册拦截器类,添加黑名单(addPathPatterns("/**")),‘/*’只拦截一个层级,'/**'拦截全部
        // 和白名单(excludePathPatterns("List类型参数")),将不必拦截的路径添加到List列表中
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(new LoginHandlerInterceptor()) // 添加拦截器
                .addPathPatterns("/test1") // 拦截/test1路径的请求,如果还有其他路径的话,可以链式addPathPatterns("路径"),这里的路径和SpringMVC的路径要求一样
                .excludePathPatterns("/login") // 对应的不拦截的请求
                .excludePathPatterns("/download").excludePathPatterns("/assets/**");
    }
}

4.3控制层实现

@RequestMapping("/test1")
public String test1(){
    System.out.println("执行控制层方法");
    return "hello SpringBoot";
}

执行结果:

执行Myinterceptor拦截器之preHandle方法
执行控制层方法
执行Myinterceptor拦截器之postHandle方法
执行Myinterceptor拦截器之afterCompletion方法

单个拦截器的执行流程

 

多个拦截器执行流程:

 

也就是多个拦截器的时候出了preHandle是按照拦截器配置顺序执行,postHandle和afterCompletion都是按照拦截器配置顺序的反向执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值