当前位置: 首页 > article >正文

FilterListener组件

文章目录

  • Java Web三大组件
  • 一、Filter概述
  • 二、Filter开始
    • 1_过滤器API介绍
    • 2_过滤器开发步骤
    • 3_代码实现
    • 4_过滤器执行流程小结
  • 三、使用细节
    • 1_生命周期
    • 2_拦截路径
    • 3_过滤器链
  • 四、Listener
    • 1_Listener概述
    • 2_监听器举例
    • 3_Listener开始
    • 4_案例:模拟spring框架

Java Web三大组件


  1. 组件: 是一个系统的组成部件
  2. javaweb组件 : javaweb项目的组成部件
    1. servlet
    2. filter
    3. listener
组件作用实现接口
ServletServer Applet小应用程序,在JavaWeb中主要做为控制器来使用,可以处理用户的请求并且做出响应javax.servlet.Servlet
Filter过滤器,对用户发送的请求或响应进行集中处理,实现请求的拦截 javax.servlet.Filter
Listener监听器,在Web执行过程中,监听一些事件,当相应事件发生时, 进行处理 javax.servlet.XxxListener 每个事件有一个接口

一、Filter概述


生活中的过滤器

净水器、空气净化器、地铁安检

web中的过滤器

当用户访问服务器资源时,过滤器将请求拦截下来,完成一些通用的操作

F i l t e r Filter Filter 的作用

  1. 拦截客户端对web资源的请求 (重要!)
  2. 拦截web资源对客户端的响应

应用场景

如:登录验证、统一编码处理、敏感字符过滤

在这里插入图片描述


二、Filter开始


1_过滤器API介绍

F i l t e r Filter Filter 表示过滤器接口,我们想使用该接口必须自定义类实现接口并实现该接口中的所有抽象方法。

javax.Servlet.Filter接口下面的三个方法:

方法说明
void init(FilterConfig filterConfig)过滤器对象创建的时候调用的方法
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)执行过滤的方法,每次访问被拦截的资源都会执行该方法
void destory()过滤器销毁的时候调用的方法

注意:doFilter第三个参数:FilterChain 表示过滤器链接口。

放行:使用 FilterChain 对象调用 FilterChain 中的方法:chain.doFilter(request,response);即可以让浏览器访问服务器资源。

不放行,那么不写上述代码,即不让浏览器访问服务器资源。


2_过滤器开发步骤

1.自定义过滤器类实现过滤器接口 F i l t e r Filter Filter

2.在自定义类中实现过滤器接口 F i l t e r Filter Filter中的所有抽象方法

3.在doFilter方法体中书写拦截资源的代码

F i l t e r Filter Filter 过滤器接口的关键方法说明:

void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

参数:

  • request:表示请求对象,不满足 h t t p http http协议

  • response:表示响应对象,不满足 h t t p http http协议

  • chain:属于 FilterChain 的接口,表示过滤器链。

    FilterChain 接口中具有一个放行方法:

    void doFilter(ServletRequest request, ServletResponse response)  
    
    • 如果放行,希望浏览器可以访问拦截的资源则执行该方法

      filterChain.doFilter(servletRequest,servletResponse);

    • 如果不放行,不希望浏览器访问拦截的资源则不执行该方法

4.配置过滤器

5.访问被拦截的资源


3_代码实现

过滤器类:

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

//1.自定义过滤器类实现过滤器接口Filter
public class MyFilter implements Filter {
    //2.在自定义类中实现过滤器接口Filter中的所有抽象方法
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 不要调用父类的初始化方法否则报错
        // Filter.super.init(filterConfig);
    }

    //3.在doFilter方法体中书写拦截资源的代码
    //每次访问被过滤的资源都要执行该方法
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("执行过滤器了...");
        //不放行
        /*
            Filter过滤器接口的:
                void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                        参数:
                            request:表示请求对象,不满足http协议
                            response:表示响应对象,不满足http协议
                            chain:属于FilterChain的接口,表示过滤器链。
                            FilterChain接口中具有一个放行方法:
                            void doFilter(ServletRequest request, ServletResponse response)
                                如果放行,希望浏览器可以访问拦截的资源则执行该方法
                                如果不放行,不希望浏览器访问拦截的资源则不执行该方法
         */
        //放行
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

