Filter与Listener(过滤器与监听器)

1.Filter

1.过滤器概述

过滤器——Filter,它是JavaWeb三大组件之一。另外两个是Servlet和Listener

它可以对web应用中的所有资源进行拦截,并且在拦截之后进行一些特殊的操作

在程序中访问服务器资源时,当一个请求到来,服务器首先判断是否有过滤器与请求资源相关联,如果有,过滤器可以将请求拦截下来,完成一些特定的功能,再由过滤器决定是否交给请求资源。如果没有则像之前那样直接请求资源了。响应也是类似的

过滤器一般用于完成通用的操作,例如:登录验证、统一编码处理、敏感字符过滤等

2.Filter概述

Filter 是一个接口,如果想实现过滤器的功能,必须实现该接口

核心方法

返回值方法名作用
voidinit(FilterConfig config)初始化方法
voiddoFilter(ServletRequest req,ServletResponse resp,FilterChain chain)对请求资源和响应资源过滤
voiddestory()销毁方法

 配置方式

        注解方式

        配置文件 

3.FilterChain

 FilterChain 是一个接口,代表过滤器链对象。由 Servlet 容器提供实现类对象,直接使用即可。

 过滤器可以定义多个,就会组成过滤

核心方法

返回值方法名作用
voiddoFilter(ServletRequest req,ServletResponse resp)放行方法

如果有多个过滤器,在第一个过滤器中调用下个过滤器,依次类推。直到到达最终访问资源

如果只有一个过滤器,放行时,就会直接到达最终访问资源

  

4.过滤器的使用 

需求说明

通过Filter过滤器解决多个资源写出中文乱码的问题

实现步骤

1.创建一个web项目

2.创建两个Servlet功能类,都向客户端写出中文数据

3.创建一个Filter过滤器实现类,重写doFilter核心方法

4.在方法内部解决中文乱码,并放行

5.部署并启动项目

6.通过浏览器测试

package filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/*
    过滤器基本使用
*/
@WebFilter("/*")
public class FilterDemo01 implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filterDemo01执行了...");
        //处理乱码
        servletResponse.setContentType("text/html;charset=UTF-8");
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
    }
}

5.过滤器的使用细节

配置方式

         注解方式 @WebFilter(拦截路径)

         配置文件

<filter>
    <filter-name>filterDemo01</filter-name>
    <filter-class>filter.FilterDemo01</filter-class>
</filter>
<filter-mapping>
    <filter-name>filterDemo01</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

 多个过滤器使用顺序

如果有多个过滤器,取决于过滤器映射的顺序

也就是filter-mapping配置的先后顺序

6.过滤器的生命周期

 创建(出生)

当应用加载时实例化对象并执行 init 初始化方法

 服务(活着)

对象提供服务的过程,执行 doFilter 方法
​​​​​

只要应用一直提供服务,对象就一直存在

 销毁(死亡)

当应用卸载时或服务器停止时对象销毁。执行 destroy

Filter的实例对象在内存中也只有一份。所以也是单例的

package filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/*")
public class FilterDemo03 implements Filter {
    //初始化方法
    @Override
    public void init(FilterConfig filterConfig) {
        System.out.println("对象初始化成功了...");
    }

    //提供服务方法
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filterDemo03执行了...");
        //处理乱码
        servletResponse.setContentType("text/html;charset=UTF-8");
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
    }

    //对象销毁
    @Override
    public void destroy() {
        System.out.println("对象销毁了...");
    }
}

 web.xml

<filter>
        <filter-name>filterDemo03</filter-name>
        <filter-class>filter.FilterDemo03</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filterDemo03</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

7.FilterConfig过滤器配置对象

FilterConfig 是一个接口。代表过滤器的配置对象,可以加载一些初始化参数。与ServletConfig类似

核心方法

返回值方法名作用
StringgetFilterName()获取过滤器对象名称
StringgetInitParameter(String key)根据key过去value
EnumerationgetInitParameterNames()获所有参数的key
ServletContextgetServletContext()获取应用上下文对象
package filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/*")
public class FilterDemo04 implements Filter {
    //初始化方法
    @Override
    public void init(FilterConfig filterConfig) {

        System.out.println("对象初始化成功了...");
        //获取过滤器名称
        String filterName = filterConfig.getFilterName();
        System.out.println(filterName);
        //根据name获取value
        String username = filterConfig.getInitParameter("username");
        System.out.println(username);
    }

    //提供服务方法
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filterDemo04执行了...");
        //处理乱码
        servletResponse.setContentType("text/html;charset=UTF-8");
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
    }

    //对象销毁
    @Override
    public void destroy() {
        System.out.println("对象销毁了...");
    }
}

web.xml

 <filter>
        <filter-name>filterDemo04</filter-name>
        <filter-class>filter.FilterDemo04</filter-class>
        <init-param>
            <param-name>username</param-name>
            <param-value>zhangsan</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>filterDemo04</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

8.过滤器五种拦截行为 

Filter 过滤器默认拦截的是请求,但是在实际开发中,我们还有请求转发和请求包含,以及由服务器触发调用的全局错误页面。默认情况下过滤器是不参与过滤的,要想使用,就需要我们配置

<filter>
    <filter-name>filterDemo05</filter-name>
    <filter-class>Filter.FilterDemo5</filter-class>
    <!--配置开启异步支持,当dispatcher配置ASYNC时,需要配置此行-->
    <async-supported>true</async-supported>
</filter>
<filter-mapping>
    <filter-name>filterDemo05</filter-name>
    <url-pattern>/index.jsp</url-pattern>
    <!--过滤请求:默认值。-->
    <dispatcher>REQUEST</dispatcher>
    <!--过滤全局错误页面:当由服务器调用全局错误页面时,过滤器工作-->
    <dispatcher>ERROR</dispatcher>
    <!--过滤请求转发:当请求转发时,过滤器工作。-->
    <dispatcher>FORWARD</dispatcher>
    <!--过滤请求包含:当请求包含时,过滤器工作。它只能过滤动态包含,jsp的include指令是静态包含,过滤器不会起作用-->
    <dispatcher>INCLUDE</dispatcher>
    <!--过滤异步类型,它要求我们在filter标签中配置开启异步支持-->
    <dispatcher>ASYNC</dispatcher>
</filter-mapping>

2.Listener 

1.监听器概述

观察者设计模式,所有的监听器都是基于观察者设计模式的

三个组成部分

事件源:触发事件的对象。

事件:触发的动作,里面封装了事件源。

监听器:当事件源触发事件时,要做的事情。一般是一个接口,由使用者来实现。

监听器:

在程序当中,我们可以对:对象的创建销毁、域对象中属性的变化、会话相关内容进行监听

Servlet 规范中共计 8 个监听器,监听器都是以接口形式提供,具体功能需要我们自己来完成

2.监听对象的监听器

1.ServletContextListener:用于监听 ServletContext 对象的创建和销毁

核心方法

返回值方法名作用
voidcontextInitialized(ServletContextEvent sce)对象创建时执行该方法
voidcontextDestroyed(ServletContextEvent sce)对象销毁时执行该方法

参数:ServletContextEvent 代表事件对象

事件对象中封装了事件源,也就是 ServletContext

真正的事件指的是创建或销毁 ServletContext 对象的操作

2.HttpSessionListener:用于监听 HttpSession 对象的创建和销毁

核心方法

返回值方法名作用
voidsessionCreated(HttpSessionEvent se)对象创建时执行该方法
voidsessionDestroyed(HttpSessionEvent se)对象销毁时执行该方法

参数:HttpSessionEvent 代表事件对象

事件对象中封装了事件源,也就是 HttpSession

真正的事件指的是创建或销毁 HttpSession 对象的操作

3.ServletRequestListener:用于监听 ServletRequest 对象的创建和销毁

核心方法

返回值方法名作用
voidrequestInitialized(ServletRequestEvent sre)对象创建时执行该方法
voidrequestDestroyed(ServletRequestEvent sre)对象销毁时执行该方法

参数:ServletRequestEvent 代表事件对象

事件对象中封装了事件源,也就是 ServletRequest

真正的事件指的是创建或销毁 ServletRequest 对象的操作

3.监听域对象属性变化的监听器

1.ServletContextAttributeListener:用于监听 ServletContext 应用域中属性的变化

核心方法

返回值方法名作用
voidattributeAdded(ServletContextAttributeEvent scae)域中添加属性时执行该方法
voidattributeRemoved(ServletContextAttributeEvent scae)域中移除属性时执行该方法
voidattributeReplaced(ServletContextAttributeEvent scae)域中替换属性时执行该方法

参数:ServletContextAttributeEvent 代表事件对象

事件对象中封装了事件源,也就是 ServletContext

真正的事件指的是添加、移除、替换应用域中属性的操作

2.HttpSessionAttributeListener:用于监听 HttpSession 会话域中属性的变化

核心方法

返回值方法名作用
voidattributeAdded(ServletSessionBindingEvent se)域中添加属性时执行该方法
voidattributeRemoved(ServletSessionBindingEvent se)域中移除属性时执行该方法
voidattributeReplaced(ServletSessionBindingEvent se)域中替换属性时执行该方法

参数:HttpSessionBindingEvent 代表事件对象

事件对象中封装了事件源,也就是 HttpSession

真正的事件指的是添加、移除、替换会话域中属性的操作

3.ServletRequestAttributeListener:用于监听 ServletRequest 请求域中属性的变化

核心方法

返回值方法名作用
voidattributeAdded(ServletRequestAttributeEvent srae)域中添加属性时执行该方法
voidattributeRemoved(ServletRequestAttributeEvent srae)域中移除属性时执行该方法
voidattributeReplaced(ServletRequestAttributeEvent srae)域中替换属性时执行该方法

参数:ServletRequestAttributeEvent 代表事件对象

事件对象中封装了事件源,也就是 ServletRequest

真正的事件指的是添加、移除、替换请求域中属性的操作

4.监听会话相关的感知性监听器

1.HttpSessionBindingListener:用于感知对象和会话域绑定的监听器

核心方法

返回值方法名作用
voidvalueBound(HttpSessionBindingEvent event)数据添加到会话域中(绑定时)执行该方法
voidvalueUnbound(HttpSessionBindingEvent event)数据从会话域中移除(解绑时)执行该方法

参数:HttpSessionBindingEvent 代表事件对象

事件对象中封装了事件源,也就是 HttpSession

真正的事件指的是添加、移除会话域中数据的操作

2.HttpSessionActivationListener:用于感知会话域中对象钝化和活化的监听器

核心方法

返回值方法名作用
voidsessionWillPassivate(HttpSessionEvent se)会话域中数据钝化时执行该方法
voidsessionDidActivate(HttpSessionEvent se)会话域中数据活化时执行该方法

参数:HttpSessionEvent 代表事件对象

事件对象中封装了事件源,也就是 HttpSession

真正的事件指的是会话域中数据钝化、活化的操作

5.监听器的使用

在实际开发中,我们可以根据具体情况来从这8个监听器中选择使用

感知型监听器由于无需配置,只需要根据实际需求编写代码

ServletContextListener

package listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/*
    ServletContext对象的创建和销毁的监听器
    //配置监听器:@WebListener
 */
