SpringMVC-- 14 拦截器

Posted Moon&&Dragon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMVC-- 14 拦截器相关的知识,希望对你有一定的参考价值。

17 拦截器

在Servlet阶段学习过过滤器,那么这里的拦截器其实是和Servlet中的过滤器性质差不多,但是底层的实现是完全的不一样。

17.1 SpringMVC的拦截器

拦截器是SpringMVC框架中的一部分,它天然的在SpringIOC容器中运行着,它的底层其实和SpringAOP一样通过代理模式实现的,是SpringAOP的一个具体实现。而过滤器是J2EE的标准,是由不同的第三方容器厂商实现的,基于函数回调

作用:

  • 日志记录
  • 权限认证
  • 性能监控
  • 用户画像

17.1.1 拦截器和过滤器区别

需要注意的是拦截器是SpringMVC框架中的一部分,而过滤器是服务器中的,一个请求最先到达就是过滤器,然后就进入了SpringMVC的请求分发处理中心,在进行处理控制器前调用了前置方法,这就是属于拦截器的方法。

17.1.2 单个拦截器流程

在单个拦截器中,其实是有三个方法的,他们分别在不同的时间执行

拦截器方法说明执行时间
preHandle这个方法是拦截器中使用比较多,是前置拦截器,该拦截方法在执行在控制器之前,可以对整个的访问进行处理,如果返回false,则不会去继续寻找handler,直接返回空白。控制器之前
postHandle这个方法是属于后置拦截器,该方法无法对访问进行处理,不管如何都会继续。在控制器之后,目标资源已经被SpringMVC框架处理,也就是在HandlerAdapter之后,但是在渲染页面之前
afterCompletion这个方法也是属于后置拦截器,和上面的方法一样,但是执行的时间不一样在渲染页面之后(或者没有页面就是在json字符串被Jackson处理完之后)

流程图:

17.1.3 多个拦截器流程

如果我们去使用多个拦截器的话,那么多个拦截器之间的流程也是有有规律的,那么拦截器的执行顺序就是我们配置注册的顺序。

步骤:

  • 执行拦截器1的前置方法
  • 执行拦截器2的前置方法
  • 执行控制层
  • 处理后执行拦截器2的后置方法
  • 处理后执行拦截器1的后置方法
  • 渲染后执行拦截器2的后置完成方法
  • 渲染后执行拦截器1的后置完成方法

执行顺序:1–>2–>2–>1–>2–>1

流程图:

17.2 实现拦截器类

我们如果想要使用SpringMVC中拦截器,我们只需要新建一个类,然后去实现Spring为我们提供的接口即可,我们需要去实现HandlerInterceptor接口

Tips:

  • 我们实现完该接口后,可以选择实现全部三个方法,也可以选择实现其中一个,或者不实现,也没啥意义了
public class MyInterceptor implements HandlerInterceptor 
  /**
   * 前置处理器,拦截的是请求
   * @param request
   * @param response
   * @param handler
   * @return
   * @throws Exception
   */
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception 
    // 在这里我们可以操作请求和响应,不过现在响应啥也没有
    System.out.println("用户访问的uri:"+request.getRequestURI());
    System.out.println("用户的上网环境:"+request.getHeader("User-Agent"));
    System.out.println("用户的IP:"+request.getRemoteHost());
    // 这里如果返回了false,那么拦截到的请求不会继续往下执行,直接返回空白
    return true;
  

  /**
   * 在目标资源已经被SpringMVC框架处理之后(在HandlerAdapter之后,在渲染前)
   * @param request
   * @param response
   * @param handler
   * @param modelAndView
   * @throws Exception
   */
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception 
    // 在这里也可以操作请求和响应,而且还可以操作控制器返回的ModelAndView对象
    System.out.println(request.getRequestURI()+"被POST拦截了");
  

  /**
   * 在渲染完视图层后,产生响应文本之后(渲染页面之后或者json数据被Jackson处理之后)
   * @param request
   * @param response
   * @param handler
   * @param ex
   * @throws Exception
   */
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception 
    // 这里的拦截方法已经执行完了渲染
    System.out.println(request.getRequestURI()+"被after拦截了");
  