web.xml

<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">
    
    <display-name>Archetype Created Web Application</display-name>

    <!--配置过滤器-->
    <!--表示关联的过滤器类-->
    <filter>
        <filter-name>myFilter</filter-name>
        <!--过滤器类的全路径,底层获取这里使用反射技术调用无参构造方法创建过滤器类的对象-->
        <filter-class>com.example.sh.MyFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>myFilter</filter-name>
        <!--配置被拦截的资源-->
        <url-pattern>/filter01.html</url-pattern>
    </filter-mapping>

</web-app>

被拦截的页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>来拦截我啊</h1>
</body>
</html>

小结:

1.配置过滤器有两种方式:

  1. xml版本:

    <!--配置过滤器-->
    <!--表示关联的过滤器类-->
    <filter>
    	<filter-name>myFilter</filter-name>
    	<!--过滤器类的全路径,底层获取这里使用反射技术调用无参构造方法创建过滤器类的对象-->
    	<filter-class>com.example.sh.MyFilter</filter-class>
    </filter>
    <filter-mapping>
    	<filter-name>myFilter</filter-name>
    	<!--配置被拦截的资源-->
    	<url-pattern>/filter01.html</url-pattern>
    </filter-mapping>
    
  2. 注解版本配置

    使用注解必须去掉xml版本。

    在这里插入图片描述


4_过滤器执行流程小结


在这里插入图片描述

  1. 用户发送请求,请求Web资源(包括html, jsp, servlet等)。
  2. 如果Web资源的地址,是 f i l t e r filter filter 要拦截的地址,请求将先经过 f i l t e r filter filter,并执行doFilter()
  3. doFilter()方法中如果调用filterChain.doFilter(),则允许请求访问下一个Web资源。
  4. 访问Web资源,响应回来会再次经过 f i l t e r filter filter,执行过滤器中的代码,到达浏览器端。

三、使用细节


1_生命周期

生命周期:指的是一个对象从生(创建)到死(销毁)的一个过程

// 初始化方法
public void init(FilterConfig config);

// 执行拦截方法
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain);

// 销毁方法
public void destroy();
  • 创建

    服务器启动项目加载,创建 f i l t e r filter filter对象,执行init方法(只执行一次)

  • 运行(过滤拦截)

    用户访问被拦截目标资源时,执行doFilter方法

  • 销毁

    服务器关闭时,销毁 f i l t e r filter filter对象,执行destroy方法(只执行一次)

  • 补充:

    过滤器一定是优先于servlet创建的,后于 S e r v l e t Servlet Servlet 销毁

    复习:servlet默认是第一次访问的时候创建

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

/*
    Filter的生命周期方法
    1. init
        web服务器启动时,此方法运行,就运行一次(早于Servlet)
    2. doFilter
        当请求经过过滤器,此方法就会运行(每经过一次,就运行一次) (早于servlet的service方法)
    3. destroy
       tomcat关闭, 此方法运行一次 (晚于servlet的destroy)
 */

@WebFilter("/MyFilterLife")
public class MyFilterLife implements Filter {

    public MyFilterLife() {
        System.out.println("MyFilterLife的构造方法被调用了..........");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFilterLife init");
    }

    //当请求经过过滤器,此方法就会运行(每经过一次,就运行一次)
    @Override
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        System.out.println("MyFilterLife doFilter");
        //请求放行 (相当于请求转发)
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        System.out.println("MyFilterLife destroy");
    }
}

