Servlet & JSP - Filter
过滤器可以对用户的请求拦截,进行预处理操作,接着将请求交给 Servlet 处理并生成响应,最后再对响应拦截,进行后处理操作。过滤器应用的场景有:用户登录、加密解密、会话校验等。
Filter API
过滤器必须继承 javax.servlet.Filter 接口。Filter 接口暴露三个生命周期方法:init、doFilter 和 destroy。
init: 当容器将过滤器引入服务的时候(通常是应用启动的时候),init 方法会被调用。Servlet 容器调用 init 方法时会传入一个 javax.servlet.FilterConfig 参数。FilterConfig 包含了过滤器的配置信息,如过滤器的名称、初始化参数、上下文环境等。
doFilter: 当过滤器关联的资源被请求时,doFilter 方法会被调用。doFilter 方法接收三个参数:ServletRequest、ServletResponse 和 FilterChain。ServletRequest 和 ServletResponse 是被拦截的请求和响应对象,我们可以对其做一些处理,如对请求设置属性或者在响应添加 HTTP 首部,甚至是使用装饰器来改变请求和响应的行为。调用 FilterChain 的 doFilter 方法将请求和响应传递至过滤器链的下一个过滤器或目标资源。在 filterChain.doFilter(request, response) 方法调用之前的操作是预处理,在 filterChain.doFilter(request, response) 方法调用之后的操作是后处理。
destroy: 当容器将过滤器移出服务的时候(通常是应用停止的时候),destroy 方法会被调用。
配置过滤器
1. 使用部署描述符配置:
<filter> <filter-name>myFilter</filter-name> <filter-class>com.huey.hello.filters.MyFilter</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2. 在 Servlet3.0 可以使用 @WebFilter 注解配置:
@WebFilter(filterName = "myFilter", urlPatterns = {"/*"}) public class MyFilter implements Filter { // ... }
过滤器的作用顺序
当多个过滤器作用在同一资源时,过滤器的作用顺序由其在部署描述符中的声明顺序决定,使用 @WebFilter 注解无法指定作用顺序。假设有 Filter1 和 Filter2 作用在同一个资源,且 Filter1 在 Filter2 之前声明,那么作用顺序为:Filter1 的预处理 ---> Filter2 的预处理 ---> 目标资源的处理 ---> Filter2 的后处理 ---> Filter1 的后处理。
应用示例
package com.huey.hello.filters; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.annotation.WebInitParam; import javax.servlet.http.HttpServletRequest; import com.huey.hello.wrapper.CharsetServletRequestWrapper; /** * 使用注解配置 Filter * urlPatterns 配置关联的目标资源 * initParams 配置初始参数 */ @WebFilter(filterName="charsetFilter", urlPatterns = {"/*"}, initParams = { @WebInitParam(name = "oldCharset", value = "ISO-8859-1"), @WebInitParam(name = "newCharset", value = "UTF-8"), }) public class CharsetFilter implements Filter { private String oldCharset; private String newCharset; @Override public void init(FilterConfig filterConfig) throws ServletException { oldCharset = filterConfig.getInitParameter("oldCharset"); newCharset = filterConfig.getInitParameter("newCharset"); } @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding(newCharset); response.setContentType("text/plain;charset=" + newCharset); HttpServletRequest httpRequest = (HttpServletRequest) request; CharsetServletRequestWrapper requestWrapper = new CharsetServletRequestWrapper(httpRequest, oldCharset, newCharset); chain.doFilter(requestWrapper, response); } }