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的请求进行过滤(精确写法)
<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做出过滤
@WebServlet(value = "/ServletA",name = "ServletA") //注解的name属性别名
<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大致相同
@WebFilter("/*")
与web.xml相同,注解中也有servletNames属性
WebInitParam[] initParams() default {};
... ...
String[] servletNames() default {};
String[] value() default {};
String[] urlPatterns() default {};
我们可以使用WebInitParam[] initParams()注解属性对其初始参数进行配置
doFilter
请求到达目标资源之前,先经过该方法,该方法有能力控制请求是否继续向后到达目标资源,可以在该方法内直接向客户端做响应处理
请求在将目标资源相应回去之前,会再次经过该方法
- 请求到达目标之前的功能代码
- 判断是否登录
- 校验权限是否满足
- ……
- 放行代码
- HttpServletResponse在转换为响应报文之前的功能代码
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>配置的先后顺序执行,但响应的顺序是从后到前
<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响应
注解的方式配置多个过滤器
通过注解配置的多个过滤器时,是通过类名决定过滤器链(过滤器顺序)
@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响应