总结:

  1. 过滤器是在 t o m c a t tomcat tomcat启动的时候 t o m c a t tomcat tomcat调用过滤器类中的无参构造方法创建对象,使用对象调用init方法,只会执行一次
  2. 当使用浏览器访问被过滤的资源的时候就会执行过滤器 F i l t e r Filter Filter中的doFilter方法,访问一次就会执行一次doFilter方法
  3. 当关闭 t o m c a t tomcat tomcat服务器就会使用对象调用销毁方法destroy,只会执行一次
  4. 过滤器优先于访问的资源执行

2_拦截路径

在开发时,我们可以指定过滤器的拦截路径来定义拦截目标资源的范围

  • 精准匹配

    用户访问指定目标资源(/demo01.html)时,过滤器进行拦截

  • 目录匹配

    用户访问指定目录下(/user/*)所有资源时,过滤器进行拦截

  • 后缀匹配

    用户访问指定后缀名(*.html)的资源时,过滤器进行拦截,不能加/

  • 匹配所有

    用户访问该网站所有资源(/*)时,过滤器进行拦截

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


 
//@WebFilter({"/xx","/yy"})
//@WebFilter("/xx") // 精准匹配
//@WebFilter("/user/*") // 目录匹配
//@WebFilter("*.do") // 后缀匹配
@WebFilter("/*") // 匹配所有
public class MyFilterPath implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("doFilter");
    }

    @Override
    public void destroy() {

    }
}

注意: 在过滤器中,如果多个过滤器过滤同一个资源,那么要执行所有满足条件的过滤器。


3_过滤器链

在一次请求中,若我们请求匹配到了多个 f i l t e r filter filter,通过请求就相当于把这些 f i l t e r filter filter串起来了,形成了过滤器链。

问题:如果多个过滤器都对相同路径进行匹配,执行顺序该是什么?

F i l t e r Filter Filter 默认是按照字母顺序执行的,如果过滤器名字第一个字母相同,再看过滤器名字的第二个字母,以此类推。从而形成一个执行链条。

前提:多个过滤器过滤同一个资源,并且多个过滤器是在同一下。

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter("/apple")
public class AFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        System.out.println("AFilter....放行前");
        chain.doFilter(request, response);
        System.out.println("AFilter....放行后");
    }

    public void init(FilterConfig config) throws ServletException {

    }

}
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter("/apple")
public class BFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        System.out.println("BFilter....放行前");
        chain.doFilter(request, response);
        System.out.println("BFilter....放行后");
    }

    public void init(FilterConfig config) throws ServletException {

    }

}
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/apple")
public class AppleServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("AppleServlet....");
    }
}

在这里插入图片描述

在这里插入图片描述

总结:

  1. 如果同一个包下多个过滤器拦截同一个资源,那么按照过滤器类的名字字母升序来依次执行(针对注解开发)

    AFilter ---- BFilter

  2. 执行完拦截资源后依次在按照相反顺序执行

  3. 如果是xml配置方式,那么按照从上往下配置的顺序执行


四、Listener


1_Listener概述

说明:

javaweb中的监听器是监听 S e r v l e t C o n t e x t ServletContext ServletContext H t t p S e s s i o n HttpSession HttpSession H t t p S e r v l e t R e q u e s t HttpServletRequest HttpServletRequest三个对象创建和销毁的,同时监听是哪个对象中数据的变化,就是监听属性的变化setAttributeremoveAttribute

  1. S e r v l e t C o n t e x t ServletContext ServletContext 是在 t o m c a t tomcat tomcat启动创建,关闭 t o m c a t tomcat tomcat销毁

  2. H t t p S e s s i o n HttpSession HttpSession 是在浏览器第一次访问执行request.getSession()创建,销毁时间:1)30min 2) 执行invalidate()

  3. H t t p S e r v l e t R e q u e s t HttpServletRequest HttpServletRequest 是浏览器第一次访问创建,浏览器接收到服务器的响应就销毁

生活中的监听器

我们很多商场有摄像头,监视着客户的一举一动。如果客户有违法行为,商场可以采取相应的措施。

javaweb中的监听器

在我们的 java 程序中,有时也需要监视某些事情,一旦被监视的对象发生相应的变化,我们应该采取相应的操作。

监听 web 三大域对象: H t t p S e r v l e t R e q u e s t HttpServletRequest HttpServletRequest H t t p S e s s i o n HttpSession HttpSession S e r v l e t C o n t e x t ServletContext ServletContext (创建和销毁)

场景

历史访问次数、统计在线人数、系统启动时初始化配置信息

监听器的接口分类

事件源监听器接口时机
ServletContextServletContextListener上下文域创建和销毁
ServletContextServletContextAttributeListener上下文域属性增删改的操作
HttpSessionHttpSessionListener会话域创建和销毁
HttpSessionHttpSessionAttributeListener会话域属性增删改的操作
HttpServletRequestServletRequestListener请求域创建和销毁
HttpServletRequestServletRequestAttributeListener请求域属性增删改的操作

2_监听器举例


监听的关键要素:

  1. 设置监听器的人
  2. 监听器
  3. 监听器目标: 被监听的对象
  4. 监听器工作: 被监听的对象执行某种行为,监听器就开始工作

web 中监听的关键要素:

  1. 雇佣人 : web程序开发者

  2. 监听器例子A

    1. 监听器A:ServletContextListener
    2. 目标 : 监听 S e r v l e t C o n t e x t ServletContext ServletContext 对象
    3. 执行 : 监听 S e r v l e t C o n t e x t ServletContext ServletContext 对象创建和销毁
  3. 监听器例子B

    1. 监听器A:HttpSessionListener
    2. 目标: H t t p S e s s i o n HttpSession HttpSession 对象
    3. 执行:监听 H t t p S e s s i o n HttpSession HttpSession 对象创建和销毁
  4. 监听器例子C

    1. 监听器A:HttpRequestListener
    2. 目标: H t t p R e q u e s t HttpRequest HttpRequest 对象
    3. 执行:监听 H t t p R e q u e s t HttpRequest HttpRequest 对象创建和销毁
  5. 监听器例子D

    1. 监听器A: ServletContextAttributeListener

    2. 目标 : S e r v l e t C o n t e x t ServletContext ServletContext对象

    3. 执行 : 监听 S e r v l e t C o n t e x t ServletContext ServletContext对象增删改数据 (add,remove)

      当我们向 S e r v l e t C o n t e x t ServletContext ServletContext对象中添加数据setAttribute()和删除数据removeAttribute()就会被ServletContextAttributeListener 监听器监听。

  6. 其他监听器

    HttpSessionAttributeListenerHttpRequestAttributeListener


3_Listener开始

监听器在web开发中使用的比较少,见的机会就更少了,我们使用ServletContextListenner对监听器快速了解,因为这个监听器是监听器中使用率最高的一个,且监听器的使用方式都差不多。

我们使用这个监听器可以在项目启动和销毁的时候做一些事情,例如:在项目启动的时候加载配置文件。

步骤分析

  1. 创建一个普通类,实现ServletContextListenner

  2. 重写方法

    • 监听 S e r v l e t C o n t e x t ServletContext ServletContext创建

    • 监听 S e r v l e t C o n t e x t ServletContext ServletContext销毁

  3. 配置

    • web.xml

    • 注解

① xml版本

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

/*
    设置监听器的人: 开发者
    监听器 : MyListener
    监听器目标 : ServletContext 对象
    监听器的工作:
        1). 当ServletContext 对象创建的时候就会执行contextInitialized方法
            ServletContext是tomcat启动时就会创建 (早于Filter和Servlet)
        2). 当ServletContext 对象销毁的时候就会执行contextDestroyed方法
             ServletContext是tomcat关闭时销毁 (晚于Filter和Servlet)

        这两个方法是事件驱动
 */
public class MyListener implements ServletContextListener {
    //tomcat一启动,此方法就会运行
    //运用场景: spring底层封装了一个ServletContextListener加载配置文件
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitialized");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroyed");
    }
}
<!--    配置监听器   -->
<listener>
    <listener-class>com.example.sh.MyListener</listener-class>
