Filter(过滤器)&Listener(监听器)总结

一、Filter

1、简介

Filter中文意思为过滤器。顾名思义,过滤器可在浏览器以及目标资源之间起到一个过滤的作用。

1.1 生活中的过滤器
  • 水龙头过滤器
    • 水净化器,可以看成是生活中的一个过滤器,他可以将污水中的杂质过滤,从而使进入的污水变成净水。
  • 空气净化器
  • 吸烟过滤嘴
1.2 程序中的过滤器
  1. 对于WEB应用来说,过滤器是一个驻留在服务器中的WEB组件,他可以截取客户端和WEB资源之间的请求和响应信息。

  2. WEB资源可能包括Servlet、JSP、HTML页面等
    在这里插入图片描述

  3. 当服务器收到特定的请求后,会先将请求交给过滤器,程序员可以在过滤器中对请求信息进行读取修改等操作,然后将请求信息再发送给目标资源。目标资源作出响应后,服务器会再次将响应转交给过滤器,在过滤器中同样可以对响应信息做一些操作,然后再将响应发送给服务器。也就是说过滤器可以在WEB资源收到请求之前,浏览器收到响应之前,对请求和响应信息做一些相应的操作。

  4. 在一个WEB应用中可以部署多个过滤器,多个过滤器就组成了一个过滤器链,请求和响应必须在经过多个过滤器后才能到达目标;

在这里插入图片描述

  1. 过滤器不是必须将请求传送到下一个过滤器(或WEB资源),也可以自己来处理请求,发送响应。

2、相关接口

2.1 Filter接口

编写Filter和编写Servlet类似,都需要实现接口。

编写Filter需要实现Filter接口,我们来看一下Filter接口的主要方法:

在这里插入图片描述

Filter接口,实现Filter需要实现该接口

  • init()方法用于初始化Filter

  • doFilter()作用和service()方法类似,是过滤请求和响应的主要方法。

  • destroy()用于在Filter对象被销毁前做一些收尾工作。如:释放资源等。

2.2 FilterConfig接口

FilterConfig对象在服务器调用init()方法时传递进来。

  1. getFilterName() 获取Filter的名字

  2. getServletContext() 获取ServletContext对象(即application)

  3. getInitParameter() 获取Filter的初始化参数

  4. getInitParameterNames() 获取所有初始化参数的名字

在这里插入图片描述

2.3 FilterChain接口

FilterChain对象是在doFilter()方法被调用时作为参数传递进来的。

  1. doFilter()方法用于调用Filter链上的下一个过滤器,如果当前过滤器为最后一个过滤器则将请求发送到目标资源。

在这里插入图片描述

3、使用

作用:

​ 请求&响应之前需要解决的问题,放到Filter中处理。

3.1 实现Filter接口
public class HelloFilter implements Filter {
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		System.out.println("Hello Filter");
	}

	@Override
	public void destroy() {
	}
}

3.2 在web.xml中进行注册
	<filter>
		<filter-name>HelloFilter</filter-name>
		<filter-class>com.atguigu.web.filter.HelloFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>HelloFilter</filter-name>
		<url-pattern>/index.html</url-pattern>
	</filter-mapping>

  • 我们编写的这个Filter用来过滤发送到index.html的请求。
  • 在doFilter()方法中我们只写了一个打印语句,并没有将请求转交给目标资源处理。
  • 所以这个过滤器的效果是我们将不能正常查看到index.html页面,在访问index.html时页面上将会是一片空白。同时,控制台将输出Hello Filter。
  • 如果想要index.html正确显示,需要在输出语句后,调用一个chain.doFilter(request, response)将请求放行。
  • Filter的配置文件和Servlet的配置文件类似
    • filter-name 指定的是过滤器的名字
    • filter-class 指定的是过滤器的全类名
    • url-pattern 指定的是需要过滤器处理的请求地址
  • 除此之外在filter-mapping还有一个子标签dispatcher,该标签用来指定需要Filter处理的请求类型,该标签可以配置四个值:
  • REQUEST
  • 用户直接访问资源时,会调用Filter
  • FORWARD
  • 通过转发访问时,会调用Filter
  • INCLUDE
  • 通过动态包含获取时,会调用Filter
  • ERROR
  • 当通过异常处理访问页面时,会调用Filter
  • 这四种情况可以设置一个,也可以同时设置多个,如果不设置那么默认为REQUEST。

