• java web 过滤器跟拦截器的区别和使用


    一、过滤器 
    1.什么是过滤器?

    过滤器是一个程序,它先于与之相关的servlet或JSP页面运行在服务器上。过滤器可附加到一个或多个servlet或JSP页面上,并且可以检查进入这些资源的请求信息。在这之后,过滤器可以作如下的选择: 
    ①以常规的方式调用资源(即,调用servlet或JSP页面)。 
    ②利用修改过的请求信息调用资源。 
    ③调用资源,但在发送响应到客户机前对其进行修改。 
    ④阻止该资源调用,代之以转到其他的资源,返回一个特定的状态代码或生成替换输出。

    2.Servlet过滤器的基本原理:

    在Servlet作为过滤器使用时,它可以对客户的请求进行处理。处理完成后,它会交给下一个过滤器处理,这样,客户的请求在过滤链里逐个处理,直到请求发送到目标为止。例如,某网站里有提交“修改的注册信息”的网页,当用户填写完修改信息并提交后,服务器在进行处理时需要做两项工作:判断客户端的会话是否有效;对提交的数据进行统一编码。这两项工作可以在由两个过滤器组成的过滤链里进行处理。当过滤器处理成功后,把提交的数据发送到最终目标;如果过滤器处理不成功,将把视图派发到指定的错误页面。

    3.过滤器:只想要在一堆东西里面选个B: 
    这里写图片描述

    4.示例代码

    在web.xml里面配置自定义的过滤器
    <filter>
       <filter-name>Redirect Filter</filter-name>
       <filter-class>com.xx.filter.RedirectFilter</filter-class>
    </filter>
    
    <filter-mapping>
       <filter-name>Redirect Filter</filter-name>
       <url-pattern>/xx/xx/*</url-pattern>
    </filter-mapping>

    如何编写自定义的过滤器
    public class RedirectFilter implements Filter {
           public void doFilter(ServletRequest request, ServletResponse response,
                  FilterChain filterChain) throws IOException, ServletException {
        // 获取URL
       Long startTime = null;
            if (log.isDebugEnabled())
            {
                startTime = System.currentTimeMillis();
            }
                  HttpServletRequest httpRequest = (HttpServletRequest) request;
                              String url = httpRequest.getRequestURL().toString();
                          if (url == null || url.trim().length() == 0) {
                                        return;
                                                       }
                         if (url.indexOf(luceneCreateMapping) != -1
                                      || url.indexOf(luceneSearchMapping) != -1) {
                                   doFilterForxxx(request, response, url);
                                   } else {
                                         doxxxx(request, response, url);
                                        }
             if (log.isDebugEnabled())
            {
                long endTime = System.currentTimeMillis();
                Thread currentThread = Thread.currentThread();
                String threadName = currentThread.getName();
                log.debug("[" + threadName + "]" + "< "
                        + this.getClass().getName() + " " + url + " "
                        + (endTime - startTime) + " ms");
            }
    // 激活下一个Filter
     filterChain.doFilter(request, response);
    
            }
    }
    示例2
    // 填充100个带有随机字母标签的球
    List<String> array = new ArrayList<>();
    Random r = new Random();
    String[] balls = new String[]{"A", "B", "C"};
    for (int i = 0; i < 100; i++)
      array.add(balls[r.nextInt(3)]);
    
    // 只拿出B的来。不明白的自行学习Java 8
    array = array.stream().filter(ball -> ball.equals("B")).collect(Collectors.toList())

    二、拦截器 
    1.什么是拦截器?

    拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。 
    在Webwork的中文文档的解释为——拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。 
    谈到拦截器,还有一个词大家应该知道——拦截器链(Interceptor Chain,在Struts 2中称为拦截器栈 Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

    2.拦截器的实现原理:

    大部分时候,拦截器方法都是通过代理的方式来调用的。Struts 2的拦截器实现相对简单。当请求到达Struts 2的ServletDispatcher时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表(list),最后一个一个地调用列表中的拦截器。

    3.拦截器:把水流变小点,把鱼都拦住!顺便发个电: 
    这里写图片描述

    4.示例代码

    在xml文件中如何定义拦截器
    <interceptors>
        <interceptor name="filterIPInterceptor" class="com.xxxx.web.FilterIPActionInterceptor" />
            <interceptor-stack name="filterIPStack">
            <interceptor-ref name="defaultStack" />                           
            <interceptor-ref name="filterIPInterceptor" />
        </interceptor-stack>
    </interceptors>
    怎么编写自定义拦截器 
    public class FilterIPActionInterceptor extends AbstractInterceptor
    {
        /** 日志控制. */
        private final Log log = LogFactory.getLog(getClass());
    
        /**
         * @see com.opensymphony.xwork2.interceptor.AbstractInterceptor#intercept(com.opensymphony.xwork2.ActionInvocation)
         */
        @Override
        @SuppressWarnings("unchecked")
        public String intercept(ActionInvocation invocation) throws Exception
        {
            String result = null;
            // 获得当前方法名.
            String methodName = invocation.getInvocationContext().getName();
            String currIp = null;
            try
            {
                if (invocation.getAction() instanceof PortletAction)
                {
                    PortletAction action = (PortletAction) invocation.getAction();
                    currIp = action.getRequest().getRemoteAddr();
                }
                String ip = ApplicationResource.getHotValue("ALLOW_CACHE_IP");
    
                if (StringUtils.isBlank(ip) || StringUtils.isBlank(currIp))
                {
                    log.error("允许刷新的IP不存在或当前请求的IP非法.");
                    throw new NoAllowIPException();
                }
                else
                {
                    String[] ips = ip.split(",");
                    boolean errorIp = true;
                    for (String s : ips)
                    {
                        if (s.equals(currIp))
                            errorIp = false;
                    }
                    // 判断IP
                    if (errorIp)
                        throw new NoAllowIPException();
                }
                result = invocation.invoke();//调用被拦截的方法
            }
            catch (Exception e)
            {
                log.error("异常类名:" + invocation.getAction().getClass());
                log.error("异常方法:" + methodName, e);
                throw e;
            }
    
            return result;
        }
    
    }
    
    示例2
    作者:知乎用户
    链接:https://www.zhihu.com/question/35225845/answer/61876681
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    class River {
      // 流量
      int volume;
    
      // 总鱼数
      int numFish;
    }
    
    class PowerGenerator {
      double generate (int volume) {
        // 假设每一百立方米水发一度电
        return volume / 100;
      }
    }
    
    interface Interceptor {
      void intercept (River river);
    }
    
    class SomeInterceptor implements Interceptor {
      PowerGenerator generator = new PowerGenerator();
    
      @Override
      public void intercept (River river) {
        // 消耗了1000立方米水来发电
        int waterUsed = 1000;
    
        // 水量减少了1000。请不要跟我讨论水电站原理的问题,
        // 我就那么一比方
        river.volume -= waterUsed;
    
        // 发电
        generator.generate (waterUsed);
    
        // 拦截所有的鱼
        river.numFish = 0;
      }
    }
    
    class RiverController {
      Interceptor interceptor;
    
      void flow(River river) {
        // 源头积累下来的水量和鱼
        river.volume += 100000
        river.numFish += 1000
    
        // 经过了大坝
        interceptor.intercept(river);
    
        // 下了点雨
        river.volume += 1000
      }
    
      void setInterceptor (Interceptor interceptor) {
        this.interceptor = interceptor
      }
    }
    
    class Main {
      public static void main (String args[]) {
        RiverController rc = new RiverController;
        Interceptor inter = new SomeInterceptor();
    
        // 这一步通常叫做控制反转或依赖注入,其实也没啥子
        rc.setInterceptor(inter);
    
        rc.flow(new River());
      }
    }


    拦截器与过滤器的区别 :

     1. 拦截器是基于java的反射机制的,而过滤器是基于函数回调。
     2. 拦截器不依赖与servlet容器,过滤器依赖与servlet容器。 
     3. 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
     4. 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。 
     5. 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次拦截器的代  
        码实现。
     6. Filter基于回调函数,我们需要实现的filter接口中doFilter方法就是回调函数,而interceptor则基于 
        java本身的反射机制,这是两者最本质的区别。
     7. Filter是依赖于servlet容器的,即只能在servlet容器中执行,很显然没有servlet容器就无法来回调
        doFilter方法。而interceptor与servlet容器无关。
     8. Filter的过滤范围比Interceptor大,Filter除了过滤请求外通过通配符可以保护页面,图片,文件等等,
        而Interceptor只能过滤请求。
     9. Filter的过滤例外一般是在加载的时候在init方法声明,而Interceptor可以通过在xml声明是guest请求还
        是user请求来辨别是否过滤。
    

    三、监听器 
    1.监听器(Listener):当一个事件发生的时候,你希望获得这个事件发生的详细信息,而并不想干预这个事件本身的进程,这就要用到监听器。 
    这里写图片描述

    2.示例代码

    作者:知乎用户
    链接:https://www.zhihu.com/question/35225845/answer/61876681
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    // 监听器
    interface BedListener {
      // 监听器在参数中收到了某个事件,而这个事件往往是只读的
      // 监听器的方法名通常以"on"开头
      void onBedSound (String sound);
    }
    
    class Neighbor {
      BedListener listener;
    
      // 依然是所谓控制反转
      setListener (BedListener listener) {
        this.listener = listener;
      }
    
      void doInterestingStuff () {
        // 根据当地法律法规,部分内容无法显示
    
        // 将事件发送给监听器
        listener.onBedSound("嘿咻");
        listener.onBedSound("oyeah");
      }
    }
    
    class Main {
      public static void main (String args[]) {
        Neighbor n = new Neighbor();
        n.setListener (sound -> generatePower());
        n.doInterestingStuff();
      }
    
      private static void generatePower() {
        // 根据当地法律法规,部分内容无法显示
      }
    }
  • 相关阅读:
    leetcode hot 100- 84. 柱状图中最大的矩形
    leetcode hot 100- 221. 最大正方形
    leetcode hot 100-34. 在排序数组中查找元素的第一个和最后一个位置
    leetcode hot 100-剑指 Offer 37. 序列化二叉树
    leetcode hot 100-2. 两数相加
    leetcode hot 100-33. 搜索旋转排序数组
    leetcode hot 100- 98. 验证二叉搜索树
    leetcode hot 100-152. 乘积最大子数组
    leetcode hot 100-19. 删除链表的倒数第N个节点
    v-modal的使用。
  • 原文地址:https://www.cnblogs.com/shizhijie/p/8423338.html
Copyright © 2020-2023  润新知