Filter 简介
- Servlet 过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息。
- 可以将一个或多个 Servlet 过滤器附加到一个 Servlet 或一组 Servlet。Servlet 过滤器也可以附加到 JavaServer Pages (JSP) 文件和 HTML 页面。
- Servlet 过滤器是可用于 Servlet 编程的 Java 类,可以实现以下目的:
- 在客户端的请求访问后端资源之前,拦截这些请求。
- 在服务器的响应发送回客户端之前,处理这些响应。
Servlet 过滤器方法
过滤器是一个实现了 javax.servlet.Filter 接口的 Java 类。javax.servlet.Filter 接口定义了三个方法:
序号 | 方法 & 描述 |
---|---|
1 |
public void doFilter (ServletRequest, ServletResponse, FilterChain) 该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain用户访问后续过滤器。 |
2 |
public void init(FilterConfig filterConfig) web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。 |
3 |
public void destroy() Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。 |
快速入门
示例1
过滤器通过 Web 部署描述符(web.xml)中的 XML 标签来声明,然后映射到您的应用程序的部署描述符中的 Servlet 名称或 URL 模式。当 Web 容器启动 Web 应用程序时,它会为您在部署描述符中声明的每一个过滤器创建一个实例。Filter的执行顺序与在web.xml配置文件中的配置顺序一致,一般把Filter配置在所有的Servlet之前。
Input
web.xml
<filter>
<!-- 声明Filter名字 -->
<filter-name>demo01</filter-name>
<!-- 对应的Filter类全名 -->
<filter-class>my.stringbug.FilterDemo01</filter-class>
</filter>
<filter-mapping>
<!-- 对应声明的Filter名字 -->
<filter-name>demo01</filter-name>
<!-- 过滤器的过滤路径 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
FilterDemo01.java
public class FilterDemo01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("FilterDemo01 过滤器给执行了 ~~");
// 放行(假如没有放行,那么被该过滤器过滤的页面都不会有请求信息和响应信息)
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() { }
}
index.jsp
<body>
<h1>Demo 01 ~~~~~</h1>
</body>
Output
控制台
FilterDemo01 过滤器给执行了 ~~
浏览器页面
Demo 01 ~~~~~
示例2
使用注解的方式进行声明,映射到对应的应用程序的部署描述符中的 Servlet 名称或 URL 模式。
Input
FilterDemo02.java
// "/*" 访问所有资源之前,都会执行该过滤器
@WebFilter("/*")
public class FilterDemo02 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("FilterDemo02 过滤器给执行了 ~~");
// 放行(假如没有放行,那么被该过滤器过滤的页面都不会有请求信息和响应信息)
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() { }
}
index.jsp
<body>
<h1>Demo 02 ~~~~~</h1>
</body>
Output
控制台
FilterDemo02 过滤器给执行了 ~~
浏览器页面
Demo 02 ~~~~~
Filter 执行流程 & Filter 生命周期
Filter 执行流程
-
Filter 接口中有一个doFilter 方法,当咱们编写好 Filter,并配置对哪个 web 资源进行拦截后,web 服务器每次在调用 web 资源的 service 方法之前,都会先调用一下 Filter 的 doFilter 方法,因此,在该方法内编写代码可达到如下的:
- 调用目标资源之前,让一段代码执行;
- 是否调用目标资源,即是否让用户访问 web 资源;
- 调用目标资源之后,让一段代码执行。
-
web 服务器在调用 doFilter 方法时,会传递一个 filterChain 对象进来,filterChain 对象是 filter 接口中最重要的一个对象,它也提供了一个 doFilter 方法,开发人员可以根据需求决定是否调用此方法。如果调用该方法,则 web 服务器就会调用 web 资源的 service 方法,即 web 资源就会被访问;否则的话, web 资源就不会被访问。
Filter 生命周期
- init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源
- doFilter:每一次请求被拦截资源时,会执行。执行多次
- destroy:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源
Filter 配置说明
拦截路径配置
- 具体资源路径,如:
/index.jsp
- 拦截某个目录,如:
/directory1/directory2/*
- 后缀名拦截,如:
*.html
- 拦截所有资源,如:
/*
拦截方式配置
-
注解配置
属性 类型 说明 asyncSupported boolean 指定Filter是否支持异步模式 dispatcherTypes DispatcherType[ ] 指定Filter对哪种方式的请求进行过滤。
支持的属性:ASYNC、ERROR、FORWARD、INCLUDE、REQUEST;
默认过滤所有方式的请求filterName String Filter名称 initParams WebInitParam[ ] 配置参数 displayName String Filter显示名 servletNames String[ ] 指定对哪些Servlet进行过滤 urlPatterns/value String[ ] 两个属性作用相同,指定拦截的路径
-
web.xml配置
-
<filter>
指定一个过滤器。-
<filter-name>
用于为过滤器指定一个名字,该元素的内容不能为空。 -
<filter-class>
元素用于指定过滤器的完整的限定类名。 -
<init-param>
元素用于为过滤器指定初始化参数,它的子元素<param-name>
指定参数的名字,<param-value>
指定参数的值。 - 在过滤器中,可以使用
FilterConfig
接口对象来访问初始化参数。
-
-
<filter-mapping>
元素用于设置一个 Filter 所负责拦截的资源。- 一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
-
<filter-name>
子元素用于设置filter的注册名称。该值必须是在<filter>
元素中声明过的过滤器的名字 -
<url-pattern>
设置 filter 所拦截的请求路径(过滤器关联的URL样式)
-
<servlet-name>
指定过滤器所拦截的Servlet名称。 -
<dispatcher>
指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST
,INCLUDE
,FORWARD
和ERROR
之一,默认REQUEST
。用户可以设置多个<dispatcher>
子元素用来指定 Filter 对资源的多种调用方式进行拦截。-
<dispatcher>
子元素可以设置的值及其意义-
REQUEST
:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。 -
INCLUDE
:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。 -
FORWARD
:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。 -
ERROR
:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
-
-
-
过滤器链
有多个过滤器,过滤器的执行顺序和拦截顺序说明。
过滤器先后顺序问题
-
注解配置:按照类名的字符串比较规则比较,值小的先执行。
如: AFilter 和 BFilter,AFilter先执行。
-
web.xml配置:
谁定义在上边,谁先执行
过滤器执行顺序
如果有两个过滤器:过滤器1和过滤器2
过滤器1
@WebFilter(value = "/index.jsp")
public class FilterDemo04 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("小明通过过滤器1,去服务器了");
// Filter1 放行
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("小明通过过滤器1,从服务器回来了");
}
@Override
public void destroy() { }
}
过滤器2
@WebFilter(value = "/index.jsp")
public class FilterDemo05 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("小明通过过滤器2,去服务器了");
// Filter2 放行
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("小明通过过滤器2,从服务器回来了");
}
@Override
public void destroy() { }
}
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Filter And Listener Demo</title>
</head>
<body>
<% System.out.println("服务器资源被访问了"); %>
</body>
</html>
启动服务器,访问index.jsp资源,控制台输出:
小明通过过滤器1,去服务器了
小明通过过滤器2,去服务器了
服务器资源被访问了
小明通过过滤器2,从服务器回来了
小明通过过滤器1,从服务器回来了
Listener 学习笔记
简介
监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。监听器可以用来检测网站的在线人数,统计网站的访问量等
监听器涉及三个组件:事件源,事件对象,事件监听器
当事件源发生某个动作的时候,它会调用事件监听器的方法,并在调用事件监听器方法的时候把事件对象传递进去。
ServletContextListener
ServletContextListener:监听ServletContext对象的创建和销毁
void contextDestroyed(ServletContextEvent sce)
// ServletContext对象被销毁之前会调用该方法
void contextInitialized(ServletContextEvent sce)
// ServletContext对象创建后会调用该方法
快速入门
- 实现ServletContextListener接口
- 复写方法
- 配置(web.xml配置或注解配置)
实现ServletContextListener接口,复写方法
public class ContextLoaderListener implements ServletContextListener {
/**
* 监听ServletContext对象创建的。ServletContext对象在服务器启动后自动创建。
*/
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
// ServletContext对象创建后会调用该方法
System.out.println("ServletContext 对象被创建了");
}
/**
* 在服务器关闭后,ServletContext对象被销毁。当服务器正常关闭后,该方法会被执行。
*/
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
// ServletContext对象被销毁之前会调用该方法
System.out.println("ServletContext 对象被销毁了");
}
}
web.xml配置
<listener>
<listener-class>my.listener.ContextLoaderListener</listener-class>
</listener>
注解配置:在实现监听接口的方法上面添加注解
@WebListener("my/listener/contextLoaderListener")
正常的启动服务器,和关闭服务器:控制台输出
启动服务器
ServletContext 对象被创建了
关闭服务器
ServletContext 对象被销毁了