4、Filter生命周期

4.1 细化说
* 构造器
	* 执行时机:启动服务器时执行。
	* 执行次数 :在整个生命周期中,执行一次。
* init()
	* 执行时机:启动服务器时执行。(在构造器之后)
	* 执行次数 :在整个生命周期中,执行一次。
* doFilter()
	* 执行时机:过滤的目标请求,被触发(请求)时执行。
	* 执行次数:在整个生命周期中,执行多次。
* destroy()
	* 执行时机:关闭服务器时执行。
	* 执行次数:在整个生命周期中执行一次。
4.2 广义说

启动服务器时创建过滤器,并调用init()方法初始化(FilterConfig,requset,response等参数)浏览器发送请求,调用doFilter()方法,过滤请求(项目需求),放行。执行web资源,做出响应(不会立刻响应)。先执行放行后的代码(过滤响应),执行响应。

5、Filter工作原理(执行流程)

  1. 浏览器(客户端)请求
    2. 执行Filter中doFilter(),过滤请求(项目需求)
    3. 放行请求,chain.doFilter()。让请求执行下一个资源。
    4. 执行Servlet中的service()处理请求,做出响应。(不会立刻响应)
    5. 执行放行后的代码,过滤响应(项目需求)
    6. 响应。

6、多个Filter的执行顺序

  1. 请求
    2. 执行Filter1放行前,过滤请求,放行。
    3. 执行Filter2放行前,过滤请求,放行。
    4. 执行目标资源(Servlet),处理请求,并做出响应。(不会立刻响应)
    5. 执行Filter2放行后,过滤响应。
    6. 执行Filter1放行后,过滤响应。
    7. 响应

注意

​ Filter的先后顺序由web.xml中的Url顺序决定

​ /TargetServlet

7、URL配置规则

* Url配置规则大体分为以下两种情况
	1. 精准配置
		* <url-pattern>/TargetServlet</url-pattern>
		* <servlet-name>TargetServlet</servlet-name>(了解)
	2. 模糊配置  
		* 什么是模糊配置,包含“*”的Url,称之为模糊配置。
			* 前置模糊:以“*”开头的Url
				* eg:<url-pattern>*.jsp</url-pattern> 
			* 后置模糊:以“*”结尾的Url
				* <url-pattern>/pages/*</url-pattern>
		/** 注意:"*"不能放到中间位置,没有中置模糊。 */
* 扩展Servlet中Url配置
	* 支持模糊配置
	* <url-pattern>/</url-pattern> 	
		* 所有的Servlet,(不包括jsp文件)。
	* <url-pattern>/*</url-pattern> 
    	*所有的Servlet,包括jsp文件

8、手写(自定义)HttpFilter

自定义HttpFilter步骤(和实现HTTPServlet的实现过程一致,只是一步到位)

1. 提供getFilterConfig()&getServletContext()
    
2. public abstract void doFilter(HttpServletRequest req,HttpServletResponse res,FilterChain chain); 

3. public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain){
HttpServletRequest req = (HttpServletRequest)request;
						HttpServletResponse res = (HttpServletResponse)response;
						this.doFilter(req,res,chain);
}

示例:

public abstract class HttpFilter implements Filter {

	private FilterConfig filterConfig;
	
    public HttpFilter() {
       
    }

	public void destroy() {
		
	}
	//抽象化doFilter方法
	public abstract void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException;
	//强转ServletRequest, ServletResponse
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest)request;
		HttpServletResponse res = (HttpServletResponse)response;
		this.doFilter(req,res,chain);
	}

    //初始化FilterConfig
	public void init(FilterConfig fConfig) throws ServletException {
		filterConfig = fConfig;
	}

	/**
	 * 获取FilterConfig对象
	 * @return
	 */
	public FilterConfig getFilterConfig() {
		return filterConfig;
	}
	
	/**
	 * 获取ServletContext对象
	 * @return
	 */
	public ServletContext getServletContext() {
		return filterConfig.getServletContext();
	}
	
	
}

二、Listener

1、简介

  • Listener用于监听JavaWeb程序中的事件。
    • 例如:ServletContext、HttpSession、ServletRequest的创建、修改和删除。
  • Listener和我们之前学习的JS中的事件处理机制类似。在JS中,当我们触发某个事件后(例如:点击一个按钮)程序会调用一个响应函数来处理事件。同样的,在JavaWeb中,我们可以为某些事件来设置监听器,当事件被触发时,监听器中的指定方法将会被调用。

