1、过滤器介绍
java中的Filter接口就是过滤器的接口,通过是实现该接口,就可以自定义过滤器。过滤器存在的目的就是对请求进行预处理和后处理。主要的过滤器有身份验证过滤器、数据压缩过滤器、加密过滤器、触发资源访问事件过滤器、图像转换过滤器、日志记录和审核过滤器、MIME-TYPE链过滤器、标记化过滤器、XSL/T过滤器(转换xml内容)。
2、过滤器的执行流程:
1、客户端发送请求
2、服务器接收到请求并将其交给指定Filter对请求进行预处理,并在FilterChain上传递,直到最后一个过滤器。请求在过滤器传递中,如果如果请求被被过滤器拦截,那么请求将不会到达Servlet,直接跳过步骤3。
3、Servlet对请求进行处理
4、返回过滤器,这时候可以对响应response进行修改
5、最后由服务器将处理的最后结果response返回给客户端
接下来我们再来看看Filter接口:
public interface Filter {
/**
* 实现类的构造方法是在服务器启动的时候执行,
* 即FIilter实例是在启动服务器的时候就创建好了
* 只执行一次
*/
// 在服务器启动的时候执行,执行一些初始化工作,只执行一次
public void init(FilterConfig config) throws ServletException;
/**
* FilterChain.doFilter(request, response)方法表示请求链
* 式向下传递(如果该Filter后面还有Filter,则将请求传给下一个Filter,
* 如果没有请求,则将请求传给Servlet处理,处理过后,再返回Filter中)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException;
/**
* 销毁释放资源是在服务器关闭的时候执行
*/
public void destroy();
}
其中有FilterConfig接口(其默认实现类为org.apache.catalina.core.ApplicationFilterConfig)的参数,其作用是通过该接口方法,获取声明式参数(即在声明Filter时使用init-param声明的参数)的值,那么我们来看看FilterConfig接口方法:
public interface FilterConfig {
// 获取Filter声明时的名字
public String getFilterName();
// 获得ServletContext实例
public ServletContext getServletContext();
// 通过参数名获取InitFilter的声明式参数
public String getInitParameter(String s);
// 获取所有的声明式参数的参数名
public Enumeration getInitParameterNames();
}
FilterChain接口(其默认实现类为org.apache.catalina.core.ApplicationFilterChain)的方法如下:
public interface FilterChain{
// 其中用用为让请求在Filter链中传递,如果没有下一个Filter,那么就传给Servlet处理
public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse)
throws IOException, ServletException;
}
3、过滤器的使用
接下来我们来看看过滤器的使用(使用过滤器处理请求编码的问题):
1、实现过滤器接口
public class EncodingFilter implements Filter {
private static final String DEFAULT_ENCODING = "UTF-8";
private static final String DEFAULT_BCHARSET = "ISO-8859-1";
private static final String GET_PARAMETER = "getParameter";
private static final String GET_PARAMETER_VALUES = "getParameterValues";
//
private String bCharset;
private String aCharset;
public void init(FilterConfig config) throws ServletException {
String encoding = config.getInitParameter("encoding");
String beforeCharset = config.getInitParameter("bcharset");
this.bCharset = beforeCharset == null ? DEFAULT_BCHARSET : beforeCharset;
this.aCharset = encoding == null ? DEFAULT_ENCODING : encoding;
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
// 对请求转型
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
// 处理POST请求的参数
request.setCharacterEncoding(aCharset);
response.setCharacterEncoding(aCharset);
// 处理GET请求的参数,当然,这个并不是必要的
HttpServletRequest proxy = (HttpServletRequest) Proxy.newProxyInstance(
request.getClass().getClassLoader(),
new Class[]{HttpServletRequest.class},
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
String requestType = request.getMethod();
Object result = method.invoke(request, args);
String methodName = method.getName();
if( GET_PARAMETER.equals(methodName)
&& "GET".equals(requestType)
&& result != null ) {
String rst = (String) result;
result = new String(rst.getBytes(bCharset), aCharset);
} else if( GET_PARAMETER_VALUES.equals(methodName)
&& "GET".equals(requestType)
&& result != null ) {
String[] rst = (String[]) result;
String[] temp = new String[rst.length];
for(int i = 0; i < rst.length; i++ ) {
temp[i] = new String(rst[i].getBytes(aCharset), bCharset);
}
result = temp;
}
return result;
}
});
chain.doFilter(proxy, response); // 传入代理对象
}
public void destroy() { }
}
2、过滤器配置
Filter和Servlet一样,都可以在web.xml中配置,也可以使用注解来实现配置,使用注解的优势在于操作简单,但缺点是,当有多个Filter时,其没办法控制Filter的执行顺序。
1) 在web.xml中配置
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.yanshujie.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在web.xml中配置时,Filter链执行的顺序为Filter配置的先后,先配置的先执行,后配置的后执行。
2) 使用注解
使用@WebFilter注解,可以实现Filter的配置,其属性和在xml中一样。在网上看到很多说使用Filter的类名来控制Filter的执行顺序,但我测试的时候还是没有实现顺序的控制。
其中,Filter可以配置的属性有:
其中dispatcherTypes的参数含义如下:
REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时(例如jsp:include 包含的页面请求),那么该过滤器将被调用。除此之外,该过滤器不会被调用。
FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。