5、拦截器

SpringMVC的拦截器

SpringMVC的拦截器,类似于Servlet中的过滤器Filter,都是用来对处理器进行预处理和后处理。开发者可以通过拦截器自定义一些功能。区别在于过滤器可以过滤所有请求(动态请求,静态请求),但是拦截器只能拦截动态请求(用于控制层)

拦截器跟AOP一样,底层都是动态代理模式

拦截器常见的使用的场景

2种实现方式

实现HandlerInterceptor接口

org.springframework.web.servlet.HandlerInterceptor

实现HandlerInterceptor接口

public class ImpInterceptor implements HandlerInterceptor{
    /**
    * 收到请求后,在执行controller方法之前
    * return:true代表放行,fasle代表不需要放行
    * arg2:被拦截的控制器对象(当前的controller对象)
    */
    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        System.out.println("执行controller方法前执行,下一个责任链对象是:" + arg2);
        return true;
    }
    /**
    * controller方法执行完毕,响应之前
    * arg2:当前的控制器对象(controller对象)
    * arg3:当前执行的controller方法中的ModelAndView对象,可以获得要转发的地址和传递的参数
    */
    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)throws Exception {
        System.out.println("执行完controller方法后,响应之前执行,当前责任链对象是:" + arg2);
    }
    /**
    * 响应之后
    * arg2:当前的控制器对象(controller对象)
    * arg3:当前controller方法中发生的异常对象
    */
    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)throws Exception {
        System.out.println("执行完controller方法后,响应之后执行,当前责任链对象是:" + arg2 + ",当前的异常对象是:" + arg3);
    }
}

继承HandlerInterceptorAdapter(推荐)

org.springframework.web.servlet.handler.HandlerInterceptorAdapter

是HandlerInterceptor的实现类,所以,此方式,可以按照也无需求进行选择方法,不需要三个方法都写

继承HandlerInterceptorAdapter

public class ExetInterceptor extends HandlerInterceptorAdapter{
    /**
    * 收到请求后,在执行controller方法前执行该方法
    * return:true代表放行,执行下一个责任链对象的方法(controller方法),fasle代表不需要放行
    * arg2:下一个责任链对象(当前的controller对象)
    */
    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        System.out.println("执行controller方法前执行,下一个责任链对象是:" + arg2);
        return true;
    }
    /**
    * arg2:当前的责任链对象(controller对象)
    * arg3:当前执行的controller方法中的ModelAndView对象,可以获得要转发的地址和传递的参数
    */
    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)throws Exception {
        System.out.println("执行完controller方法后,响应之前执行,当前责任链对象是:" + arg2);
    }
    /**
    * arg2:当前的责任链对象(controller对象)
    * arg3:当前controller方法中发生的异常对象
    */
    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)throws Exception {
        System.out.println("执行完controller方法后,响应之后执行,当前责任链对象是:" + arg2 + ",当前的异常对象是:" + arg3);
    }
}

配置拦截器

基于配置文件

基于Spring核心配置文件,对拦截器进行配置

<!--配置拦截器-->
<mvc:interceptors>
    <!--拦截所有的请求-->
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="top.ygang.interceptor.ExetInterceptor1"/>
    </mvc:interceptor>
    <!--拦截sys下的所有请求-->
    <mvc:interceptor>
        <mvc:mapping path="/sys/*"/>
        <bean class="top.ygang.interceptor.ExetInterceptor2"/>
    </mvc:interceptor>
    <!--拦截sys/login单个请求-->
    <mvc:interceptor>
        <mvc:mapping path="/sys/login"/>
        <bean class="top.ygang.interceptor.ExetInterceptor3"/>
    </mvc:interceptor>
</mvc:interceptors>

当多个拦截器拦截同一个路径的时候,拦截顺序与配置文件中拦截器声明顺序保持一致

基于配置类

在不使用Spring配置文件的情况下,基于实现WebMvcConfigurer接口的addInterceptors方法对拦截器进行配置

@Configuration
@ComponentScan("top.ygang.sm_demo")
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new ExetInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login")
                .order(1);
    }
}

当多个拦截器拦截同一个路径的时候,拦截顺序与按照order()参数从小到大的允许进行排序拦截,order默认值为0

过滤器与拦截器的区别(面试题)

拦截器和过滤器同时使用的执行顺序:过滤前 - 拦截前 - Action处理 - 拦截后 - 过滤后

拦截器 过滤器
只能拦截动态请求(控制层的方法) 能过滤所有的请求
由Spring MVC框架提供 由servlet api提供
原理是动态代理模式,AOP的思想 原理是回调的机制
运行在Spring容器中 运行在Tomcat容器中

实现登录拦截

@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object o) throws Exception {
    HttpSession session = req.getSession();
    Object ob = session.getAttribute("nowLogin");
    String uri = req.getRequestURI();
    if(uri.endsWith("/login.do")){
        return true;
    }else{
        if(ob == null){
            return false;
        }else{
            return true;
        }
    }
}