1.Filter过滤器简介

过滤器作用是当一个请求在访问服务器资源时,可以在访问目标资源前和访问后进行相应处理。

比如访问前我们常做的操作有: 判断是否登陆编码统一处理

访问后后我们常做操作有:敏感字判断

2.运行逻辑

当一个请求来到服务器的时候,首先经过过滤器链再到目标资源。

如上图所示:

  1. 请求先到Filter1中经过访问前处理,若没有问题则调用 filterChain.doFilter方法继续运行;
  2. 请求通过Filter的filterChain.doFilter调用进入Filter2中的访问前处理逻辑;
  3. Filter2处理完也通过filterChain.doFilter调用去访问目标资源;
  4. 访问目标资源后像一个栈一样先Filter2访问后处理
  5. 再到Filter1访问后处理
  6. 最后把处理完的结果返回到浏览器。

3.过滤器的使用

过滤器使用要很实现javax.servlet.Filter接口并实现其中三个方法,一个简单的对所有资源进行处理的过滤器代码如下:

package com.hyq.sessionAndCookieStudy.web.filter;

import javax.servlet.*;
import java.io.IOException;
//过滤器生效的路径
@WebFilter("/*")
public class MyFilter implements Filter {

    /**
    初始化方法,在Tomcat启动的时候自动调用
    */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println(" MyFilter init...");
    }

    /**
    过滤器操作
    每次访问符合@WebFilter设置的资源都会调用
    */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
		//访问前处理
        System.out.println("MyFilter");
        //继续访问资源,或转到下个过滤器上
        filterChain.doFilter(servletRequest,servletResponse);
        //访问后处理
    }

    /**
    销毁方法
    当tomcat正常关闭时调用
    如果强制关闭tomcat该方法不会被调用   
    */
    @Override
    public void destroy() {
        System.out.println(" MyFilter destroy...");
    }
}

写完对代码进行测试,在web目录下随意建立一个index.html进行访问后结果如下:

[INFO] create webapp with contextPath:
六月 30, 2022 2:05:17 下午 org.apache.coyote.AbstractProtocol init
信息: Initializing ProtocolHandler ["http-bio-8999"]
六月 30, 2022 2:05:17 下午 org.apache.catalina.core.StandardService startInternal
信息: Starting service Tomcat
六月 30, 2022 2:05:17 下午 org.apache.catalina.core.StandardEngine startInternal
信息: Starting Servlet Engine: Apache Tomcat/7.0.47
 MyFilter init...			
六月 30, 2022 2:05:18 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-bio-8999"]
MyFilter
MyFilter
 MyFilter destroy...
终止批处理操作吗(Y/N)? y

  • MyFilter init... 是在tomcat启动的时候只执行一次,证明init确实在服务器执行的时候只调用一次;
  • MyFilter 因为我这里访问2次,所以输出2次,也证明doFilter是访问需要过滤器处理时都会被用。
  • MyFilter destroy... 在Ctrl+C结束tomcat时也只输出一次,证明destroy只在服务器关闭时调用一次。

4.过滤器路径种类

和Servlet的路径一样一共有4种:

  1. 精准匹配,例子:@WebFilter("/user/login")
  2. 目录 ,例子:@WebFilter("/user/*")
  3. 扩展名,例子:@WebFilter("*.jsp")
  4. 任意匹配,例子@WebFilter("/*")

5.过滤器配置

上边我们是使用@WebFilter注解来配置过滤器路径,这个是Servet 3.0以上版本才支持。3.0以下版本是通过在web.xml中进入配置,配置方法和Servlet的配置类型,也是先声明再绑定,配置方如下:

<?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_3_1.xsd"
         version="3.1">
    <!-- 声明过滤器 -->
    <filter>
        <!-- 过滤器名字 -->
        <filter-name>myFilter</filter-name>
         <!-- 过滤器全限定类名 -->
        <filter-class>com.hyq.sessionAndCookieStudy.web.filter.MyFilter</filter-class>
    </filter>
     <!-- 过滤器映射绑定 -->
    <filter-mapping>
        <!-- 上边声明的过滤器名字 -->
        <filter-name>myFilter</filter-name>
        <!-- 需要处理的路径 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

6.过滤器的执行顺序

当我们有多个过滤器并且都处理一个资源的时候多个过滤器是按什么顺序执行,这里要分不同情况
PS:这里最基础的方式,听说spring框架有参数可以直接调用顺序,但是本人还没学习那边一块

使用@WebFilter注解

使用注解方法,他是按过滤器名称排序来执行,比如我们有2个过滤器代码如下:那么调用顺序就是Filter01 --> Filter02。

@WebFilter("/*")
public class MyFilter02 implements Filter {
	....
}

@WebFilter("/*")
public class MyFilter01 implements Filter {
	....
}

使用web.xml配置

使用web.xml配置是根据 在web.xml配置文件中声明顺序,先声明的先调用。

比如我们按下边在web.xml中声明,则先调用myFilter2,再调用myFilter1

    <filter-mapping>
        <filter-name>myFilter2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <filter-mapping>
        <filter-name>myFilter1</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

直接和web.xml配置混用

这个不太推荐,但是我也做了实验这样的情况是web.xml中的配置优先。

比如我们如下配置3个过滤器,它们是先按web.xml配置运行规则执行myFilter3再到myFilter2,之后再执行注解中声明的myFilter1

<filter-mapping>
    <filter-name>myFilter3</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>myFilter2</filter-name>
    <url-pattern>/*</url-pattern>			
</filter-mapping>
@WebFilter("/*")
public class MyFilter01 implements Filter {
	....
}

7.注意事项

  1. 注解和web.xml建议只采用一种,若两种都使用,当你不小心一个过滤器两边都配置后该过滤器会被 注册2次,意味着这个过滤器会被生成2个实例造成资源的浪费和重复处理。