2、观察者模式

  • Listener的原理是基于观察者模式的,所谓观察者模式简单来说,就是当被观察者的特定事件被触发(一般这某些方法被调用)后,会通知观察者(调用观察者的方法),观察者可以在自己的方法中来对事件做一些处理。

  • 在我们的JavaWeb中,观察者就是Listener,而被观察者可能有三个ServletContext、HttpSession、ServletRequest。而事件指的就是这些对象的创建、修改和删除等。

3、监听器的分类

3.1 监听对象的创建与销毁
(1) ServletContextListener
  • 作用:监听ServletContext对象的创建与销毁

  • 方法:

  • public void contextInitialized ( ServletContextEvent sce );

    • ServletContext创建时调用
  • public void contextDestroyed ( ServletContextEvent sce );

    • ServletContext销毁时调用
  • ServletContextEvent对象

  • 作用:public ServletContext getServletContext ()

    • 获取ServletContext对象
(2) HttpSessionListener
  • 作用:监听HttpSession对象的创建与销毁

  • 方法:

  • public void sessionCreated ( HttpSessionEvent se );

    • HttpSession对象创建时调用
  • public void sessionDestroyed ( HttpSessionEvent se );

    • HttpSession对象销毁时调用
  • HttpSessionEvent对象

  • 作用:public HttpSession getSession ()

    • 获取当前HttpSession对象
(3) ServletRequestListener
  • 作用:监听ServletRequest对象的创建与销毁

  • 方法:

  • public void requestInitialized ( ServletRequestEvent sre );

    • ServletRequest对象创建时调用
  • public void requestDestroyed ( ServletRequestEvent sre );

    • ServletRequest对象销毁时调用
  • ServletRequestEvent对象

  • 作用:

    • public ServletRequest getServletRequest ();
      • 获取当前的ServletRequest对象。
    • public ServletContext getServletContext ();
      • 获取当前项目的ServletContext对象。
(4) 创建与销毁监听器的使用
  • 三种创建与销毁的监听器使用起来基本一致。

  • 下边来编写一个ServletContext的监听器:

    • 步骤:

      • 创建一个类实现ServletContextListener

        public class MyServletContextListener implements ServletContextListener {
        	@Override
        	public void contextInitialized(ServletContextEvent sce) {
        		System.out.println("哈哈,我是ServletContext,我出生了");
        	}
        	@Override
        	public void contextDestroyed(ServletContextEvent sce) {
        		System.out.println("~~~~(>_<)~~~~,我是ServletContext,我要死了");	
        	}
        }
        
        
      • 在web.xml文件中注册监听器

        <listener>
        	<listener-class>
        		com.atguigu.web.listener.MyServletContextListener
        	</listener-class>
        </listener>
        
        
    • 由于ServletContext对象在服务器启动时创建,停止时销毁。所以启动服务器时我们会发现contextInitialized()方法被调用,服务器停止时contextDestroyed()方法被调用。

    • 其他两个监听器和该监听器使用方法一样,不再多说。

3.2 监听对象的属性变化
(1)ServletContextAttributeListener
  • 作用:监听ServletContext中属性的创建、修改和销毁

  • 方法:

  • public void attributeAdded(ServletContextAttributeEvent scab);

    • 向ServletContext中添加属性时调用
  • public void attributeRemoved(ServletContextAttributeEvent scab);

  • 从ServletContext中移除属性时调用

  • public void attributeReplaced(ServletContextAttributeEvent scab);

    • 当ServletContext中的属性被修改时调用
  • ServletContextAttributeEvent对象

  • 作用:

    • public String getName()
      • 获取修改或添加的属性名
    • public Object getValue()
      • 获取被修改或添加的属性值
    • public ServletContext getServletContext ()
      • 获取当前WEB应用的ServletContext对象
