首页 > 代码库 > 监听器和拦截器复习

监听器和拦截器复习

监听器(Listener)

监听器是一个接口,具体内容由我们来实现,监听器的实现用了观察者模式,我们实现的具体监听器就是观察者

JavaWeb中的监听器

事件源(被监听的对象):三大域!

  • ServletContext

生命周期监听:ServletContextListener,它有两个方法,一个在出生时调用,一个在死亡时调用;

  1.   void contextInitialized(ServletContextEvent sce):创建SErvletcontext时
  2.   void contextDestroyed(ServletContextEvent sce):销毁Servletcontext时

 属性监听:ServletContextAttributeListener,它有三个方法,一个在添加属性时调用,一个在替换属性时调用,最后一个是在移除属性时调用。

  1.   void attributeAdded(ServletContextAttributeEvent event):添加属性时;
  2.   void attributeReplaced(ServletContextAttributeEvent event):替换属性时;
  3.   void attributeRemoved(ServletContextAttributeEvent event):移除属性时;
  • HttpSession

 生命周期监听:HttpSessionListener,它有两个方法,一个在出生时调用,一个在死亡时调用;

  1.   void sessionCreated(HttpSessionEvent se):创建session时
  2.   void sessionDestroyed(HttpSessionEvent se):销毁session时

属性监听:HttpSessioniAttributeListener,它有三个方法,一个在添加属性时调用,一个在替换属性时调用,最后一个是在移除属性时调用。

  1.   void attributeAdded(HttpSessionBindingEvent event):添加属性时;
  2.   void attributeReplaced(HttpSessionBindingEvent event):替换属性时
  3.   void attributeRemoved(HttpSessionBindingEvent event):移除属性时
  • ServletRequest

 生命周期监听:ServletRequestListener,它有两个方法,一个在出生时调用,一个在死亡时调用;

  1.   void requestInitialized(ServletRequestEvent sre):创建request时
  2.   void requestDestroyed(ServletRequestEvent sre):销毁request时

 属性监听:ServletRequestAttributeListener,它有三个方法,一个在添加属性时调用,一个在替换属性时调用,最后一个是在移除属性时调用。

  1.   void attributeAdded(ServletRequestAttributeEvent srae):添加属性时
  2.   void attributeReplaced(ServletRequestAttributeEvent srae):替换属性时
  3.   void attributeRemoved(ServletRequestAttributeEvent srae):移除属性时

javaWeb中完成编写监听器:

  • 写一个监听器类:要求必须去实现某个监听器接口;
  • 注册,是在web.xml中配置来完成注册!(可以使用注解的方式,在后面的笔记中我再记录)

在web.xml文件注册形式为 :

<listener><listener-class>你编写的具体监听器类</listener-class></listener>

 

在三大域中都存在一个生命周期监听和一个属性监听,实际上还有几个监听类,是与HttpSession相关,但它们是用来添加到JavaBean上,而不是添加到三大域上!这两个监听器都不需要在web.xml中注册!它们可以感知session域中对象的创建和销毁

 

监听器在SSH中的应用

在SSH整合的过程中,我们在项目的web.xml文件中配置的spring监听类,其内部就是实现了一个监听器接口,使服务器在启动的时候可以加载spring的配置文件进行初始化

  <!--指定spring文件的位置 -->   <context-param>     <param-name>contextConfigLocation</param-name>     <param-value>classpath:applicationContext.xml</param-value>   </context-param>    <!--配置spring监听器,这样在服务器启动的时候来加载spring-->  <listener>    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  </listener>

 

拦截器(Filter)

过滤器JavaWeb三大组件之一,它与Servlet很相似!不它过滤器是用来拦截请求的,而不是处理请求的

当用户请求某个Servlet时,会先执行部署在这个请求上的Filter,如果Filter“放行”,那么会继承执行用户请求的Servlet;如果Filter不“放行”,那么就不会执行用户请求的Servlet。

其实可以这样理解,当用户请求某个Servlet时,Tomcat会去执行注册在这个请求上的Filter,然后是否“放行”由Filter来决定。可以理解为,Filter来决定是否调用Servlet!当执行完成Servlet的代码后,还会执行Filter后面的代码

所谓的放行就是使用:

 

chain.doFilter(request, response);

 

chain是javax.servlet.FilterChain的参数

javaWeb中完成编写拦截器:

  • 写过滤器就是写一个类,实现Filter(javax.servlet.Filter)接口
  • 注册,是在web.xml中配置来完成注册!(可以使用注解的方式,在后面的笔记中我再记录)

