码迷,mamicode.com
首页 > 其他好文 > 详细

过滤器 Filter

时间:2016-07-08 11:35:47      阅读:145      评论:0      收藏:0      [点我收藏+]

标签:

Filter(过滤器)简介

Filter 的基本功能是对发送到 Servlet 的请求进行拦截, 并对响应也进行拦截.

Filter 程序是一个实现了 Filter 接口的 Java 类,与 Servlet 程序相似,它由 Servlet 容器进行调用和执行

Filter 程序需要在 web.xml 文件中进行注册和设置它所能拦截的资源:Filter 程序可以拦截 Jsp, Servlet, 静态图片文件和静态 html 文件

技术分享

如何创建一个 Filter

①. 创建一个 Filter 类: 实现 Filter 接口: public class HelloFilter implements Filter

②. 在 web.xml 文件中配置并映射该 Filter. 其中 url-pattern 指定该 Filter 可以拦截哪些资源, 即可以通过哪些 url 访问到该 Filter

<!-- 注册 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>
</filter-mapping>

 Filter 相关的 API:

①. Filter 接口:

    > public void init(FilterConfig filterConfig): 类似于 Servlet 的 init 方法. 在创建 Filter 对象(Filter 对象在 Servlet 容器加载当前 WEB 应用时即被创建)后, 立即被调用, 且只被调用一次. 该方法用于对当前的 Filter 进行初始化操作. Filter 实例是单例的.

    *  FilterConfig 类似于 ServletConfig

    * 可以在 web.xml 文件中配置当前 Filter 的初始化参数. 配置方式也和 Servlet 类似

        <filter>
            <filter-name>helloFilter</filter-name>
            <filter-class>com.atguigu.javaweb.HelloFilter</filter-class>
            <init-param>
                <param-name>name</param-name>
                <param-value>root</param-value>
            </init-param>
        </filter>

    > public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain): 真正 Filter 的逻辑代码需要编写在该方法中. 每次拦截都会调用该方法.

    * FilterChain: Filter 链. 多个 Filter 可以构成一个 Filter 链.    

               技术分享

      - doFilter(ServletRequest request, ServletResponse response):

        把请求传给 Filter 链的下一个 Filter,若当前 Filter 是 Filter 链的最后一个 Filter, 将把请求给到目标 Serlvet(或 JSP)   

      - 多个 Filter 拦截的顺序和 <filter-mapping> 配置的顺序有关, 靠前的先被调用.

    理解 Filter 链:

    技术分享

  > public void destroy(): 类似于 Servlet 的destroy() 方法; 释放当前 Filter 所占用的资源的方法. 在 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-mapping>
    <filter-name>secondFilter</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 响应头字段都可以禁止浏览器缓存当前页面,它们在 Servlet 中的示例代码如下:

response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache"); 

  并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用上面的三个响应头

2. 解决字符编码的过滤器

  通过配置参数encoding指明使用何种字符编码,以处理Html Form请求参数的中文问题

3. 检验用户是否登录的过滤器

 HttpServletWrapper 和 HttpServletResponseWrapper

1). Servlet API 中提供了一个 HttpServletRequestWrapper 类来包装原始的 request 对象,HttpServletRequestWrapper 类实现了 HttpServletRequest 接口中的所有方法,
  这些方法的内部实现都是仅仅调用了一下所包装的的 request 对象的对应方法

//包装类实现 ServletRequest 接口.
public class ServletRequestWrapper implements ServletRequest {

    //被包装的那个 ServletRequest 对象
    private ServletRequest request;
    
    //构造器传入 ServletRequest 实现类对象
    public ServletRequestWrapper(ServletRequest request) {
        if (request == null) {
            throw new IllegalArgumentException("Request cannot be null");   
        }
        this.request = request;
    }

    //具体实现 ServletRequest 的方法: 调用被包装的那个成员变量的方法实现。
    public Object getAttribute(String name) {
        return this.request.getAttribute(name);
    }

    public Enumeration getAttributeNames() {
        return this.request.getAttributeNames();
    }    
    
    //...    
}    

 相类似 Servlet API 也提供了一个 HttpServletResponseWrapper 类来包装原始的 response 对象

2). 作用: 用于对 HttpServletRequest 或 HttpServletResponse 的某一个方法进行修改或增强.

public class MyHttpServletRequest extends HttpServletRequestWrapper{

    public MyHttpServletRequest(HttpServletRequest request) {
        super(request);
    }
    
    @Override
    public String getParameter(String name) {
        String val = super.getParameter(name);
        if(val != null && val.contains(" fuck ")){
            val = val.replace("fuck", "****");
        }
        return val;
    }
}

3). 使用: 在 Filter 中, 利用 MyHttpServletRequest 替换传入的 HttpServletRequest

HttpServletRequest req = new MyHttpServletRequest(request);
filterChain.doFilter(req, response);

此时到达目标 Servlet 或 JSP 的 HttpServletRequest 实际上是 MyHttpServletRequest

自定义HttpFilter 类

/**
 * 自定义的 HttpFilter, 实现自 Filter 接口
 *
 */
public abstract class HttpFilter implements Filter {
	/**
	 * 用于保存 FilterConfig 对象. 
	 */
	private FilterConfig filterConfig;
	
	/**
	 * 不建议子类直接覆盖. 若直接覆盖, 将可能会导致 filterConfig 成员变量初始化失败
	 */
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		this.filterConfig = filterConfig;
		init();
	}

	/**
	 * 供子类继承的初始化方法. 可以通过 getFilterConfig() 获取 FilterConfig 对象. 
	 */
	protected void init() {}

	/**
	 * 直接返回 init(ServletConfig) 的 FilterConfig 对象
	 */
	public FilterConfig getFilterConfig() {
		return filterConfig;
	}
	
	/**
	 * 原生的 doFilter 方法, 在方法内部把 ServletRequest 和 ServletResponse 
	 * 转为了 HttpServletRequest 和 HttpServletResponse, 并调用了 
	 * doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
	 * 
	 * 若编写 Filter 的过滤方法不建议直接继承该方法. 而建议继承
	 * doFilter(HttpServletRequest request, HttpServletResponse response, 
	 *		FilterChain filterChain) 方法
	 */
	@Override
	public void doFilter(ServletRequest req, ServletResponse resp,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
		
		doFilter(request, response, chain);
	}
	
	/**
	 * 抽象方法, 为 Http 请求定制. 必须实现的方法. 
	 * @param request
	 * @param response
	 * @param filterChain
	 * @throws IOException
	 * @throws ServletException
	 */
	public abstract void doFilter(HttpServletRequest request, HttpServletResponse response, 
			FilterChain filterChain) throws IOException, ServletException;

	/**
	 * 空的 destroy 方法。 
	 */
	@Override
	public void destroy() {}

}

 

过滤器 Filter

标签:

原文地址:http://www.cnblogs.com/linyueshan/p/5648332.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!