过滤器与拦截器区别、使用场景笔记整理

①拦截器是基于java的反射机制的,而过滤器是基于函数回调。
  ②拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
  ③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
  ④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
  ⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

  6.拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

另摘自http://blog.csdn.net/chenleixing/article/details/44573495#reply ,疑似《java编程思想》截图

这本书对java开发者来说确实是奇书,虽然不管什么时候看都是似懂非懂,而且每次都没看完。但确实有帮助,推荐1-2年开发者看

 

大家请看我的web.xml过滤器配置,依次 为shiro权限过滤器,编码过滤器,微信接口过滤器,上传文件过滤器

复制代码

复制代码

<!-- shiro过滤器定义 -->
  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
      <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->
      <param-name>targetFilterLifecycle</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!-- 编码过滤器 -->
  <filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!--<async-supported>true</async-supported>-->
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>


  <!--微信接口访问-->
  <filter>
    <filter-name>WXInterface</filter-name>
    <filter-class>com.shangtu.filter.WXInterfaceFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>WXInterface</filter-name>
    <url-pattern>/WX/*</url-pattern><!-- 你开放的接口前缀  -->
  </filter-mapping>

  <!--上传接口访问-->
  <filter>
    <filter-name>UploadInterface</filter-name>
    <filter-class>com.shangtu.filter.FileUploadFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>UploadInterface</filter-name>
    <url-pattern>/upload/*</url-pattern><!-- 你开放的接口前缀  -->
  </filter-mapping>

复制代码

复制代码

然后很不幸的我的项目中没有使用interceptor(第一次自己搭建项目,很多功能需求还在确认中),使用的是aspect,以下以日志记录为例:

1、注册bean,开启aspect注解支持,开启aspect注解扫描

 View Code

2、建立自定义注解类,达到灵活注解的目的

 View Code

3、写入逻辑,日志为操作成功后记录

 View Code

至此,只要在controller方法中加入

@SyslogAnnotation(modelName="代理中心", functionName="给代理发卡", commons="userId:登录ID,agentId:被发卡人ID,card:发卡数量")

即可获取参数,插入自定义日志到数据库中 。

而关于Aspect与interceptor的关系,大致百度了一下(不能不信,也不能全信,希望以后能在这方面继续完善更新) 

AOP是一种将业务逻辑提取出来,以实现代码复用,易于维护的方式,拦截器是它的一种具体实现,aspectJ也是一种具体实现,但拦截器具有代码侵入性,aspectJ具有相比更低的侵入性,更好,易于维护

根据以上代码事实可以确认的是,

1、大量的请求块信息处理使用filter,  特别的内部逻辑处理所使用aspect

2、filter是servlet级别的,不属于spring      aspect和interceptor属于spring框架 

3、filter配置在web.xml中    interceptor配置在spring配置文件中 

4、filter的作用范围中可以包含aspect和interceptor

 

 

拦截器与过滤器的区别总结:

 

 

过滤器在web.xml中配置:

(1)因为一开始在过滤器中映射的url-pattern填写路径是*.action。所有的action要经过它的过滤。<url-pattern>*.action</url-pattern>

(2)因为在web.xml中配置了过滤器,所以,执行过程所有程序都经过struts2过滤器(路径是:/*),首先过滤自己相关的程序,如xx.action,先处理,如果是.html或者.jsp就不会处理,直接放行。

解决方法:把过滤器映射路径改为:/*  ,即全部过滤处理。

<url-pattern>/*</url-pattern>

过滤器和拦截器不同,struts中拦截器是核心。

 

理解

(1)过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。(理解:就是一堆字母中取一个B)

(2)拦截器(Interceptor):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。(理解:就是一堆字母中,干预他,通过验证的少点,顺便干点别的东西)。
 

拦截器 :是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。

过滤器:是在javaweb中,你传入的request、response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符.。

 

拦截器与过滤器使用场景:

spring Web MVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。

 

1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。

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

3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);

4、通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。

5、OpenSessionInView:如hibernate,在进入处理器打开Session,在完成后关闭Session。

 

 

具体区别

 

拦截器是AOP( Aspect-Oriented Programming)的一种实现,底层通过动态代理模式完成。

区别:

(1)拦截器是基于java的反射机制的,而过滤器是基于函数回调。

(2)拦截器不依赖于servlet容器,而过滤器依赖于servlet容器。

(3)拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。

(4)拦截器可以访问action上下文、值栈里的对象,而过滤器不能。

(5)在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

 

 

 两者的本质区别:从灵活性上说拦截器功能更强大些,Filter能做的事情,他都能做,而且可以在请求前,请求后执行,比较灵活。Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验(比较泛的,比如登录不登录之类),太细的话,还是建议用interceptor。不过还是根据不同情况选择合适的。

 

 

 

filter

Interceptor

多个的执行顺序

根据filter mapping配置的先后顺序

按照配置的顺序,但是可以通过order控制顺序

规范

在Servlet规范中定义的,是Servlet容器支持的

spring容器内的,是Spring框架支持的。

使用范围

只能用于Web程序中

既可以用于Web程序,也可以用于Application、Swing程序中。

深度

Filter在只在Servlet前后起作用

拦截器能够深入到方法前后、异常抛出前后等

 

 

 
补充说明:
    Spring的拦截器与Servlet的Filter有相似之处,比如二者都是AOP编程思想的体现,都能实现权限检查、日志记录等。不同的是:

     使用范围不同:Filter是Servlet规范规定的,只能用于Web程序中。而拦截器既可以用于Web程序,也可以用于Application、Swing程序中。
     规范不同:Filter是在Servlet规范中定义的,是Servlet容器支持的。而拦截器是在Spring容器内的,是Spring框架支持的。

使用的资源不同:同其他的代码块一样,拦截器也是一个Spring的组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象,例如Service对象、数据源、事务管理等,通过IoC注入到拦截器即可;而Filter则不能。

深度不同:Filter在只在Servlet前后起作用。而拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。所以在Spring构架的程序中,要优先使用拦截器。

  实际上Filter和Servlet极其相似,区别只是Filter不能直接对用户生成响应。实际上Filter里doFilter()方法里的代码就是从多个Servlet的service()方法里抽取的通用代码,通过使用Filter可以实现更好的复用。
  filter是一个可以复用的代码片段,可以用来转换HTTP请求、响应和头信息。Filter不像Servlet,它不能产生一个请求或者响 应,它只是修改对某一资源的请求,或者修改从某一的响应。
  JSR中说明的是,按照多个匹配的Filter,是按照其在web.xml中配置的顺序 来执行的。 

所以这也就是,把自己的Filter或者其他的Filter(比如UrlRewrite的Filter)放在Struts的 DispatcherFilter的前面的原因。因为,它们需要在请求被Struts2框架处理之前,做一些前置的工作。 

        当Filter被调用,并且进入了Struts2的DispatcherFilter中 后,Struts2会按照在Action中配置的Interceptor Stack中的Interceptor的顺序,来调用Interceptor。

 

 

 

 

 

一、过滤器 
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() {
    // 根据当地法律法规,部分内容无法显示
  }
}
--------------------- 
作者:suk1M 
来源:CSDN 
原文:https://blog.csdn.net/w214019153/article/details/68491523 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 1
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值