Filter过滤和Listener监听器

Posted 2324hh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Filter过滤和Listener监听器相关的知识,希望对你有一定的参考价值。

过滤器Filter简介

Filter也称之为过滤器,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能 处理编码。它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Filter的完整流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

Filter过滤位置

 

FilterAPI运行流程

 

Filter时序图

 

 

监听器Listener简介

类似于前端的事件绑定,java中的监听器用于监听web应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等等。

 

 

 

JAVA中有哪些监听器接口

java中一共给我们提供了八个监听器接口,分别用于监听三个域对象,每个监听器都有专门监听的事件

​ Request

​ ServletRequestListener (处理request对象创建和销毁)​ ServleRequestAttributeListener (处理域对象中的数据添加 替换 删除)

​ Session

​ HttpSessionListener (处理session对象创建和销毁)​ HttpSessionAttributeListener (处理session域对象中的数据添加 修改 删除)​ HttpSessionBindingListener (处理session对象监听器绑定和解绑定接口)​ HttpSessionActivationListener (处理session对象钝化和活化状态接口)

​ Application

​ ServletContextListener (处理application对象创建和销毁)​ ServletContextAttributeListener (处理application域对象中的数据添加 修改 删除)

 

05-JavaWeb的三大组件:小程序Servlet+过滤器Filter+监听器Listener

Java Web的三大组件【掌握】

组件作用实现接口
Servlet小应用程序,在JavaWeb的服务器中主要做为控制器来使用 可以处理用户的请求并且做出响应javax.servlet.Servlet
Filter过滤器,对用户发送的请求或响应进行集中处理,实现请求的拦截javax.servlet.Filter
Listener监听器,在某些框架中会使用到监听器,如:Spring框架 在Web执行过程中,引发一些事件,对相应事件进行处理。主要是监听Servlet的3大域对象的创建销毁以及属性的变化javax.servlet.XxxListener 每个事件有一个接口

Servlet在web分栏的笔记一有中有详细的描述。

一、过滤器Filter

过滤器介绍

过滤器(filter)本质是Java中预先定义好了不同的接口,和servlet类似。可以过滤不同的内容,具体怎么过滤,需要使用者定义一个实现类,然后实现接口中的过滤方法,在方法中书写过滤的条件。

filter是对客户端访问资源的过滤,符合条件放行,不符合条件不放行。

简而言之,是在servlet之前执行,拦截(过滤)请求,将servlet中一些共同的业务代码抽取出来,这就是过滤器作用。比如:请求乱码处理。

在这里插入图片描述

过滤器API介绍

Filter是由Tomcat启动时创建,是javax.servlet包下面的一个接口,

这个接口中定义了3个方法。

方法说明
void init(FilterConfig filterConfig)过滤器对象创建的时候调用的方法
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)执行过滤的方法
void destory()过滤器销毁的时候调用的方法

1.tomcat服务器一启动就会调用过滤器中的无参构造方法创建过滤器类的对象,然后立刻调用初始化init方法。

2.每次访问拦截的资源都会执行一次执行过滤的方法doFilter

3.正常关闭tomcat服务器,执行销毁过滤器的方法destory

package javax.servlet;
import java.io.IOException;
public interface Filter {
    void init(FilterConfig var1) throws ServletException;
    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
    void destroy();
}

过滤器开发步骤

项目中如果需要使用到过滤器,使用Servlet3.0的注解方式进行创建。

创建步骤如下:

在这里插入图片描述

  • 第一步:新建一个普通java类,实现Filter接口;
  • 第二步:根据提示重写Filter接口的3个方法;
  • 第三步:在这个类上面通过注解的方式配置这个Filter;
  • 注解@WebFilter:配置Filter的注解,这个注解有两个参数;
    • filterName:设置过滤器的名称;
    • urlPatterns:配置这个过滤器要拦截的资源的路径;
  • 第四步:在doFilter()方法中,书写过滤的业务逻辑;
  • chain.doFilter()方法放行;

过滤器是在请求资源之前执行,这点非常重要

在这里插入图片描述

【参考代码】

Filter的web.xml版本

package cn.itheima.filter01;

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

public class FilterOne implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //doFilter 每一次请求都会执行  进行过滤业务逻辑处理
        //如果想放行
