Filter
Filter,即过滤器,是JAVAEE技术规范之一,作用目标资源的请求进行过滤的一套技术规范,是Java Web项目中最为实用的技术之一
- Filter接口定义了过滤器的开发规范,所有的过滤器都要实现该接口
- Filter的工作位置是项目中所有目标资源之前,容器在创建HttpServletRequest和HttpServletResponse对象后,会先调用Filter的doFilter方法
- Filter的doFilter方法可以控制请求是否继续,如果放行,则请求继续,如果拒绝,则请求到此为止,由过滤器本身做出响应
- Filter不仅可以对请求做出过滤,也可以在目标资源做出响应前,对响应再次进行处理
- Filter是GOF中责任链模式的典型案例
- Filter的常用应用包括但不限于: 日志的记录、性能的分析、乱码的处理、事务的控制、登录的控制、跨域的处理
在软件包下建立filters目录作为过滤器的文件夹
继承Filter接口
重写过滤方法(doFilter)
配置过滤器
配置过滤器
使用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")
|
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大致相同
与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;
public class LoggingFilter implements Filter { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) servletRequest; HttpServletResponse resp = (HttpServletResponse) servletResponse;
String requestURI = req.getRequestURI(); 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响应