Filter:过滤器,用于在 Servlet 之外对 Request 或者 Response 进行拦截,做一些处理后再交给下一个过滤器或者 Servlet 进行处理,通常用来拦截 Request 进行处理,也可以对返回的 Response 做拦截处理
主要用途:自动登录、统一编码设置、访问权限控制、敏感字符过滤
Filter 类结构:
Filter 生命周期
javax.servlet.Filter 接口:
// Filter 接口
public interface Filter {
// 初始化方法
default public void init(FilterConfig filterConfig) throws ServletException {}
// 过滤方法,主要是对request和response进行处理,再转交下一个过滤器或Servlet
// chain.doFilter(request,response)
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException;
// 销毁方法
default public void destroy() {}
}
Filter的创建和销毁由WEB服务器负责:
- Filter 创建:web 应用程序启动时,web 服务器将创建 Filter 的实例对象,并调用其 init 方法,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作,filter对象只会创建一次,init方法也只会执行一次。通过 init 方法的参数,可获得代表当前 filter 配置信息的 FilterConfig 对象
- Filter 销毁:Web 容器调用 destroy 方法销毁 Filter。destroy 方法在 Filter 的生命周期中仅执行一次。在 destroy 方法中,可以释放过滤器使用的资源
FilterConfig 接口:用户在配置 filter 时,可以使用为 filter 配置一些初始化参数,当 web 容器实例化 Filter 对象,调用其 init 方法时,会把封装了 filter 初始化参数的 filterConfig 对象传递进来。因此开发人员在编写 filter 时,通过 filterConfig 对象的方法,就可获得:
- String getFilterName():得到 filter 的名称
- String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值。如果不存在返回 null
- Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合
- public ServletContext getServletContext():返回 Servlet 上下文对象的引用
Filter 实现
Filter 实现分为三步:
- 引入 Servlet-API
- 创建一个类继承 HttpFilter(或者实现 Filter 接口)
- 配置需要过滤的 URL 路径
1、在 pom.xml 中引入 Servlet-API
Servlet-API 一般在 web 容器中会提供,因此我们只需要在开发编译时引入 Servlet-API 提供支持即可,而无需打包到项目中,因此设置其生命周期为 provided
<!-- Servlet3.0之前的版本为servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- Servlet3.0之后的版本为javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
2、创建一个类继承 HttpFilter(或者实现 Filter 接口)
chain.doFilter(req, res):将当前处理过的 HttpServletRequest 或 HttpServletResponse 转交给下一步处理
public class DemoFilter extends HttpFilter {
@Override
protected void doFilter(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain) throws IOException, ServletException {
// 设置请求的编码格式
req.setCharacterEncoding("utf-8");
// 设置服务端的响应编码格式
res.setCharacterEncoding("utf-8");
// 设置客户端对响应信息的编码格式
res.setHeader("Content-type","text/html;charset=UTF-8");
// 转交刚给下一个Filter或者Servlet
chain.doFilter(req, res);
// 在执行后对响应做一定的处理
after(req , res);
}
}
3、配置过滤器过滤的URL映射,支持注解和web.xml中配置:
web.xml中配置:
<filter>
<filter-name>encoding</filter-name>
<filter-class>top.songfang.filter.DemoFilter</filter-class>
<init-param>
<!-- 可以通过FilterConfig进行获取 -->
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<!-- 对所有的请求都进行过滤 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
注解方式:@WebFilter 注解
@WebFilter(value = "/*", // 统配符,拦截所有请求
initParams = {
// 初始化参数
@WebInitParam(name = "encoding", value = "UTF-8", description = "字符编码")
})
@WebFilter 注解属性说明
@WebFilter:声明一个类为过滤器,该注解在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。该注解具有下表给出的一些常用属性 ( 以下所有属性均为可选属性,但是 value、urlPatterns、servletNames 三者必需至少包含一个,且 value 和 urlPatterns 不能共存,如果同时指定,通常忽略 value 的取值 )
属性名 | 类型 | 描述 |
---|---|---|
filterName | String | 指定过滤器的name属性,等价于 |
value | String[] | 该属性等价于urlPatterns属性,但两者不能同时使用 |
urlPatterns | String[] | 指定一组过滤器的URL匹配模式,等价于 |
servletNames | String[] | 指定过滤器将应用于哪些Servlet,取值为@WebServlet中name属性的取值,或者web.xml中 |
dispatcherTypes | DispatcherType | 指定过滤器的转发模式,包括ASYNC(异步)、ERROR(出错)、FORWARD(转发)、INCLUDE(包含在页面的)、REQUEST(请求的) |
initParams | WebInitParam[] | 指定一组过滤器初始化参数,等价于 |
asyncSupported | boolean | 指定过滤器是否支持异步操作模式,等价于 |
description | String | 该过滤器的描述信息,等价于 |
displayName | String | 该过滤器的显示名,配合工具使用,等价于 |
dispatcher 说明:
- REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过 RequestDispatcher 的 include() 或 forward() 方法访问时,那么该过滤器就不会被调用
- INCLUDE:如果目标资源是通过 RequestDispatcher 的 include() 方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用
- FORWARD:如果目标资源是通过 RequestDispatcher 的 forward() 方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用
- ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用
过滤器链的执行顺序
关于过滤器的注解执行顺序的说明:https://www.concretepage.com/java-ee/jsp-servlet/how-to-use-filter-in-servlet-3-with-webfilter-annotation
过滤器链的执行顺序:
- 请求时执行顺序:
- 在 web.xml 中,filter 执行顺序跟
的顺序有关,先声明的先执行 - 使用注解配置的话,无法决定执行顺序,因此如果需要严格设定执行顺序,需要在 web.xml 中声明
- 如果既有在 web.xml 中声明的 Filter,也有通过注解配置的 Filter,那么会优先执行 web.xml 中配置的 Filter
- 在 web.xml 中,filter 执行顺序跟
- 响应时执行顺序:以相反的顺序执行