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接口。
需要实现的方法有三个,他们分别是:
注:现setFilterConfig和getFilterConfig方法已取消,代之为init(FilterConfig config)和destory()方法。
init(FilterConfig filterConfig) |
doFilter(ServletRequest request, ServletResponse response, FilterChain chain) |
destroy() |
对于服务器的多次请求,doFilter,destroy这两个方法都会被调用。
FilterConfig接口有方法可以找到filter名字及初始化参数信息.服务器可以设置FilterConfig为空来指明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>
当有请求进入的时候,那么则有如下的过滤顺序(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