</listener>

② 注解版本

//3.配置监听器
@WebListener
//1. 创建一个普通类,实现ServletContextListener
public class MyListener implements ServletContextListener {

    //2.重写方法
    //当上下文对象ServletContext创建就执行该方法
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitialized");
    }

    //当上下文对象ServletContext销毁就执行该方法
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroyed");
    }
}

4_案例:模拟spring框架

需求:可以在项目启动时读取配置文件,获取配置文件的名字。

步骤:

  1. web.xml进行配置文件的配置

  2. 创建自定义监听器类监听 S e r v l e t C o n t e x t ServletContext ServletContext的创建和销毁

  3. 在自定义监听器类中实现监听器的方法

  4. 实现的方法体中读取web.xml文件中关于当前项目配置文件的信息

  5. 输出结果

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

//2.创建自定义监听器类监听ServletContext的创建和销毁
//别忘记注册监听器
@WebListener
public class SpringContextListener implements ServletContextListener {
    //3.在自定义监听器类中实现监听器的抽象方法
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        //4.实现的方法体中读取web.xml文件中关于当前项目配置文件的信息
        //4.1根据事件类对象servletContextEvent调用方法获取ServletContext上下文对象
        ServletContext servletContext = servletContextEvent.getServletContext();
        //4.2使用上下文对象调用方法获取web.xml配置文件中的数据
        /*
            <context-param>
                <param-name>jdbc</param-name>
                <param-value>jdbc.properties</param-value>
            </context-param>
         */
        String str = servletContext.getInitParameter("jdbc");
        System.out.println("str = " + str);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("释放资源....销毁。。。。");
    }
}
<!--配置当前项目的配置文件信息-->
<!--1.在web.xml进行配置文件的配置-->
<context-param>
    <param-name>jdbc</param-name>
    <param-value>jdbc.properties</param-value>