(2)HttpSessionAttributeListener
  • 作用:监听HttpSession中属性的创建、修改和销毁

  • 方法:

  • public void attributeAdded ( HttpSessionBindingEvent se );

    • 向HttpSession中添加属性时调用
  • public void attributeRemoved(HttpSessionBindingEvent se);

    • 从HttpSession中移除属性时调用
  • public void attributeReplaced(HttpSessionBindingEvent se);

    • 当HttpSession中的属性被修改时调用
  • HttpSessionBindingEvent对象

  • 作用:

    • public String getName()
      • 获取修改或添加的属性名
    • public Object getValue()
      • 获取被修改或添加的属性值
    • public HttpSession getSession ()
      • 获取当前的HttpSession对象
(3)ServletRequestAttributeListener
  • 作用:监听ServletRequest中属性的创建、修改和销毁

  • 方法:

  • public void attributeAdded (ServletRequestAttributeEvent srae );

  • 向ServletRequest中添加属性时调用

  • public void attributeRemoved(ServletRequestAttributeEvent srae);

    • 从ServletRequest中移除属性时调用
  • public void attributeReplaced(ServletRequestAttributeEvent srae);

    • 当ServletRequest中的属性被修改时调用
  • ServletRequestAttributeEvent对象

  • 作用:

    • public String getName()
      • 获取修改或添加的属性名
    • public Object getValue()
      • 获取被修改或添加的属性值
    • public ServletRequest getServletRequest ()
      • 获取当前的ServletRequest对象
(4) 对象属性变化监听器的使用

同样三种对象属性变化监听器使用方式类似,下边以request属性监听器为例。

  • 创建一个类实现ServletRequestAttributeListener接口

    public class ReqAttrListener implements ServletRequestAttributeListener {
    	@Override
    	public void attributeAdded(ServletRequestAttributeEvent srae) {
    		System.out.println("request域中添加一个属性"+srae.getName()+"="+srae.getValue());
    	}
    	@Override
    	public void attributeRemoved(ServletRequestAttributeEvent srae) {
    		System.out.println("request域中移除一个属性"+srae.getName()+"="+srae.getValue());
    	}
    	@Override
    	public void attributeReplaced(ServletRequestAttributeEvent srae) {
    		System.out.println("request域中一个属性被修改了"+srae.getName()+"="+srae.getValue());
    	}
    
    }
    
    
  • 在web.xml文件中注册监听器

    <listener>
    		<listener-class>
    			com.atguigu.web.listener.ReqAttrListener
    		</listener-class>
    </listener>
    
    

如此当我们操作request域中的属性时,对应方法将会被调用。

3.3 监听session内的对象
(1) HttpSessionBindingListener
  • 作用:监听某个对象在session域中的创建与移除。

  • 方法:

  • public void valueBound(HttpSessionBindingEvent event)

    • 该类的实例被放到Session域中时调用
  • public void valueUnbound(HttpSessionBindingEvent event)

    • 该类的实例从Session中移除时调用
  • HttpSessionBindingEvent对象

  • 作用:

    • public HttpSession getSession ()
      • 获取HttpSession对象
    • public String getName()
      • 获取操作的属性名
    • public Object getValue()
      • 获取操作的属性值
(2) 使用:要监听哪一个类,直接使该类实现HttpSessionBindingListener接口即可。
public class Student implements HttpSessionBindingListener {
	@Override
	public void valueBound(HttpSessionBindingEvent event) {
		//doSomeThing
	}
	@Override
	public void valueUnbound(HttpSessionBindingEvent event) {
		//doSomeThing
	}
}

(3) HttpSessionActivationListener
  • 作用:监听某个对象在session中的序列化与反序列化。

  • 方法:

  • public void sessionWillPassivate(HttpSessionEvent se)

    • 该类实例和Session一起钝化到硬盘时调用
  • public void sessionDidActivate(HttpSessionEvent se)

    • 该类实例和Session一起活化到内存时调用
  • HttpSessionEvent对象

  • 作用:

    • public HttpSession getSession ()
      • 获取HttpSession对象
(4) 使用:要监听哪一个类,直接使该类实现HttpSessionActivationListener接口即可。
public class Student implements HttpSessionActivationListener , Serializable {
	private static final long serialVersionUID = 1L;
	@Override
	public void sessionWillPassivate(HttpSessionEvent se) {
		// TODO Auto-generated method stub
	}
	@Override
	public void sessionDidActivate(HttpSessionEvent se) {
		// TODO Auto-generated method stub
	}
}

注意:

这里为了是Student对象可以正常序列化到硬盘上,还需要让类实现java.io.Serializable接口

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值