1 过滤器和拦截器的异同

1.1 一张图表明两者之间的差异:

tomcat,filter,servet,interceptor以及controller等各种容器的关系图

1.2 两者的区别:

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

  • 拦截器不依赖与servlet容是依赖于spring容器,过滤器依赖与servlet容器。

  • 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用,可以限制用户对图片,文件以及其他资源的访问。

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

  • 在action的生命周期中,拦截器可以多次被调用(因为拦截器是基于反射机制实现的,即通过加载java字节码而实现的函数的调用,所以每一次运行拦截器的时候都需要找到拦截器相关的字节码并且执行),而过滤器只需在容器初始化时被调用一次(意思是只需要调用一次,filter过滤器程序就会一直在内存中执行下去,每当碰到一次请求,服务器无需再次调用都会进行拦截,除非被主动摧毁。(1)启动服务器时加载过滤器的实例,并调用init()方法来初始化实例;(2)、每一次请求时都只调用方法doFilter()进行处理;(3)、停止服务器时调用destroy()方法,销毁实例。)。

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

1.3 两者的相同之处:

本文主要对基于Spring boot对过滤器和拦截器的配置进行的讲解。无论是过滤器还是拦截器都属于AOP(面向切面编程)思想的具体实现。

2 过滤器

2.1 用法

当Web容器接受到一个对资源的请求时:

  1. 它将判断是否有过滤器与这个资源相关联。
  2. 如果有,那么容器将把请求交给过滤器进行处理。在过滤器中,你可以改变请求的内容,或者重新设置请求的报头信息,然后再将请求发送给目标资源
  3. 当目标资源对请求作出响应时候,容器同样会将响应先转发给相应的过滤器。

2.2 作用

在过滤器中你可以对响应的内容进行转换,然后再将响应发送到客户端。常见的过滤器用途

主要包括:

  • 对用户请求进行统一认证
  • 对用户的访问请求进行记录和审核、
  • 对用户发送的文本数据进行过滤或替换,比如替换掉脏话、
  • 转换图象格式、
  • 对响应内容进行压缩以减少传输量、
  • 对请求或响应进行加解密处理、
  • 触发资源访问事件、
  • 对XML的输出应用XSLT等。

2.3 实现过滤器 方法一:不使用@WebFilter下,既需要编写过滤器类,又要编写配置类

2.3.1 先编写过滤器类

过滤器类就是指 当拦截到某一个请求后,在该请求发往servlet容器前,执行什么操作,需要进行什么处理

public class LogCostFilter implements Filter{@Overridepublic void init(FilterConfig filterConfig)throws ServletException{}@Overridepublic void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain)throws IOException,ServletException{long start =System.currentTimeMillis();filterChain.doFilter(servletRequest,servletResponse);System.out.println("Execute cost="+(System.currentTimeMillis()-start));}@Overridepublic void destroy(){}
}

这段代码的逻辑比较简单,就是在方法执行前先记录时间戳,然后通过过滤器链完成请求的执行,在返回结果之间计算执行的时间。这里需要主要,这个类必须继承Filter类,这个是Servlet的规范,这个跟以前的Web项目没区别。

2.3.2 再在其配置类中配置过滤器需要拦截的请求类型的正则表达式以及决定使用哪一个过滤器类

但是,有了过滤器类以后,以前的web项目可以在web.xml中进行配置,但是spring- boot项目并没有web.xml这个文件,那怎么配置?在Spring boot中,我们需要FilterRegistrationBean来完成配置。其实现过程如下:


@Configuration
public class FilterConfig{@Beanpublic FilterRegistrationBean registFilter(){FilterRegistrationBean registration =new FilterRegistrationBean();registration.setFilter(newLogCostFilter());registration.addUrlPatterns("/*");registration.setName("LogCostFilter");registration.setOrder(1);return registration;}
}

这样配置就完成了,需要配置的选项主要包括实例化Filter类,然后指定url的匹配模式,设置过滤器名称和执行顺序,这个过程和在web.xml中配置其实没什么区别,只是形式不同而已。现在我们可以启动服务器访问任意URL:

2.4 过滤器实现代码 方法二:仅仅使用@WebFilter和过滤器类,不要编写配置类

大家可以看到上面的配置已经生效了。除了通过 FilterRegistrationBean 来配置以外,还有一种更直接的办法,

2.4.1 直接通过注解@WebFilter就可以完成了:

@WebFilter(urlPatterns ="/*", filterName ="logFilter2")
public class LogCostFilter2 implements Filter{@Overridepublicvoid init(FilterConfig filterConfig)throwsServletException{}@Overridepublic void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain)throwsIOException,ServletException{long start =System.currentTimeMillis();filterChain.doFilter(servletRequest, servletResponse);System.out.println("LogFilter2 Execute cost="+(System.currentTimeMillis()- start));}@Overridepublic void destroy(){}
}

2.4.2