</context-param>


http://www.kler.cn/a/386180.html

相关文章:

  • 24.11.13 机器学习 特征降维(主成份分析) KNN算法 交叉验证(K-Fold) 超参数搜索
  • MFC工控项目实例三十实现一个简单的流程
  • 无人机应用场景:石油管道巡检技术详解
  • Vue3 -- 环境变量的配置【项目集成3】
  • 【深度学习】学习率介绍(torch.optim.lr_scheduler学习率调度策略介绍)
  • 【汇编语言】包含多个段的程序(二)—— 将数据、代码、栈放入不同的段
  • SSH实验5密钥登录Linuxroot用户(免密登录)
  • NodeJS的安装 npm 配置和使用 Vue-cli安装 Vue项目介绍
  • 理解虚拟 DOM:Vue 的灵魂之处
  • 关于CountDownLatch失效问题
  • 量化交易系统开发-实时行情自动化交易-股票大资金动力指标
  • ROS2humble版本使用colcon构建包
  • Remix部署智能合约时报错:Gas estimation failed
  • lua ruturn 和goto
  • 【DL】YOLO11 OBB目标检测 | 模型训练 | 推理
  • 鸿蒙系统崛起:机遇、挑战与未来展望
  • matlab 质心重合法实现点云配准
  • 2-148 基于matlab的铣削动力学仿真
  • 2.Python解释器
  • 征程 6 工具链性能分析与优化 2|模型性能优化建议
  • 如何电脑连接电视,实现大屏自由!
  • 基于 SSM(Spring + Spring MVC + MyBatis)框架构建电器网上订购系统
  • Unity性能优化-具体操作
  • 从技术创新到商业应用,智象未来(HiDream.ai)创新不止步
  • web 渗透学习指南——初学者防入狱篇
  • java:修复aspectj-maven-plugin插件在java9项目中执行报错:cannot be resolved to a module