Filter & Listener
文章目录
1、Filter:过滤器
1.1、概念
生活中的过滤器:净水器,空气净化器,“土匪”…
web 中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。
过滤器的作用:
- 一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤…
1.2、快速入门
- 步骤:
- 定义一个类,实现接口 Filter;
- 复写方法;
- 配置拦截路径:
- web.xml
- 注解
创建一个 FilterDemo1 类:
package com.example.day19_filter_listener.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* 过滤器快速入门
*/
@WebFilter("/*")//访问所有资源之前,都会执行该过滤器
public class FilterDemo1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void destroy() {
Filter.super.destroy();
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("FilterDemo1被执行了...");
}
}
访问 index.jsp:
可以发现:index.jsp 的内容无法显示,但是执行了 doFilter() 的方法。
在 doFilter() 的方法中添加 “放行” 方法:
//放行
filterChain.doFilter(servletRequest, servletResponse);
发现,可以展示 index.jsp 的内容了。
1.3、过滤器细节
1.3.1、web.xml 配置
修改 FilterDemo1:(注释掉注解和 “放行”)
package com.example.day19_filter_listener.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* 过滤器快速入门
*/
//@WebFilter("/*")//访问所有资源之前,都会执行该过滤器
public class FilterDemo1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void destroy() {
Filter.super.destroy();
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("FilterDemo1被执行了...");
//放行
//filterChain.doFilter(servletRequest, servletResponse);
}
}
配置 web.xml:
<?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">
<filter>
<filter-name>demo1</filter-name>
<filter-class>com.example.day19_filter_listener.filter.FilterDemo1</filter-class>
</filter>
<filter-mapping>
<filter-name>demo1</filter-name>
<!-- 拦截路径 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
再次访问 index.jsp:
1.3.2、过滤器执行流程
创建 FilterDemo2:
package com.example.day19_filter_listener.filter;
import javax.servlet.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebFilter("/*")
public class FilterDemo2 implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
//对request对象的请求消息增强
System.out.println("filterDemo2执行了...");
//放行
chain.doFilter(request, response);
//对response对象的响应消息的增强
System.out.println("filterDemo2回来了...");
}
}
修改 index.jsp:
<body>
index.jsp...
<%
System.out.println("index.jsp...");
%>
</body>
执行结果:
filterDemo2执行了...
index.jsp...
filterDemo2回来了...
可以看到,过滤器的执行流程如下:
- 执行过滤器;
- 执行 “放行” 后的资源;
- 回来执行过滤器放行代码下边的代码。
1.3.3、过滤器生命周期
- init:在服务器启动后,会创建 Filter 对象,然后调用 init 方法。只执行一次。用于加载资源;
- doFilter:每一次请求被拦截资源时,会执行。执行多次;
- destroy:在服务器关闭后,Filter 对象被销毁。如果服务器是正常关闭,则会执行 destroy 方法。只执行一次。用于释放资源。
创建 FilterDemo2:
package com.example.day19_filter_listener.filter;
import javax.servlet.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebFilter("/*")
public class FilterDemo3 implements Filter {
/**
* 在服务器启动后,会创建Filter对象,然后调用init方法,只执行一次
* 用于加载资源
* @param config
* @throws ServletException
*/
public void init(FilterConfig config) throws ServletException {
System.out.println("init...");
}
/**
* 在服务器关闭后,Filter对象被销毁,如果服务器是正常关闭,则会执行destroy方法,只执行一次
* 用于释放资源
*/
public void destroy() {
System.out.println("destory...");
}
/**
* 每一次请求被拦截资源时,会执行,执行多次
* @param request
* @param response
* @param chain
* @throws ServletException
* @throws IOException
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
System.out.println("doFilter...");
//放行
chain.doFilter(request, response);
}
}
1.3.4、过滤器配置详解
-
拦截路径配置:
- 具体资源路径:/index.jsp 只有访问 index.jsp 资源时,过滤器才会被执行;
- 拦截目录:/user/* 访问 /user下的所有资源时,过滤器都会被执行;
- 后缀名拦截:*.jsp 访问所有后缀名为 jsp 资源时,过滤器都会被执行;
- 拦截所有资源:/* 访问所有资源时,过滤器都会被执行。
-
拦截方式配置:资源被访问的方式
-
注解配置:
设置:设置 dispatcherTypes 属性
- REQUEST:默认值。浏览器直接请求资源;
- FORWARD:转发访问资源;
- INCLUDE:包含访问资源;
- ERROR:错误跳转资源;
- ASYNC:异步访问资源。
创建 FilterDemo5:(演示 dispatcherTypes = DispatcherType.REQUEST,其他参数同理)
package com.example.day19_filter_listener.filter; import javax.servlet.*; import javax.servlet.annotation.*; import java.io.IOException; //浏览器直接请求index.jsp资源时,过滤器会被执行 @WebFilter(value = "/index.jsp", dispatcherTypes = DispatcherType.REQUEST) public class FilterDemo5 implements Filter { public void init(FilterConfig config) throws ServletException { } public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { System.out.println("filterDemo5..."); //放行 chain.doFilter(request, response); } }
浏览器直接请求index.jsp资源时,过滤器会被执行。而浏览器转发到 index.jsp 时,不会被执行。我们再创建一个 ServletDemo2 转发到 index.jsp:
package com.example.day19_filter_listener.servlet; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; @WebServlet("/user/updateServlet") public class ServletDemo2 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("updateServlet"); //转到到index.jsp request.getRequestDispatcher("/index.jsp").forward(request, response); } }
我们使用浏览器直接访问 index.jsp:(过滤器被执行)
我们访问 updateServlet(转发到 index.jsp):(过滤器不会被执行)
同时,dispatcherTypes 属性也可以设置多个值:
//浏览器直接请求和转发请求index.jsp资源时,过滤器会被执行 @WebFilter(value = "/index.jsp", dispatcherTypes ={DispatcherType.REQUEST, DispatcherType.FORWARD})
-
web.xml 配置
设置
<dispatcher></dispatcher>
标签即可。
-
1.3.5、过滤器链(配置多个过滤器)
执行顺序:如果有两个过滤器:过滤器 1 和过滤器 2
- 过滤器 1
- 过滤器 2
- 资源执行
- 过滤器 2
- 过滤器 1
创建 FilterDemo6:
package com.example.day19_filter_listener.filter;
import javax.servlet.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebFilter("/*")
public class FilterDemo6 implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
System.out.println("filterDemo6执行了...");
//放行
chain.doFilter(request, response);
System.out.println("filterDemo6回来了...");
}
}
创建 FilterDemo7:
package com.example.day19_filter_listener.filter;
import javax.servlet.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebFilter("/*")
public class FilterDemo7 implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
System.out.println("filterDemo7执行了...");
//放行
chain.doFilter(request, response);
System.out.println("filterDemo7回来了...");
}
}
过滤器先后顺序问题:
-
注解配置:按照类名的字符串比较规则比较,值小的先执行
如: AFilter 和 BFilter,AFilter 就先执行了。
-
web.xml 配置:
<filter-mapping>
谁定义在上边,谁先执行
2、Listener
2.1、概念
web 的三大组件之一。
时间监听机制:
- 事件:一件事情
- 事件源:事件发生的地方
- 监听器:一个对象
- 注册监听:将事件、事件源、监听器绑定在一起。 当事件源上发生某个事件后,执行监听器代码
2.2、ServletContextListener
监听 ServletContext 对象的创建和销毁。
方法:
void contextDestroyed(ServletContextEvent sce)
:ServletContext 对象被销毁之前会调用该方法void contextInitialized(ServletContextEvent sce)
:ServletContext 对象创建后会调用该方法
步骤:
- 定义一个类,实现 ServletContextListener 接口
- 复写方法
- 配置
创建一个类 ContextLoaderListener 继承 ServletContextListener,复写其中的方法:
package com.example.day19_filter_listener.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ContextLoaderListener implements ServletContextListener {
/**
* 监听ServletContext对象创建。ServletContext对象服务器启动后自动创建
* 在服务器启动后自动调用
* @param sce
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext对象被创建了...");
ServletContextListener.super.contextInitialized(sce);
}
/**
* 在服务器关闭后,SevletContext对象被销毁。当服务器关闭后方法被调用
* @param sce
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext对象被销毁了...");
ServletContextListener.super.contextDestroyed(sce);
}
}
配置 web.xml:
<listener>
<listener-class>com.example.day19_filter_listener.listener.ContextLoaderListener</listener-class>
</listener>
启动服务器:
关闭服务器:
跟 Servlet 的生命周期很像!