这里直接用@WebFilter就可以进行配置,同样,可以设置url匹配模式,过滤器名称等。这里需要注意一点的是@WebFilter这个注解是Servlet3.0的规范,并不是Spring boot提供的。除了这个注解以外,我们还需在配置类中加另外一个注解:@ServletComponetScan,指定扫描的包。

@SpringBootApplication
@MapperScan("com.pandy.blog.dao")
@ServletComponentScan("com.pandy.blog.filters")
public class springbootApplication{public static void main(String[] args) throws Exception{SpringApplication.run(Application.class, args);}
}

现在,我们再来访问一下任意URL:

2.4.3 多个拦截器存在时候的执行顺序问题

可以看到,我们配置的两个过滤器都生效了。细心的读者会发现,第二个Filter我们并没有指定执行的顺序,但是却在第一个Filter之前执行。这里需要解释一下,@WebFilter这个注解并没有指定执行顺序的属性,其执行顺序依赖于Filter的名称,是根据Filter类名(注意不是配置的filter的名字)的字母顺序倒序排列,并且@WebFilter指定的过滤器优先级都高于FilterRegistrationBean配置的过滤器。有兴趣的朋友可以自己实验一下。

3 拦截器

3.1 拦截器定义

3.1.1 讲一讲拦截器实现的机制。

在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截,然后在之前或之后加上某些操作。拦截是AOP的一种实现策略。

3.1.2 拦截器作用有什么作用呢?

AOP面向切面有什么作用,那么拦截器就有什么作用。

  • 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV…
  • 权限检查:认证或者授权等检查性能
  • 监控:通过拦截器在进入处理器之前记录开始时间,处理完成后记录结束时间,得到请求处理时间。
  • 通用行为:读取cookie得到用户信息并将用户对象放入请求头中,从而方便后续流程使用。

3.1.3 拦截器实现拦截器集成接口HandlerInterceptor,实现拦截,接口方法有下面三种:

  • preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) 方法将在请求处理之前进行调用。SpringMVC中的Interceptor同Filter一样都是链式调用。每个Interceptor的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor中的preHandle方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean 类型的,当它返回为false时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值为true时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。

  • postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。

  • afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。总结一点就是:preHandle是请求执行前执行postHandle是请求结束执行afterCompletion是视图渲染完成后执行

3.2 拦截器实现

3.2.1

上面我们已经介绍了过滤器的配置方法,接下来我们再来看看如何配置一个拦截器。我们使用拦截器来实现上面同样的功能,记录请求的执行时间。首先我们实现拦截器类:

public class LogCostInterceptor implements HandlerInterceptor{long start =System.currentTimeMillis();@Overridepublicboolean preHandle(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Object o) throws Exception{start =System.currentTimeMillis();return true;}@Overridepublic void postHandle(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Object o,ModelAndView modelAndView) throws Exception{System.out.println("Interceptor cost="+(System.currentTimeMillis()-start));}@Overridepublicvoid afterCompletion(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Object o,Exception e)throwsException{}
}

3.3.2

这里我们需要实现HandlerInterceptor这个接口,这个接口包括三个方法,preHandle是请求执行前执行的,postHandler是请求结束执行的,但只有preHandle方法返回true的时候才会执行,afterCompletion是视图渲染完成后才执行,同样需要preHandle返回true,该方法通常用于清理资源等工作。除了实现上面的接口外,我们还需对其进行配置:

@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter{@Overridepublic void addInterceptors(InterceptorRegistry registry){registry.addInterceptor(newLogCostInterceptor()).addPathPatterns("/**");super.addInterceptors(registry);}
}

这里我们继承了WebMVCConfigurerAdapter,看过前面的文章的朋友应该已经见过这个类了,在进行静态资源目录配置的时候我们用到过这个类。这里我们重写了addInterceptors这个方法,进行拦截器的配置,主要配置项就两个,一个是指定拦截器,第二个是指定拦截的URL。现在我们再启动系统访问任意一个URL:

可以看到,我们通过拦截器实现了同样的功能。不过这里还要说明一点的是,其实这个实现是有问题的,因为preHandle和postHandle是两个方法,所以我们这里不得不设置一个共享变量start来存储开始值,但是这样就会存在线程安全问题。当然,我们可以通过其他方法来解决,比如通过ThreadLocal就可以很好的解决这个问题,有兴趣的同学可以自己实现。不过通过这一点我们其实可以看到,虽然拦截器在很多场景下优于过滤器,但是在这种场景下,过滤器比拦截器实现起来更简单。

