目录
JavaWeb基础 (六):过滤器 Filter
Filter是拦截Request请求的对象:在用户的请求访问资源前处理ServletRequest以及ServletResponse,它可用于日志记录、加解密、Session检查、图像文件保护等。通过Filter可以拦截处理某个资源或者某些资源。也能够对传出的数据拦截
当一个资源或者某些资源需要被多个Filter所使用到,且它的触发顺序很重要时,只能通过部署描述(web.xml)来配置,注解配置不能设置过滤器的执行顺序。
本文介绍了Filter 过滤器相关概念,包含Filter、FilterConfg、FilterChain。
功能:
- 用来拦截传入的请求和传出的响应
- 修改或以某种方式处理正在客户端和服务端之间交换的数据流
使用:
- 与使用Servlet 类似,Filter 是JavaWeb 提供的一个接口,只需自定义一个类并实现该接口 javax.servlet.Filter
这个接口包含了Filter的3个生命周期:init、doFilter、destroy。
Filter 生命周期
Tomcat 是如何调用Filter的 (前提是配置了Filter):
当Tomcat 启动时,通过反射调用Filter 的无参构造函数创建对象,同时调用init 方法实现初始化。 每次请求时调用doFilter 方法,当Tomcat 服务关闭的时候,调用destroy 方法销毁对象。
-
Servlet 容器初始化Filter 时,会触发Filter 的init 方法,一般来说是在应用开始时(即启动Tomcat 服务时)。也就是说,init方法并不是在该Filter相关的资源使用到时才初始化的,而且这个方法只调用一次,用于初始化Filter。
void init(FilterConfig filterConfig) // FilterConfig实例是由Servlet容器传入init方法中的
-
当Servlet容器每次处理Filter相关的资源时,都会调用该Filter实例的doFilter方法。Filter的doFilter方法包含ServletRequest、ServletResponse、FilterChain这3个参数
void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
一个资源可能需要被多个Filter关联到(更专业一点来说,这应该叫作Filter链条/调用链),这时Filter.doFilter() 的方法将触发Filter链条中下一个Filter。只有在Filter链条中最后一个Filter里调用的FilterChain.doFilter(),才会触发处理资源的方法。
注意:doFilter 方法中处理完业务逻辑之后,必须添加filterChain.doFilter(servletRequest, servletResponse); 否则请求/响应无法向后传递,一直停留在Filter中,不会继续执行。
-
Filter接口中,最后一个方法是destroy,该方法在Servlet容器要销毁Filter时触发,一般在应用停止的时候进行调用。
Void destroy()
除非Filter在部署描述中被多次定义到,否则Servlet 窗口只会为每个Filter创建单一实例。也就是说Filter 是单例的。
Filter 如何配置
步骤:
- 首先需要确认,哪一些资源需要使用这个Filter 进行拦截
- 定义一个Filer 类并实现javax.servlet.Filter 接口
- 在web.xml 中 或是 使用@WebFilter() 注解配置该Filer 的实现类,配置对请求资源的拦截映射
FilterConfig 接口
-
访问ServleContext
ServletContext getServletContext()
-
获取Filter 的名称
String getFilterName()
-
获取Filter 配置时的初始化参数
Enumeration<String> getInitParameterNames() // 如果未配置初始化参数,则返回空的Enumeration 对象
String getInitParameter(String parameterName)
Filter 执行顺序:
如果多个Filter 应用于同一个资源,Filter的触发顺序则需要使用部署描述来管理Filter:web.xml中的配置顺序决定,使用注解配置无法决定Filter 的调用顺序
案例
使用场景:
- 统一处理编码
- 屏蔽敏感词
- 控制资源的访问权限
案例1:中文乱码问题
在form表单提交过来中文数据时,需要对ServletRequest 设置编码
req.setCharacterEncoding("UTF-8");
System.out.println(req.getParameter("value"));
若是使用Filter, 能在请求时,对所有已配置过滤映射的资源,进行拦截
public class CharacterFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("UTF-8"