Filter之我见

1.Filter的来源

        Filter 技术是servlet 2.3 新增加的功能。servlet2.3是sun公司于2000年10月发布的,它的开发者包括许多个人和公司团体,充分体现了sun公司所倡导的代码开放性 原则。在众多参与者的共同努力下,servlet2.3比以往功能都强大了许多,而且性能也有了大幅提高。

2.功能

       Filter对象起到的过滤的任务,在请求一个资源(servlert或者是静态内容)或是从资源返回的时候使用。 设计Filter的一些实际应用例子如下:

        * 1) Authentication Filters
        * 2) Logging and Auditing Filters
        * 3) Image conversion Filters
         * 4) Data compression Filters
         * 5) Encryption Filters
         * 6) Tokenizing Filters
         * 7) Filters that trigger resource access events
         * 8) XSL/T filters
         * 9) Mime-type chain Filter

      filter最重要的功能,它使用户可以改变一个request和修改一个response. Filter 不是一个servlet,它不能产生一个response,它能够在一个request到达servlet之前对request进行预处理,也可以在response离开servlet时处理response.换种说法,filter其实是一个“servlet chaining“(servlet 链).

3.Filter的是实现

        所有定义的Filter,都必须实现javax.servlet.Filter接口。

        需要实现的方法有三个,他们分别是:

       1. void setFilterConfig(FilterConfig config) //设置filter 的配置对象;
       2. FilterConfig getFilterConfig() //返回filter的配置对象;
       3. void doFilter(ServletRequest req,ServletResponse res,FilterChain chain) //执行filter 的工作.

       注:现setFilterConfig和getFilterConfig方法已取消,代之为init(FilterConfig config)和destory()方法。     

init(FilterConfig filterConfig)
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
destroy()
        init方法只会初始化一次,就是在初始化的时候,以后有要处理的请求的话,该方法不会再执行

        对于服务器的多次请求,doFilter,destroy这两个方法都会被调用。

        FilterConfig接口有方法可以找到filter名字及初始化参数信息.服务器可以设置FilterConfig为空来指明filter已经终结.

        每一个filter从doFilter()方法中得到当前的request及response.在这个方法里,可以进行任何的针对request及response的操作.(包括收集数据,包装数据等).filter调用chain.doFilter()方法把控制权交给下一个filter.一个filter在doFilter()方法中结束.如果一个filter想停止request处理而获得对response的完全的控制,那它可以不调用下一个filter.
          一个filter可以包装request 或response以改变几个方法和提供用户定制的属性.Api2.3提供了HttpServletRequestWrapper 和HttpServletResponseWrapper来实现.它们能分派最初的request和response.如果要改变一个方法的特性,必须继承wapper和重写方法.下面是一段简单的日志filter用来记录所有request的持续时间,并且获取配置的filter参数及名字
package com.cn.greenroom.flter;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class FilterOne implements Filter {
	
	FilterConfig filterConfig ;

	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("1 init >> ");
		this.filterConfig = filterConfig;
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		ServletContext context = filterConfig.getServletContext();
		//获取配置的filter的filtername
		String servletname = filterConfig.getFilterName();
		System.out.println("filerName:" + servletname);
		//获取该filter的配置参数
		Enumeration en = filterConfig.getInitParameterNames();
		while (en.hasMoreElements()) {
	           String property = (String)en.nextElement();
	           Object value = filterConfig.getInitParameter(property);
	           System.out.println("initParam:" + property + " " + value);
	        }
		//执行时间
		long bef = System.currentTimeMillis();
		chain.doFilter(request, response);
		System.out.println(System.currentTimeMillis());
		long aft = System.currentTimeMillis();
		context.log("Request to " + request.getLocalAddr()	+ ": " + (aft-bef));
	}

	public void destroy() {
		System.out.println("1 destroy >> ");
	}

}
          只是有Fiter的定义还是不够的,还需要将其配置到web.xml中
<!-- 在web.xml中定义一个filter --> 
  <filter>
  	<filter-name>filterOne</filter-name>
  	<filter-class>com.cn.greenroom.flter.FilterOne</filter-class>
  	<init-param>
  		<param-name>name</param-name>
  		<param-value>value</param-value>
  	</init-param>
  </filter>
<!-- 定义该filer所起作用的url请求 -->
	<filter-mapping>
		<filter-name>filterOne</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