java中拦截器和过滤器详解相关推荐

  1. Java中拦截器和过滤器的声明用途和区别

    过滤器: 1.基于Servlet框架 2.Oracle公司的任何Java Web框架都可以用 3.可以拦截任何资源,包括 .jsp .java .html等等 拦截器: 1.基于SpringMvc框架 ...

  2. struts2中拦截器和过滤器的比较

    拦截器和过滤器的区别: 1.拦截器是基于java的反射机制的,而过滤器是基于函数回调 2.过滤器依赖与servlet容器,而拦截器不依赖与servlet容器 3.拦截器只能对action请求起作用,而 ...

  3. 详解拦截器和过滤器的区别

    拦截器和过滤器的区别 过滤器和拦截器的区别: ①拦截器是基于java的反射机制的,而过滤器是基于函数回调. ②拦截器不依赖与servlet容器,过滤器依赖与servlet容器. ③拦截器只能对acti ...

  4. 区分Java拦截器和过滤器

    今天带大家分析java拦截器和过滤器的区别,文中有非常详细的解释说明,对正在学习java的小伙伴们有很好的帮助,需要的朋友可以参考下 一.过滤器(filter) 过滤器处于客户端与Web资源(Serv ...

  5. java 拦截器和过滤器的区别

    介绍 在 Java Web 应用程序中,拦截器和过滤器是两种不同的机制,用于在请求/响应处理过程中进行拦截和过滤.两者都可以用来在请求到达目标资源之前对其进行预处理.修改或拦截. 但是,拦截器和过滤器 ...

  6. SpringBoot 拦截器和过滤器

    拦截器和过滤器 时光飞逝,最近也是很忙,但是忙到最后发现在自己并没有太多的成长 工作 学习 生活 没想到成长是不经意间的,像是被 推着,让你身不由己 午休时间,写写博客,也是保留一些自己的时间和空间 ...

  7. 关于SSM框架设置拦截器和过滤器

    我们知道拦截器和过滤器都是在项目中起到拦截过滤请求的功能,所以可能在设置的时候会傻傻分不清.这里我们先来比较它们的区别. 过滤器Filter是JavaEE标准,在Servlet的规范中定义的,是Ser ...

  8. 拦截器与过滤器详解,使用方式与注意事项,使用场景以及区别与联系

    过滤器Filter 定义 对Servlet容器调用Servlet的过程进行拦截,基于函数回调实现 常见使用场景 统一设置编码 过滤敏感字符 登录校验 URL级别的访问权限控制 数据压缩 使用方式 这了 ...

  9. 拦截器和过滤器有什么区别?

    首先了解什么是过滤器什么是拦截器 ①过滤器(Filter) 过滤器通过直接实现Filter接口实现,也可以通过@WebFilter注解实现特定的URL拦截 在Filter接口中定义了三个方法: ini ...

  10. 拦截器和过滤器之间有很多相同之处,但是两者之间存在根本的差别

    转自:https://www.cnblogs.com/shangc/p/5939708.html 拦截器和过滤器之间有很多相同之处,但是两者之间存在根本的差别.其主要区别为以下几点: 1)拦截器是基于 ...

最新文章

  1. 【树型DP】BZOJ1564 二叉查找树(noi2009)
  2. SOPC第四课 按键中断
  3. 【Python】随机划分数据集并生成VOC格式列表
  4. 几个不错的自己到的少的游戏站
  5. ux和ui_设计社交餐厅策展应用程序— UX / UI案例研究
  6. 台式计算机如何连接vif,关于计算机二级( VIF ) 县城有高手吗? 急寻
  7. 参数到不进oracle,Oracle对于启动参数检查不严格
  8. docker版本包 乌班图_Ubuntu安装Docker方式一:软件包安装
  9. Meteor项目实战 -- Next 0.0.2
  10. 2013年7月新日本語能力試験N3文字部分
  11. es查询大文本效率_【搜索引擎】 4-ES在大数据量下提高查询效率方案
  12. VJ—蟠桃记(C语言)
  13. 位图字体的制作与使用
  14. python编程语言在线编译手机_groovy在线运行,groovy在线编译,支持手机在线编程写代码 - Groovy教程...
  15. HB哈勃与HB公链【尊皇社区】深度揭秘分析!
  16. 电脑提示Wtautoreg.exe无法找到入口怎么解决?
  17. APP上查个人信用报告靠谱吗?
  18. 拼图游戏Canvas版
  19. 全志A10平板上的ubuntu终极安装版,支持HDMI和平板本机LCD
  20. Windows mobile PPC,利用tmail.exe发送短信、彩信、邮件

热门文章

  1. 计算机四级网络工程师(计算机网络单选)- 知识点
  2. nios IIcommand shell 烧录
  3. java网上购物系统_基于java的网上购物系统的设计与实现
  4. UE4 虚幻引擎,蓝图Movement组件
  5. 2019汤家凤高等数学强化班讲义
  6. 企业权限管理系统之AdminLTE的基本介绍(一)
  7. Word基础(八)带圈字符
  8. 安卓逆向 -- JEB3.7安装使用
  9. 《你的灯亮着吗》开始解决问题前,得先知道“真问题”是什么
  10. CTF知识总结--MISC