一、背景介绍
1.过滤器
依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等。
2.拦截器
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。
3.监听器
web监听器是一种Servlet中的特殊的类,它们能帮助开发者监听web中的特定事件,实现了javax.servlet.ServletContextListener 接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。主要作用是:感知到包括request(请求域),session(会话域)和applicaiton(应用程序)的初始化和属性的变化。
二、知识剖析
1.拦截器的使用
项目中使用:编写实现接口的类+springMVC.xml中配置
过滤器只需要实现HandlerInterceptor或者WebRequestInterceptor,重写相应的preHandle(...)、postHandle(...)和afterCompletion(...)方法即可。
(1)preHandle 方法将在请求处理之前进行调用。所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean 类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。
(2)postHandle 方法,顾名思义就是在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。
(3)afterCompletion法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。
2.过滤器的使用
项目中使用:编写实现接口的类+web.xml中配置
过滤器只需要实现javax.servlet.filter,重写doFilter(...)、init(...)和destroy(..)方法即可
实现doFilter方法,完成对请求或响应的过滤
实现init方法,读取过滤器的初始化参数
destroy(),过滤器销毁的时候做一些操作
3.监听器的使用
项目中使用:编写实现接口的类+springMVC.xml中配置
监听器接口主要有四类八种,能够监听包括request域,session域,application域的产生,销毁和属性的变化
监听对象的创建:
(1)ServletContext:主要监听servletContext的创建,需要实现ServeltContextListener接口;
(2)ServletRequest:主要监听request的创建,需要实现ServletRequestListener接口;
(3)HttpSession:主要监听session的创建,需要实现HttpSessionListener接口
监听属性的改变:
(1)ServletContext:主要监听servletContext属性的更改、添加、删除,需要实现ServeltContextAttrbuteListener接口;
(2)ServletRequest:主要监听request属性的更改、添加、删除, 需要实现ServletRequestAttrbuteListener接口; (3)HttpSession:主要监听session属性的更改、添加、删除,需要实现HttpSessionAttrbuteListener接口。
监听session的活化与钝化:httpSessionActivationListener主要监听了session的活化与钝化。
监听session与对象的绑定:httpSessionBindingListener监听了session与对象的绑定。
三、常见问题及解决
拦截器、过滤器、监听器的区别是什么?
1.从关注的点来说:过滤器拦截器作用域web请求,并对一些信息做相应的更改;监听器作用于系统级别的参数的监听,一般不做更改。
2.所依赖的支持来说:拦截器需要Spring的支持;过滤器、监听器需要servlet的支持。
3.应用场景的不同
(1)拦截器:拦截未登录、审计日志等;
(2)过滤器:设置字符编码、URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等;
(3)监听器:统计在线人数、清除过期session。
四、扩展思考
1.拦截器、过滤器、监听器的执行顺序
监听器 > 过滤器 > 拦截器 > servlet执行 > 拦截器 > 过滤器 > 监听器
2.多个拦截器的执行顺序(两个)
(1)当俩个拦截器都实现放行操作时,顺序为preHandle 1,preHandle 2,postHandle 2,postHandle 1,afterCompletion 2,afterCompletion 1;
(2)当第一个拦截器preHandle返回false,也就是对其进行拦截时,第二个拦截器是完全不执行的,第一个拦截器只执行preHandle部分;
(3)当第一个拦截器preHandle返回true,第二个拦截器preHandle返回false,顺序为preHandle 1,preHandle 2 ,afterCompletion 1。
3.多个过滤器的执行顺序
web服务器根据Filter在web.xml中的注册顺序,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法,在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第二个filter,如果没有,则调用目标资源。
4.多个监听器的执行顺序
一个webServlet里面若有多个监听器的话,顺序是按照加载的顺序来加载和注册的这些servlet监听器的。
五、更多讨论
1.怎样使用自定义注解实现拦截器?
首先需要定义一个自定义的注解
@Target(ElementType.METHOD ) @Retention(RetentionPolicy.RUNTIME) public @interface AccessRequired {undefined }
这里的ElementType.METHOD 表示的是对方法有效
RetentionPolicy.RUNTIME
一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解
然后在编写自己的拦截器,web.xml文件中也需要配置
最后在需要拦截的方法上标上自定义注解,表示需要拦截这个方法。
2.未登录或者非vip的话,可以试看10分钟怎么解决 ?
将视频分段,前十分钟是一个请求,之后再次请求,拦截后边这个请求
3.拦截器与过滤器的区别 :
(1)拦截器是基于java的反射机制的,而过滤器是基于函数回调。
(2)拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
(3)拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
(4)拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
(5)在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次