Filter与Listener(过滤器与监听器)
1.Filter
1.过滤器概述
过滤器——Filter,它是JavaWeb三大组件之一。另外两个是Servlet和Listener
它可以对web应用中的所有资源进行拦截,并且在拦截之后进行一些特殊的操作
在程序中访问服务器资源时,当一个请求到来,服务器首先判断是否有过滤器与请求资源相关联,如果有,过滤器可以将请求拦截下来,完成一些特定的功能,再由过滤器决定是否交给请求资源。如果没有则像之前那样直接请求资源了。响应也是类似的
过滤器一般用于完成通用的操作,例如:登录验证、统一编码处理、敏感字符过滤等
2.Filter概述
Filter 是一个接口,如果想实现过滤器的功能,必须实现该接口
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | init(FilterConfig config) | 初始化方法 |
void | doFilter(ServletRequest req,ServletResponse resp,FilterChain chain) | 对请求资源和响应资源过滤 |
void | destory() | 销毁方法 |
配置方式
注解方式
配置文件
3.FilterChain
FilterChain 是一个接口,代表过滤器链对象。由 Servlet 容器提供实现类对象,直接使用即可。
过滤器可以定义多个,就会组成过滤
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | doFilter(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类似
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
String | getFilterName() | 获取过滤器对象名称 |
String | getInitParameter(String key) | 根据key过去value |
Enumeration | getInitParameterNames() | 获所有参数的key |
ServletContext | getServletContext() | 获取应用上下文对象 |
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 对象的创建和销毁
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | contextInitialized(ServletContextEvent sce) | 对象创建时执行该方法 |
void | contextDestroyed(ServletContextEvent sce) | 对象销毁时执行该方法 |
参数:ServletContextEvent 代表事件对象
事件对象中封装了事件源,也就是 ServletContext
真正的事件指的是创建或销毁 ServletContext 对象的操作
2.HttpSessionListener:用于监听 HttpSession 对象的创建和销毁
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | sessionCreated(HttpSessionEvent se) | 对象创建时执行该方法 |
void | sessionDestroyed(HttpSessionEvent se) | 对象销毁时执行该方法 |
参数:HttpSessionEvent 代表事件对象
事件对象中封装了事件源,也就是 HttpSession
真正的事件指的是创建或销毁 HttpSession 对象的操作
3.ServletRequestListener:用于监听 ServletRequest 对象的创建和销毁
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | requestInitialized(ServletRequestEvent sre) | 对象创建时执行该方法 |
void | requestDestroyed(ServletRequestEvent sre) | 对象销毁时执行该方法 |
参数:ServletRequestEvent 代表事件对象
事件对象中封装了事件源,也就是 ServletRequest
真正的事件指的是创建或销毁 ServletRequest 对象的操作
3.监听域对象属性变化的监听器
1.ServletContextAttributeListener:用于监听 ServletContext 应用域中属性的变化
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | attributeAdded(ServletContextAttributeEvent scae) | 域中添加属性时执行该方法 |
void | attributeRemoved(ServletContextAttributeEvent scae) | 域中移除属性时执行该方法 |
void | attributeReplaced(ServletContextAttributeEvent scae) | 域中替换属性时执行该方法 |
参数:ServletContextAttributeEvent 代表事件对象
事件对象中封装了事件源,也就是 ServletContext
真正的事件指的是添加、移除、替换应用域中属性的操作
2.HttpSessionAttributeListener:用于监听 HttpSession 会话域中属性的变化
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | attributeAdded(ServletSessionBindingEvent se) | 域中添加属性时执行该方法 |
void | attributeRemoved(ServletSessionBindingEvent se) | 域中移除属性时执行该方法 |
void | attributeReplaced(ServletSessionBindingEvent se) | 域中替换属性时执行该方法 |
参数:HttpSessionBindingEvent 代表事件对象
事件对象中封装了事件源,也就是 HttpSession
真正的事件指的是添加、移除、替换会话域中属性的操作
3.ServletRequestAttributeListener:用于监听 ServletRequest 请求域中属性的变化
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | attributeAdded(ServletRequestAttributeEvent srae) | 域中添加属性时执行该方法 |
void | attributeRemoved(ServletRequestAttributeEvent srae) | 域中移除属性时执行该方法 |
void | attributeReplaced(ServletRequestAttributeEvent srae) | 域中替换属性时执行该方法 |
参数:ServletRequestAttributeEvent 代表事件对象
事件对象中封装了事件源,也就是 ServletRequest
真正的事件指的是添加、移除、替换请求域中属性的操作
4.监听会话相关的感知性监听器
1.HttpSessionBindingListener:用于感知对象和会话域绑定的监听器
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | valueBound(HttpSessionBindingEvent event) | 数据添加到会话域中(绑定时)执行该方法 |
void | valueUnbound(HttpSessionBindingEvent event) | 数据从会话域中移除(解绑时)执行该方法 |
参数:HttpSessionBindingEvent 代表事件对象
事件对象中封装了事件源,也就是 HttpSession
真正的事件指的是添加、移除会话域中数据的操作
2.HttpSessionActivationListener:用于感知会话域中对象钝化和活化的监听器
核心方法
返回值 | 方法名 | 作用 |
---|---|---|
void | sessionWillPassivate(HttpSessionEvent se) | 会话域中数据钝化时执行该方法 |
void | sessionDidActivate(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>