在web.xml文件注册形式为 :

  <filter>    <filter-name>取个名字</filter-name>    <filter-class>类的全路径名</filter-class>  </filter>  <filter-mapping>    <filter-name>使用上边的名字</filter-name>    <url-pattern>要拦截的范围(可以使/*,表示拦截所有请求,还可以是拦截某个Servlet)</url-pattern>  </filter-mapping>

和Servlet在web.xml中的配置很相似吧

注意:Filter在web.xml中配置是有顺序的,先配置的先拦截

还有一个值得注意的地方是:不要认为一个请求在给浏览器输出就完成了,实际上很多事情都需要在给客户端响应之后才能完成,可以在放行语句的前后各输出一句话,可以看到,在Filter放行之后,浏览器就可以输出一个页面(如果Servlet中不做过多操作,只起一个转跳的作用),但是放行之后的语句还是会在控制台输出

 

过滤器的生命周期

Filter的生命周期(和Servlet的生命周期类似)

  • init(FilterConfig):在服务器启动时会创建Filter实例,并且每个类型的Filter只创建一个实例,从此不再创建!在创建完Filter实例后,会马上调用init()方法完成初始化工作,这个方法只会被执行一次;
  • doFilter(ServletRequest req,ServletResponse res,FilterChain chain):这个方法会在用户每次访问“目标资源(<url->pattern>index.jsp</url-pattern>)”时执行,如果需要“放行”,那么需要调用FilterChain的doFilter(ServletRequest,ServletResponse)方法,如果不调用FilterChain的doFilter()方法,那么目标资源将无法执行;
  •  destroy():服务器会在创建Filter对象之后,把Filter放到缓存中一直使用,通常不会销毁它。一般会在服务器关闭时销毁Filter对象,在销毁Filter对象之前,服务器会调用Filter对象的destory()方法

 

四种拦截方式

我们来做个测试,写一个过滤器,指定过滤的资源为b.jsp,然后我们在浏览器中直接访问b.jsp,你会发现过滤器执行了!

但是,当我们在a.jsp中request.getRequestDispathcer(“/b.jsp”).forward(request,response)时,就不会再执行过滤器了!也就是说,默认情况下,只能直接访问目标资源才会执行过滤器,而forward执行目标资源,不会执行过滤器

其实过滤器有四种拦截方式!分别是:REQUEST、FORWARD、INCLUDE、ERROR。

  • REQUEST:直接访问目标资源时执行过滤器。包括:在地址栏中直接访问、表单提交、超链接、重定向,只要在地址栏中可以看到目标资源的路径,就是REQUEST;
  • FORWARD:转发访问执行过滤器。包括RequestDispatcher#forward()方法、<jsp:forward>标签都是转发访问;
  • INCLUDE:包含访问执行过滤器。包括RequestDispatcher#include()方法、<jsp:include>标签都是包含访问;
  • ERROR:当目标资源在web.xml中配置为<error-page>中时,并且真的出现了异常,转发到目标资源时,会执行过滤器

 

可以在<filter-mapping>中添加0~n个<dispatcher>子元素,来说明当前访问的拦截方式:

    <filter-mapping>        <filter-name>myfilter</filter-name>        <url-pattern>/b.jsp</url-pattern>        <dispatcher>REQUEST</dispatcher>        <dispatcher>FORWARD</dispatcher>    </filter-mapping>

当没有给出拦截方式时,那么默认为REQUEST,其实最为常用的就是REQUEST和FORWARD两种拦截方式,而INCLUDE和ERROR都比较少用

我们可以使用拦截器实现一个错误转跳的功能,但发生错误就转跳到一个错误页面:

    <filter-mapping>        <filter-name>myfilter</filter-name>        <url-pattern>/b.jsp</url-pattern>        <dispatcher>ERROR</dispatcher>    </filter-mapping>    <error-page>        <error-code>500</error-code>        <location>/b.jsp</location>    </error-page>

我们就可以在b.jsp中编写一个错误提示页面,或者是做一些其他操作

 

过滤器的应用场景

  •  执行目标资源之前做预处理工作,例如设置编码,这种处理通常都会放行,只是在目标资源执行之前做一些准备工作
  • 通过条件判断是否放行,例如校验当前用户是否已经登录,或者用户IP是否已经被禁用;
  • 进行权限控制

最后我们再来看看Filter在SSH整合中的使用:

当然是Struts2的使用啦:

    <filter>      <filter-name>struts2</filter-name>      <filter-class>          org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter      </filter-class>  </filter>  <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>  </filter-mapping>

StrutPrepareAndExecuteFilter这个拦截器的作用就是拦截所有请求

 

监听器和拦截器复习