Filter

Filter

Filter,即过滤器,是JAVAEE技术规范之一,作用目标资源的请求进行过滤的一套技术规范,是Java Web项目中最为实用的技术之一

  • Filter接口定义了过滤器的开发规范,所有的过滤器都要实现该接口
  • Filter的工作位置是项目中所有目标资源之前,容器在创建HttpServletRequest和HttpServletResponse对象后,会先调用Filter的doFilter方法
  • Filter的doFilter方法可以控制请求是否继续,如果放行,则请求继续,如果拒绝,则请求到此为止,由过滤器本身做出响应
  • Filter不仅可以对请求做出过滤,也可以在目标资源做出响应前,对响应再次进行处理
  • Filter是GOF中责任链模式的典型案例
  • Filter的常用应用包括但不限于: 日志的记录、性能的分析、乱码的处理、事务的控制、登录的控制、跨域的处理

在软件包下建立filters目录作为过滤器的文件夹

  • 继承Filter接口

  • 重写过滤方法(doFilter)

  • 配置过滤器

    • web.xml配置
    • 注解配置

配置过滤器

使用web.xml配置过滤器的过程大致与servlet相同

但是在mapping的位置上,过滤器有两种写法

<url-pattern>写法:
  • /* 过滤全部资源
  • /a/* 过滤以a开头的资源
  • *.html 过滤以html为后缀的资源
  • /ServletA 对ServletA的请求进行过滤(精确写法)
1
2
3
4
5
6
7
8
<filter>
<filter-name>LoggingFilter</filter-name>
<filter-class>com.xiaobai.filters.LoggingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoggingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<servlet-name>写法:

以xml文件的servlet-name别名或者以注解的name属性别名为参数,可以针对某个Servlet做出过滤

1
@WebServlet(value = "/ServletA",name = "ServletA") //注解的name属性别名
1
2
3
4
5
6
7
8
<filter>
<filter-name>LoggingFilter</filter-name>
<filter-class>com.xiaobai.filters.LoggingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoggingFilter</filter-name>
<servlet-name>ServletA</servlet-name>
</filter-mapping>

注:servlet-name 和 url-pattern都可存在多个,并且可以共存

注解的写法

Filter注解的写法与Servlet大致相同

1
@WebFilter("/*")

与web.xml相同,注解中也有servletNames属性

1
2
3
4
5
6
7
8
9
WebInitParam[] initParams() default {};

... ...

String[] servletNames() default {};

String[] value() default {};

String[] urlPatterns() default {};

我们可以使用WebInitParam[] initParams()注解属性对其初始参数进行配置


doFilter

请求到达目标资源之前,先经过该方法,该方法有能力控制请求是否继续向后到达目标资源,可以在该方法内直接向客户端做响应处理

请求在将目标资源相应回去之前,会再次经过该方法

  • 请求到达目标之前的功能代码
    • 判断是否登录
    • 校验权限是否满足
    • ……
  • 放行代码
  • HttpServletResponse在转换为响应报文之前的功能代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.xiaobai.filters;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
* 日志过滤器,记录请求的历史 将日志打印到控制台
* 请求到达之前打印日志 yyyy-MM-dd HH:mm:ss
* 请求结束之后打印访问资源的耗时 xxx资源在xxx的请求耗时x毫秒
*/
public class LoggingFilter implements Filter {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//使用dateFormate格式化时间

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//将请求相应的两个对象向下转型,以便能够使用HttpServletRequest和HttpServletResponse的方法
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;

//请求到达目标资源之前的功能代码(打印日志)
String requestURI = req.getRequestURI();//获取URI
String dataTime = simpleDateFormat.format(new Date());//获取系统时间
String beforeLogging = requestURI + "在" + dataTime + "被访问了";
System.out.println(beforeLogging);
long t1 = System.currentTimeMillis();//获取资源前
//放行代码
filterChain.doFilter(servletRequest, servletResponse);

long t2 = System.currentTimeMillis();//获取资源后
//相应之前的功能代码
String afterLogging = requestURI + "资源在" + dataTime + "的请求耗时:" + (t2 - t1) + "毫秒";
System.out.println(afterLogging);
}
}

注:我们写的过滤器直接实现了Filter的接口,形参对象是ServletRequest servletRequest, ServletResponse servletResponse

如果想要使用HttpServletRequest和HttpServletResponse的方法,需要向下转型 😶


生命周期

Filter的生命周期也与Servlet大致相同

步骤 使用方法 执行时间
实例化 构造器 第一次请求/随服务器启动
初始化 init 构造完毕
接受请求,处理请求,服务 service 每次请求
销毁 destory 关闭服务

不同的是,我们写的过滤器直接实现了Filter接口

Filter接口中的init和destory是使用了default修饰,即不重写也不会报错

并且Filter中没有无参构造方法


过滤器链

Filter可以存在多个,分别配置到不同的资源前,同一个资源可以有多个过滤器,将会形成过滤器链


web.xml配置多个过滤器

web.xml配置的过滤器链会按照<filter-mapping>配置的先后顺序执行,但响应的顺序是从后到前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<filter>
<filter-name>Filter1</filter-name>
<filter-class>com.xiaobai.filters.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
<filter-name>Filter2</filter-name>
<filter-class>com.xiaobai.filters.Filter2</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
<filter-name>Filter3</filter-name>
<filter-class>com.xiaobai.filters.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter3</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

以上过滤器的执行流程是:

Filter1请求 -> Filter1放行 -> Filter2请求 -> Filter2放行 -> Filter3请求 -> Filter3放行 -> Filter3响应 -> Filter2响应 -> Filter1响应


注解的方式配置多个过滤器

通过注解配置的多个过滤器时,是通过类名决定过滤器链(过滤器顺序)

1
2
3
4
5
6
7
8
9
@WebFilter("/*")
public class Filter1 implements Filter {
}
@WebFilter("/*")
public class Filter2 implements Filter {
}
@WebFilter("/*")
public class Filter3 implements Filter {
}

Filter1请求 -> Filter1放行 -> Filter2请求 -> Filter2放行 -> Filter3请求 -> Filter3放行 -> Filter3响应 -> Filter2响应 -> Filter1响应



Filter
http://blog.170827.xyz/2024/04/24/Filter/
作者
XIAOBAI
发布于
2024年4月24日
许可协议