拦截器详解

网络上关于Interceptor的文章,但感觉内容都大同小异,而且知识点零零散散,不太方便阅读。因此,整理一篇关于拦截器的文章,在此分享给大家,以供大家参考阅读。

1.概念

  java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前进行拦截,然后再之前或者之后加入某些操作。

       谈到拦截器,还有一个词大家应该知道——拦截器链(Interceptor Chain,在Struts 2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

2.拦截器的原理
      大部分时候,拦截器方法都是通过代理的方式来调用的。是基于反射实现的,Struts2的拦截器实现相对简单。当请求到达Struts2的ServletDispatcher时,Struts2会查找配置文件,并根据配置实例化相对的拦截器对象,然后串成一个列表(List),最后一个一个的调用列表中的拦截器。Struts2的拦截器是可插拔的,拦截器是AOP的一个实现。Struts2拦截器栈就是将拦截器按一定的顺序连接成一条链。在访问被拦截的方法或者字段时,Struts2拦截器链中的拦截器就会按照之前定义的顺序进行调用。

3.自定义拦截器的步骤
  1)、创建我们自己的拦截器类并实现 HandlerInterceptor 接口。
  2)、创建一个Java类继承WebMvcConfigurerAdapter,并重写 addInterceptors 方法。
  3)、实例化我们自定义的拦截器,然后将对像手动添加到拦截器链中(在addInterceptors方法中添加)。

4.代码示例

IndexInterceptor.java类代码:

package com.example.interceptor;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;

import org.springframework.web.servlet.ModelAndView;

public class IndexInterceptor implements HandlerInterceptor{

  @Override

  public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)

      throws Exception {

    System.out.println(">>>IndexInterceptor>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)");

  }

  @Override

  public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)

      throws Exception {

    System.out.println(">>>IndexInterceptor>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)");

  }

  @Override

  public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {

     System.out.println(">>>IndexInterceptor>>>>>>>在请求处理之前进行调用(Controller方法调用之前)");

     // 只有返回true才会继续向下执行,返回false取消当前请求

     return true;

  }

}

IndexInterceptor2.java类代码:

package com.example.interceptor;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;

import org.springframework.web.servlet.ModelAndView;

public class IndexInterceptor2 implements HandlerInterceptor{

  @Override

  public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)

      throws Exception {

    System.out.println(">>>IndexInterceptor2>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)");

  }

  @Override

  public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)

      throws Exception {

    System.out.println(">>>IndexInterceptor2>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)");

  }

  @Override

  public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {

     System.out.println(">>>IndexInterceptor2>>>>>>>在请求处理之前进行调用(Controller方法调用之前)");

     // 只有返回true才会继续向下执行,返回false取消当前请求

     return false;

  }

}

SimpleWebAppConfigurer.java类代码:

package com.example.config;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.example.interceptor.IndexInterceptor;

import com.example.interceptor.IndexInterceptor2;

//只要能被springboot扫描到即可

@Configuration

public class SimpleWebAppConfigurer extends WebMvcConfigurerAdapter{

  @Override

  public void addInterceptors(InterceptorRegistry registry) {

    // 多个拦截器组成一个拦截器链

    // addPathPatterns 用于添加拦截规则

    // excludePathPatterns 用户排除拦截

    registry.addInterceptor(new IndexInterceptor()).addPathPatterns("/**");

    registry.addInterceptor(new IndexInterceptor2()).addPathPatterns("/**");

    super.addInterceptors(registry);

  }

}

5.应用场景

1、日志记录,可以记录请求信息的日志,以便进行信息监控、信息统计等。

2、权限检查:如登陆检测,进入处理器检测是否登陆,如果没有直接返回到登陆页面。

3、性能监控:典型的是慢日志

6.注意点

在一个工程中,可以配置多个拦截器,使用多个拦截器,则要注意的是 :多个拦截器使用的时候,prehandler是顺序执行的,而posthandler和afterhandler是倒序执行的;

所以 :如果统一日志处理器拦截器,需要改拦截器prehandler一定要返回true,且将它放在拦截器配置的第一个位置;

      如果登陆认证拦截器,放在拦截器的配置中的第一个位置(有日志处理的话,放在日志处理下面);

      如果有权限校验拦截器,则放在登陆拦截器之后,因为登陆通过后,才可以进行校验权限;

上一篇:spring拦截器配置和实现


下一篇:生产系统恢复到异机测试