Filter&Listener
服务器端的三大组件
- Servlet:用来处理用户请求
- Filter:用来过滤用户请求
- Listener:用来监听ServletContext、HttpSession、ServletRequest的生命周期和属性变化
- 服务器端的三大组件都有以下特点:
- 都需要运行在服务器上
- 都需要实现某个接口
- 都需要在web.xml中注册
Filter简介
-
Filter翻译过来叫过滤器
-
过滤器的作用
- 请求到达目标资源之前拦截请求
- 放行请求
- 响应到达浏览器之前做一些其他的操作
-
创建Filter的HelloWorld的步骤:
- 1)创建一个类实现Filter接口
public class HelloFilter 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("你已经被我拦截……"); //如果符合条件,可以放行请求 filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { } }
- 2)在web.xml中注册实现类
<!--注册Filter--> <filter> <filter-name>HelloFilter</filter-name> <filter-class>com.atguigu.filter.HelloFilter</filter-class> </filter> <!--映射Filter--> <filter-mapping> <filter-name>HelloFilter</filter-name> <url-pattern>/index.jsp</url-pattern> </filter-mapping>
- 3)在浏览器中访问index.jsp时则会调用HelloFilter的doFilter方法来拦截请求
//拦截用户请求的方法 @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("你已经被我拦截……"); }
- 4)如果满足要求,可以在doFilter方法中通过filterChain.doFilter(request, response)放行请求
//拦截用户请求的方法 @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("你已经被我拦截……"); //如果符合条件,可以放行请求 filterChain.doFilter(servletRequest,servletResponse); }
Filter的生命周期
- 构造器
- 服务器一启动就被调用,说明服务器一启动就创建了Filter对象
- 在整个生命周期过程中只被调用一次,说明Filter也是单例的
- init()方法
- 服务器一启动就被调用,对Filter对象进行初始化
- 在整个生命周期过程中只被调用一次
- doFilter()方法
- 每次发送请求都会被调用,用来拦截请求在
- 整个生命周期过程中会被调用多次
- destory()方法
- 服务器关闭时被调用,用来销毁Filter对象
- 在整个生命周期过程中只被调用一次
public class LifeFilter implements Filter {
/*
启动服务器时被调用,说明Filter对象一启动服务器就被创建
在整个生命周期过程中只被调用一次,证明Filter对象也是单例的
*/
public LifeFilter() {
System.out.println("LifeFilter对象被创建");
}
/*
启动服务器时被调用,用来初始化LifeFilter对象
在整个生命周期过程中只被调用一次
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LifeFilter对象被初始化");
//filterConfig的作用
//1.获取当前Filter的名称
String filterName = filterConfig.getFilterName();
System.out.println(filterName);
//2.获取当前Filter的初始化参数
String user = filterConfig.getInitParameter("user");
System.out.println(user);
//3.获取ServletContext
ServletContext servletContext = filterConfig.getServletContext();
System.out.println(servletContext);
}
/*
向在url-pattern标签中配置的地址发送请求时被调用,用来拦截请求
整个生命周期过程中会被调用多次
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("LifeFilter对象正在拦截请求");
}
/*
关闭服务器时被调用,用来销毁对象
整个生命周期过程中只被调用一次
*/
@Override
public void destroy() {
System.out.println("LifeFilter对象被销毁");
}
}
多个Filter的拦截顺序
- 我们可以为同一个资源设置多个Filter,多个Filte组成一个Filter链,多个Filter的执行顺序由web.xml中的filter-mapping标签来决定,在前的先拦截,在后的后拦截;如果是通过注解的方式拦截请求,那么拦截的顺序由过滤器的名字(按A-Z的顺序)决定
<filter>
<filter-name>RobFilter</filter-name>
<filter-class>com.atguigu.filter.RobFilter</filter-class>
</filter>
<filter>
<filter-name>RobFilter2</filter-name>
<filter-class>com.atguigu.filter.RobFilter2</filter-class>
</filter>
<!--
多个Filter的拦截顺序由filter-mapping决定,配置在前的先拦截,在后的后拦截
-->
<filter-mapping>
<filter-name>RobFilter2</filter-name>
<!--url-pattern标签可以配置多个,即一个Filter可以拦截多个地址-->
<url-pattern>/rob.jsp</url-pattern>
<!--
还有通过servlet-name标签配置
例如:<servlet-name>UserServlet</servlet-name>,向UserServlet发送的请求都会被拦截
-->
<!-- <servlet-name></servlet-name>-->
</filter-mapping>
<filter-mapping>
<filter-name>RobFilter</filter-name>
<url-pattern>/rob.jsp</url-pattern>
</filter-mapping>
url-pattern的配置规则
- 精确匹配
- 设置一个完整的路径
- 例如:/index.jsp
- 只有访问index.jsp时才会拦截请求
- 我们也可以通过servlet-name标签来配置拦截的路径
- 例如:UserServlet
- 拦截向UserServlet发送的请求
- 例如:UserServlet
- 模糊匹配
- 前缀匹配
- 例如:/pages/*
- 只要访问pages目录下的资源都会被拦截
- 例如:/pages/*
- 后缀匹配
- 例如:*.jsp
- 只要访问jsp页面都会被拦截
- 例如:*.jsp
- 注意:以下配置方式是无效的
- /pages/*.jsp
- 前缀匹配
Listener简介
- 监听器分为三大类八种(8个接口)
- 生命周期监听器(3个)
- 属性变化监听器(3个)
- session域中的属性变化监听器(2个)
生命周期监听器
-
ServletRequest的生命周期监听器
- ServletRequestListener接口
- 监听ServletRequest对象的创建与销毁
- ServletRequestListener接口
-
HttpSession的生命周期监听器
- HttpSessionListener接口
- 监听HttpSession对象的创建与销毁
- HttpSessionListener接口
-
ServletContext的生命周期监听器
-
ServletContextListener
- 监听ServletContext对象的创建与销毁
-
使用方式:
- 1)创建一个类实现ServletContextListener接口
public class MyServletContextListener implements ServletContextListener { //MyServletContextListener对象被创建时调用 @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("MyServletContextListener对象被创建了"); } //MyServletContextListener对象被销毁时调用 @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("MyServletContextListener对象被销毁"); } }
- 2)在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"> <!--注册监听器--> <listener> <listener-class>com.atguigu.listener.MyServletContextListener</listener-class> </listener> </web-app>
-
属性变化监听器
- 属性的变化指
- 属性的添加
- 属性的替换
- 属性的移除
- ServletRequest的属性变化监听器
- ServletRequestAttributeListener接口
- 监听request域中的属性的添加、替换、移除
- ServletRequestAttributeListener接口
- HttpSession的属性变化监听器
- HttpSessionAttributeListener接口
- 监听session域中的属性的添加、替换、移除
- HttpSessionAttributeListener接口
- ServletContext的属性变化监听器
- ServletContextAttributeListener接口
- 监听application域中的属性的添加、替换、移除
- ServletContextAttributeListener接口
session域中的属性变化监听器
- 通过以下两个接口创建的监听器不需要在web.xml中注册
- 以下两个接口是由JavaBean来实现,然后JavaBean实例在session域中的变化将会被自动监听
- HttpSessionBindingListene接口
- 用来监听JavaBean实例在session域中的添加和移除
- HttpSessionActivationListener接口
- 用来监听Session与session域中的JavaBean实例的活化和钝化
注
Filter
<%--
Created by IntelliJ IDEA.
User: fjc02
Date: 2020/3/2
Time: 9:08
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<h1>你能看见我么?</h1>
</body>
</html>
package com.atguigu.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* @author Study hard Java's Tang
* @create 2020-03-02 9:10
*/
public class HelloFilter 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("你已经被我拦截");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
Listener
package com.atguigu.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener {
//MyServletContextListener对象被创建时调用
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("MyServletContextListener对象被创建了");
}
//MyServletContextListener对象被销毁时调用
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("MyServletContextListener对象被销毁");
}
}