4.多个filter过滤的过程

    当web.xml中配置了过个filter的时候,如下所示的配置
	<filter>
		<filter-name>filterOne</filter-name>
		<filter-class>com.cn.greenroom.flter.FilterOne</filter-class>
		<init-param>
			<param-name>name</param-name>
			<param-value>value</param-value>
		</init-param>
	</filter>
	<filter>
		<filter-name>filterTwo</filter-name>
		<filter-class>com.cn.greenroom.flter.FilterTwo</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>filterTwo</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<filter-mapping>
		<filter-name>filterOne</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>


    对于init方法,则其执行顺序则是  FilterOne.init()  -> FilterTwo.init() ;(该顺序与filter配置的先后有关)

   当有请求进入的时候,那么则有如下的过滤顺序(Filter执行的先后顺序与filter-mapping有关)

   req ->   FilterTwo.doFilter  -> FilterOne.doFilter() -> FilterOne.destroy() -> FilterTwo.destroy() ;

5.常用的encodingFilter

       对于中文系统的j2ee项目,经常碰到乱码的问题,常用的做法就是添加一个过滤器,然后将所有的请求都转换为utf-8编码一下是该过滤器的实例

    ①在web.xml中添加如下的配置

          <filter>
	       <filter-name>characterEncoding</filter-name>
		 <filter-class>com.cn.greenroom.flter.CharacterEncodingFilter</filter-class>
	         <init-param>
                     <param-name>encoding</param-name>
                     <param-value>utf-8</param-value>
                </init-param>
	</filter>
	
	<filter-mapping>
		<filter-name>characterEncoding</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
   ② CharacterEncodingFilter.java

  

package com.cn.greenroom.flter;

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 CharacterEncodingFilter implements Filter{

    // encoding type
    protected String encoding = null;
   // filter config
    protected FilterConfig filterConfig = null;
   //whether ignore the encoding type
    protected boolean ignore = true;
    /**
     * destroy the filter
     */
    public void destroy() {
        this.encoding = null;
        this.filterConfig = null;
    }
    
    /**
     * do filte
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
          throws IOException, ServletException {
        // encoding logic
        if (ignore || (request.getCharacterEncoding() == null)) {
            String encoding = selectEncoding(request);
            if (encoding != null) {
                request.setCharacterEncoding(encoding);
            } else {
                
            }
        }
        // pass request,response to the next filter
        chain.doFilter(request, response);
    }

    /**
     *  init filter
     */
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        this.encoding = filterConfig.getInitParameter("encoding");
        String value = filterConfig.getInitParameter("ignore");
        if (value == null)
            this.ignore = true;
        else if (value.equalsIgnoreCase("true"))
            this.ignore = true;
        else if (value.equalsIgnoreCase("yes"))
            this.ignore = true;
        else
            this.ignore = false;
    }
    
    /**
     * Get ignore flag
     * @return
     */
    public boolean getIgnore(){
    	return this.ignore;
    }
    
    /**
     *  return the encoding type
     * @param request
     * @return
     */
    public String selectEncoding(ServletRequest request) {
        return (this.encoding);
    } 
    
    /**
     * Get filterConfig
     * @return
     */
    public FilterConfig getFilterConfig(){
    	return this.filterConfig;
    }

}


当访问该项目中的任何路径时,都使用该过滤器对其进行设置编码方式了。

6.Spring中该编码过滤器的设置

直接配置

    <!-- Filter 定义  -->
    <!-- Character Encoding filter -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

spring中是通过org.springframework.web.filter.CharacterEncodingFilter这个类来设置的。Spring中初始化则是在其公共父类抽象类GenericFilterBean中 在GenericFilterBean中有一个静态的私有类FilterConfigPropertyValues  该类负责解析所有的配置初始化参数,其解析的具体方法如下:

     Enumeration en = config.getInitParameterNames();
      while (en.hasMoreElements()) {
        String property = (String)en.nextElement();
        Object value = config.getInitParameter(property);
        addPropertyValue(new PropertyValue(property, value));
        if (missingProps != null) {
          missingProps.remove(property);
        }

      }
还有一个直接父类OncePerRequestFilter  用来保证所有的Spring中的filter都执行一次该类并且提供一个公共接口方法doFilterInternal,其所有的Filter只要实现doFilterInternal就可以了。

关于springFilter的详细解析,请参考:http://blog.csdn.net/kiss_vicente/article/details/7599186


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值