@WebListener
public class ServletContextListenerDemo implements ServletContextListener {
    /*
        ServletContext对象创建的时候执行此方法
     */
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("监听到了对象的创建...");

        //获取对象
        ServletContext servletContext = sce.getServletContext();
        System.out.println(servletContext);

    }

    /*
        ServletContext对象销毁的时候执行此方法
     */
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("监听到了对象的销毁...");
    }
}

ServletContextAttributeListener

package listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;

/*
    应用域对象中的属性变化的监听器
 */
@WebListener
public class ServletContextAttributeListenerDemo implements ServletContextAttributeListener {
    /*
        向应用域对象中添加属性时执行此方法
     */
    @Override
    public void attributeAdded(ServletContextAttributeEvent scae) {
        System.out.println("监听到了属性的添加...");

        //获取应用域对象
        ServletContext servletContext = scae.getServletContext();
        //获取属性
        Object value = servletContext.getAttribute("username");
        System.out.println(value);
    }

    /*
        向应用域对象中替换属性时执行此方法
     */
    @Override
    public void attributeReplaced(ServletContextAttributeEvent scae) {
        System.out.println("监听到了属性的替换...");

        //获取应用域对象
        ServletContext servletContext = scae.getServletContext();
        //获取属性
        Object value = servletContext.getAttribute("username");
        System.out.println(value);
    }

    /*
        向应用域对象中移除属性时执行此方法
     */
    @Override
    public void attributeRemoved(ServletContextAttributeEvent scae) {
        System.out.println("监听到了属性的移除...");

        //获取应用域对象
        ServletContext servletContext = scae.getServletContext();
        //获取属性
        Object value = servletContext.getAttribute("username");
        System.out.println(value);
    }
}

修改ServletContextListenerDemo:在contextInitialized中增加

//添加属性
servletContext.setAttribute("username","zhangsan");

//替换属性
servletContext.setAttribute("username","lisi");

//移除属性
servletContext.removeAttribute("username");

 

用配置文件方式(第一种为注解方式)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--配置监听器-->
    <listener>
        <listener-class>listener.ServletContextListenerDemo</listener-class>
    </listener>
    <listener>
        <listener-class>listener.ServletContextAttributeListenerDemo</listener-class>
    </listener>
</web-app>