17.3 配置拦截器

在SpringMVC中配置拦截器,我们同样可以使用俩种方式进行配置

Tips:

  • 过滤器的配置我们是在web.xml或者Java初始化类,而拦截器的配置我们是在SpringMCV的配置文件或者SpringMVC配置类

17.3.1 基于XML

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

  <context:component-scan base-package="com.moon"/>
  <mvc:default-servlet-handler/>
  <mvc:annotation-driven/>
	<!--配置mvc拦截器-->
  <!--配置多个拦截器标签-->
  <mvc:interceptors>
    <!--配置单个拦截器-->
    <mvc:interceptor>
      <!--拦截所有-->
      <mvc:mapping path="/**"/>
      <!--使用内部bean的方式声明我们写的拦截器-->
      <bean class="com.moon.interceptor.MyInterceptor"/>
    </mvc:interceptor>
  </mvc:interceptors>

</beans>

17.3.2 基于JavaConfig

@EnableWebMvc
@Configurable
@ComponentScan("com.moon")
public class WebMvcConfig implements WebMvcConfigurer 
  /**
   * 处理静态资源
   * @param configurer 配置
   */
  @Override
  public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) 
    configurer.enable();
  

  /**
   * 添加拦截器
   * @param registry 配置
   */
  @Override
  public void addInterceptors(InterceptorRegistry registry) 
      // 添加一个拦截器,拦截全部的请求,如果添加做个,继续在registry中添加
      registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
  

17.4 资源过滤问题

在上面的配置中,我们拦截了所有的请求,那么js这些静态文件也是会被拦截的。这时候我们可能会想,上面不是配置静态资源处理了吗,怎么还会拦截,答案是会的

为什么会出现静态资源的拦截:

  • 在我们前面配置的静态资源放行,只是在DispatcherServlet寻找执行链时生效的
  • 而我们的拦截器是在我们执行链已经找到,准备执行执行链的时候,所以之前的静态资源放行是无效的

解决方案:

  • 这种请求显然Spring也是会想到的,在我们配置拦截器的时候,Spring为我们提供了不包括的资源方法

Tips:

  • 在配置拦截放行时,我们可以使用通配符来放行对应的后缀的文件,比如==*.js==
  • 如果有多个后缀的文件,那也不是很方便,所以我们一般选择放行对应文件夹下的所有,比如static/**

XML配置:

<mvc:interceptors>
  <mvc:interceptor>
    <!--拦截所有-->
    <mvc:mapping path="/**"/>
    
    <!--去除不需要拦截的url-->
    <!--放行js-->
    <mvc:exclude-mapping path="/**.js"/>
    <!--放行css-->
    <mvc:exclude-mapping path="/**.css"/>
    <!--放行图标-->
    <mvc:exclude-mapping path="/**.ico"/>
    <!--放行static下的全部文件-->
    <mvc:exclude-mapping path="/static/**"/>

    <bean class="com.moon.interceptor.MyInterceptor"/>
  </mvc:interceptor>
</mvc:interceptors>

Java类配置:

@Override
public void addInterceptors(InterceptorRegistry registry) 
  // 资源放行文件集合
  ArrayList<String> list = new ArrayList<>();
  list.add("/**.js");
  list.add("/**.css");
  list.add("/**.jpg");
  // 资源放行
  registry.addInterceptor(new FirstInterceptor())
    .addPathPatterns("/**")
    .excludePathPatterns("/static/**")
    .excludePathPatterns(list);

以上是关于SpringMVC-- 14 拦截器的主要内容,如果未能解决你的问题,请参考以下文章

SpringMVC-- 14 拦截器

SpringMVC-- 14 拦截器

springmvc 拦截器 拦截成功怎么返回登录页面

SpringMVC学习11SpringMVC中的拦截器

springmvc验证登录用过滤器还是拦截器

学习笔记——SpringMVC拦截器的两种装配方式;SpringMVC拦截器工作原理;SpringMVC中的异常处理器;SpringMVC工作原理