zoukankan      html  css  js  c++  java
  • 拦截器详解

    网络上关于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,且将它放在拦截器配置的第一个位置;

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

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

    我话讲完!谁赞成?谁反对?
  • 相关阅读:
    [School Regional Team Contest, Saratov, 2011]
    [Codeforces Round #125 (Div. 2)] B. Special Olympics(圆的关系问题)
    2020ICPC·小米 网络选拔赛第一场 G-Tree Projection (构造)
    [Codeforces Round #679 (Div. 2)] D. Shurikens (思维,树状数组)
    [Codeforces Round #677 (Div. 3)] G. Reducing Delivery Cost (dijkstra,枚举)
    [Codeforces Round #677 (Div. 3)] F. Zero Remainder Sum (DP)
    cogs 2652. 秘术「天文密葬法」(0/1分数规划 长链剖分 二分答案 dp
    cogs 1377. [NOI2011] NOI嘉年华 (dp
    cogs 1199选课(树形dp 背包或多叉转二叉
    Minimum spanning tree for each edge(倍增LCA)
  • 原文地址:https://www.cnblogs.com/wffzk/p/15466619.html
Copyright © 2011-2022 走看看