Filter基础知识
一、简介
作用:对Servlet容器调用Servlet的过程进行拦截,从而在Servlet进行响应处理的前后实现一些特殊的功能。
过滤器 API:Filter,FilterChain,FilterConfig。
Filter 程序:实现了 Filter 接口的 Java 类,由Servlet容器进行调用和执行,需要在 web.xml 中进行注册和设置它所能拦截的资源。
原理:Filter可以对Servlet容器发送给Servlet程序的请求和Servlet程序回送给Servlet容器的响应进行拦截。可以决定是否将请求继续传递给Servlet程序,以及对请求和响应信息是否进行修改。
二、使用方法
1)void init(FilterConfig filterConfig)
作用:类似于 Servlet 的 init 方法。在创建 Filter 对象(Filter 对象在 Servlet 容器加载当前 WEB 应用时即被创建)后,立即被调用, 且只被调用一次。该方法用于对当前的 Filter 进行初始化操作。Filter 实例是单例的。
- FilterConfig 类似于 ServletConfig
- 可以在 web.xml 文件中配置当前 Filter 的初始化参数. 配置方式也和 Servlet 类似。
2)void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
作用:真正 Filter 的逻辑代码需要编写在该方法中。每次拦截都会调用该方法。
参数:FilterChain:Filter 链。多个 Filter 可以构成一个 Filter 链。
- chain.doFilter(ServletRequest request, ServletResponse response):把请求传给 Filter 链的下一个 Filter,若当前 Filter 是 Filter 链的最后一个 Filter,将把请求给到目标 Serlvet(或 JSP)。
- 多个 Filter 拦截的顺序和 <filter-mapping> 配置的顺序有关,靠前的先被调用。
3)public void destroy()
释放当前 Filter 所占用的资源的方法。在 Filter 被销毁之前被调用,且只被调用一次。
public class HelloFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)
throws IOException, ServletException {//放行 chain.doFilter(request, response); } @Override public void destroy() { } }
web.xml
url-pattern:指定该 Filter 可以拦截哪些资源,即可以通过哪些 url 访问到该 Filter。
<dispatcher>:指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截
- REQUEST:当用户直接访问页面时,Web 容器将会调用过滤器。如果目标资源是通过 RequestDispatcher 的 include() 或 forward() 方法访问时,那么该过滤器就不会被调用。通过 GET 或 POST 请求直接访问。
- FORWARD:如果目标资源是通过 RequestDispatcher 的 forward() 方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。或 <jsp:forward page="/..." /> 或 通过 page 指令的 errorPage 转发页面. <%@ page errorPage="test.jsp" %>
- INCLUDE:如果目标资源是通过 RequestDispatcher 的 include() 方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。或 <jsp:include file="/..." />
- ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。在 web.xml 文件中通过 error-page 节点进行声明:
<error-page> <exception-type>java.lang.ArithmeticException</exception-type> <location>/test.jsp</location> </error-page>
<!-- 注册 Filter --> <filter> <filter-name>helloFilter</filter-name> <filter-class>com.atguigu.javaweb.HelloFilter</filter-class> </filter> <!-- 映射 Filter --> <filter-mapping> <filter-name>helloFilter</filter-name> <url-pattern>/test.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
三、应用
1. 使浏览器不缓存页面的过滤器
有3个HTTP响应头字段都可以禁止浏览器缓存当前页面
- HttpServletResponse.setDataHeader("Expires", -1);
- HttpServletResponse.setHeader("Cache-Control", "no-cache");
- HttpServletResponse.setHeader("Pragma", "no-cache");
//HttpFilter的实现与HttpServlet相似
public class NoCacheFilter extends HttpFilter { @Override public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { response.setDateHeader("Expires",-1); response.setHeader("Cache-Control","no-cache"); response.setHeader("Pragma","no-cache"); filterChain.doFilter(request, response); } }
2. 字符编码的过滤器
目标:让所有的页面都不会出现字符编码问题,为此需要添加一个过滤器
EncodingFilter.java
public class EncodingFilter extends HttpFilter{ private String encoding; @Override protected void init() { encoding = getFilterConfig().getServletContext().getInitParameter("encoding"); } @Override public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { System.out.println(encoding); request.setCharacterEncoding(encoding); filterChain.doFilter(request, response); } }
web.xml
<context-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </context-param> <filter> <filter-name>encodingFilter</filter-name> <filter-class>com.atguigu.javaweb.encoding.EncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>