1)JavaWEB 的一个重要组件,既可以对发送到 Servlet 的请求进行拦截,也可以对 Servlet 返回的响应进行拦截
2)Filter 是实现了 Filter 接口的 Java 类。与 Servlet 程序相似,它由 Servlet 容器进行调用和执行
3)Filter 程序需要在 web.xml 文件中进行注册和设置它所能拦截的资源:Filter 程序可以拦截 Jsp, Servlet, 静态图片文件和静态 html 文件
2.如何创建 Filter ,并运行 Filter
1)创建一个 Filter 类:实现 Filter 接口:public class HelloFilter implements Filter
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;
public class HelloFilter implements Filter {
@Override
public void destroy() {
System.out.println("destroy...");
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
System.out.println("doFilter...");
}
@Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("init...");
}
}
2)在 web.xml 文件中配置并映射该 Filter,其中 url-pattern 指定了该 Filter 可以拦截哪些资源,既可以通过那些 url 可以访问到该 Filter
(1)<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST. 可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截
①REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
②INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
③FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
④ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
<!-- 注册 Filter -->
<filter>
<filter-name>helloFilter</filter-name>
<filter-class>com.javaweb.filter.HelloFilter</filter-class>
<!-- 配置初始化参数 -->
<init-param>
<param-name>user</param-name>
<param-value>root</param-value>
</init-param>
</filter>
<!-- 配置 Filter -->
<filter-mapping>
<filter-name>helloFilter</filter-name>
<url-pattern>/app1/hello.jsp</url-pattern>
</filter-mapping>
3)Filter 相关的 API
(1)Filter 接口的:
①public void init(FilterConfig arg0):类似与 Servlet 的 init 方法,在创建 Filter 对象(Filter 对象在 Servlet 容器加载当前 WEB 应用时即被创建)后,立即被调用,且只被调用一次。该方法用于对当前的 Filter 进行初始化操作
----a. FilterConfig:类似于 ServletConfig String getFilterName() ServletContext getServletContext() String getInitParameter(String name) Enumeration getInitParameterNames()
----b. 可以在 web.xml 文件中配置当前 Filter 初始化参数,配置方式也和 Servlet 方式一致
②public void doFilter(ServletRequest arg0, ServletResponse arg1,FilterChain arg2):真正 Filter 的逻辑代码需要写在该方法中,每次拦截都会调用该方法。
----a. FilterChain : Filter 链,多个 Filter 可以构成一个 Filter 链。
---------void doFilter(ServletRequest request,ServletResponse response):把请求传给 Filter 链的下一个 Filter,若当前 Filter 是Filter 链的最后一个 Filter,将把请求给目标 Servlet(或JSP)
----b. 多个 Filter 拦截顺序和<filter-mapping> 配置顺序有关,靠前的先被调用。
③public void destroy()
(2)自定义的 HttpFilter
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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class HttpFilter implements Filter {
private FilterConfig filterConfig;
//不建议子类直接覆盖,若直接覆盖可能导致 FilterConfig 对象初始化失败
@Override
public void init(FilterConfig arg0) throws ServletException {
this.filterConfig = filterConfig;
init();
}
/**
* 供子类继承的初始化方法,可以通过 getFilterConfig() 方法获取 FilterConfige 对象
*/
protected void init() {}
public FilterConfig getFilterConfig() {
return filterConfig;
}
@Override
public void doFilter(ServletRequest req, ServletResponse rep,
FilterChain arg2) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) rep;
doFilter(request, response, arg2);
}
public abstract void doFilter(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException;
@Override
public void destroy() {
}
}
3.典型应用
1)使浏览器不缓存页面的过滤器:
(1)有 3 个 HTTP 响应头字段都可以禁止浏览器缓存当前页面,它们在 Servlet 中的示例代码如下:response.setDateHeader("Expires",-1); response.setHeader("Cache-Control","no-cache"); response.setHeader("Pragma","no-cache");
(2)并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用上面的三个响应头
public class NoCache extends HttpFilter {
@Override
public void doFilter(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
chain.doFilter(request, response);
}
}
2)字符编码的过滤器:通过配置参数encoding指明使用何种字符编码,以处理Html Form请求参数的中文问题
(1)
public class EncodingFilter extends HttpFilter {
private String encoding;
@Override
protected void init() {
encoding = getFilterConfig().getServletContext().getInitParameter("encoding");
}
public String getEncoding() {
return encoding;
}
@Override
public void doFilter(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding(encoding);
chain.doFilter(request, response);
}
}