//        filterChain.doFilter(servletRequest,servletResponse);
    }
    @Override
    public void destroy() {
    }
}

说明:

filterChain.doFilter(servletRequest,servletResponse);方法被执行,相当于放行的功能。

XML配置 和servlet一样,需要在web.xml中进行配置

	 <filter>
        <filter-name>one</filter-name>
        <filter-class>cn.test.filter01.FilterOne</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>one</filter-name>
        <url-pattern>/filter01.html</url-pattern>
    </filter-mapping>

filter01.html

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

效果:访问http://localhost:8080/filter01.html

浏览器没有得到html资源。
在这里插入图片描述

Filter的注解版本

注解代码参考

package cn.itheima.filter01;

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

@WebFilter("/filter02.html")
public class FilterTwo 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;
        //code...
        //放行
        System.out.println("执行过滤方法。。。");
        chain.doFilter(request, response);  //放行,没有拦截,准许用户访问资源
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

filter02.html页面

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

效果:

访问链接:http://localhost:8080/filter02.html

在这里插入图片描述

可以修改idea中的配置过滤器的模板

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
#parse("File Header.java")
@javax.servlet.annotation.WebFilter("/${Entity_Name}")
public class ${Class_Name} implements javax.servlet.Filter {
    @Override
    public void destroy() {
    }
    @Override
    public void doFilter(javax.servlet.ServletRequest req, javax.servlet.ServletResponse resp, javax.servlet.FilterChain chain) throws javax.servlet.ServletException, java.io.IOException {
        javax.servlet.http.HttpServletRequest request = (javax.servlet.http.HttpServletRequest)req;
        javax.servlet.http.HttpServletResponse response = (javax.servlet.http.HttpServletResponse)resp;
        //your  code.... 
        chain.doFilter(request, response);
    }
    @Override
    public void init(javax.servlet.FilterConfig config) throws javax.servlet.ServletException {
    }
}

总结:

**chain.doFilter(request, response)**方法的作用:

当不写**chain.doFilter(request, response)方法时候,html文件访问不到,被拦截;当有了chain.doFilter(request, response)**方法时候,html文件可以访问,被放行;

所以:**chain.doFilter(request, response)**具有放行的作用。

过滤器的执行流程

1、过滤器中代码执行顺序

在这里插入图片描述

说明:servlet响应给浏览器的内容,过滤器也对其进行了拦截过滤。

代码演示

ProcessFilter.java

@WebFilter("/process")
public class ProcessFilter implements Filter {
    @Override
    public void destroy() {
    }
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //your  code....
        System.out.println("doFilter()之前执行。。。");
        chain.doFilter(request, response);
        System.out.println("doFilter()之后执行。。。");
    }
    @Override
    public void init(FilterConfig config) throws ServletException {
    }
}

ProcessServlet.java

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

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Servlet执行了。。。");
    }
}

执行效果图:

在这里插入图片描述

2、过滤器中请求和响应对象

过滤器的doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)方法中的request对象和response对象

与servlet中请求对象和响应对象相同。

过滤器的执行流程如下:

  1. 客户端(浏览器)的HttpRequest到达Servlet之前,被Filter的doFilter()方法拦截
  2. 根据需要,我们可以获取或者修改HttpRequest对象中的数据;
  3. 在这个请求响应给浏览器之前,Filter拦截了HttpResponse对象;
  4. 根据需要,我们可以获取或者修改HttpReponse对象中的数据;
  5. 最后,由doFilter中的chain决定是否让这个请求通过;

代码演示

ProcessServlet.java

@WebServlet("/processServlet")
public class ProcessServlet 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(request);
        System.out.println(response);
        System.out.println("servlet被执行了。。。");
    }
}

ProcessFilter.java

@WebFilter("/processServlet")
public class ProcessFilter 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;
        //code...
        System.out.println("在doFilter()之前执行。。。");
        System.out.println(request);
        System.out.println(response);
        chain.doFilter(request, response);
        System.out.println("在doFilter()之后执行。。。");
        // 拦截请求对象和响应对象就是servlet请求对象和响应对象
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

控制台运行效果图

在这里插入图片描述

3、多个Filter执行顺序

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

同一包下,拦截同一资源Filter默认是按照字母顺序执行的,如果过滤器名字第一个字母相同,再看过滤器名字的第二个字母,以此类推。从而形成一个执行链条。

执行流程图:

在这里插入图片描述

代码演示

AFilter.java

@WebFilter("/apple")
public class AFilter implements Filter {
    @Override
    public void destroy() {
    }
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //your  code....
        System.out.println("这是在AFilter之前执行。。。");
        chain.doFilter(request, response);
        System.out.println("这是在AFilter之后执行。。。");
    }
    @Override
    public void init(FilterConfig config) throws ServletException {
    }
}

BFilter.java

@WebFilter("/apple")
public class BFilter implements Filter {
    @Override
    public void destroy() {
    }
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //your  code....
        System.out.println("这是在BFilter之前执行。。。");
        chain.doFilter(request, response);
        System.out.println("这是在BFilter之后执行。。。");
    }
    @Override
    public void init(FilterConfig config) throws ServletException {
    }
}

CFilter.java

@WebFilter("/apple")
public class CFilter implements Filter {
    @Override
    public void destroy() {
    }
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //your  code....
        System.out.println("这是在CFilter之前执行。。。");
        chain.doFilter(request, response);
        System.out.println("这是在CFilter之后执行。。。");
    }
    @Override
    public void init(FilterConfig config) throws ServletException {
    }
}

AppleServlet.java

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

上述代码执行效果图:
在这里插入图片描述

过滤器的生命周期

之前学习过servlet生命周期,并且上面,分析了Filter的执行流程。

那么,当我们并没有向Filter发送请求,请求是怎么进入到doFilter()中的呢?

Filter类的对象是在什么时候创建的呢?创建之后又是怎么工作的呢?最后是在什么时候销毁的呢?这些问题就是Filter的生命周期问题。

接下来看下过滤器filter的生命周期,和servlet的生命周期差不多。

在这里插入图片描述

1、Filter生命周期代码演示

接下来我们可以通过以下代码对Filter的生命周期问题进行验证

LifecycleFilter.java

@WebFilter("/lifecycle")
public class LifecycleFilter implements Filter {
    @Override
    public void destroy() {
        System.out.println("被销毁了。。。");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //your  code....
        System.out.println("doFilter()被执行了。。。");
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        System.out.println("初始化了。。。");
    }

    public LifecycleFilter() {
        System.out.println("构造方法被执行了。。。");
    }
}

重启服务器:在浏览器输入访问过滤器地址,并查看控制台。

http://localhost:8080/lifecycle

在这里插入图片描述

【结论】

  1. Filter类的对象是在服务器启动的时候创建的;
  2. Filter类对象创建完成后会调用init()方法;
  3. 每当一个请求的路径是满足过滤器的配置路径,那么就会执行一次过滤器的doFilter方法 (类似于service方法)
  4. 当服务器停止的时候,销毁过滤器,执行过滤器的destory方法

2、doFilter()方法三个参数

doFilter()方法是拦截请求的方法,只要一个请求符合Filter拦截路径,都会被doFilter()方法拦截。doFilter()方法有3个参数,这3个参数的作用分别如下:

参数说明
ServletRequest reqServletRequest是HttpServletRequest类的父接口,其中包含了被拦截的请求的信息
ServletResponse respServletResponse是HttpServletResponse类的父接口,其中包含了被拦截的响应的信息
FilterChain chain**FilterChain给Filter提供了放行的方法。chain.doFilter();**FilterChain 是一个接口,里面doFilter(req,resp)方法,作用是将浏览器提交请求对象和响应对象传到过滤器的资源里面去,所以doFilter()方法具有放行的作用。

3、destory()方法

过滤器的销毁方法。服务器停止的时候,销毁过滤器,调用一次destory方法。

【测试】

    @Override
    public void destroy() {
      System.out.println("服务器关闭");
        Syste

以上是关于Filter过滤和Listener监听器的主要内容,如果未能解决你的问题,请参考以下文章

JavaWeb详解(第三篇)之Servlet基础简介-过滤器Filter&Listener监听器

Servlet之过滤器(Filter)和监听器(Listener)

监听器listener&过滤器filter

05-JavaWeb的三大组件:小程序Servlet+过滤器Filter+监听器Listener

Listener监听器与Filter过滤器

servlet/filter/listener/interceptor过滤器监听器拦截器区分