Servlet过滤器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Servlet过滤器相关的知识,希望对你有一定的参考价值。

一、Filter的介绍及使用

什么是过滤器?

与Servlet相似,过滤器是一些web应用程序组件,可以绑定到一个web应用程序中。但是与其他web应用程序组件不同的是,过滤器是"链"在容器的处理过程中的。这就意味着它们会在servlet处理器之前访问一个进入的请求,并且在外发响应信息返回到客户前访问这些响应信息。这种访问使得过滤器可以检查并修改请求和响应的内容。

过滤器适用于那些地方?

l  为一个web应用程序的新功能建立模型(可被添加到web应用程序中或者从web应用程序中删除而不需要重写基层应用程序代码);

l  向过去的代码添加新功能。

过滤器放在容器结构的什么位置?

过滤器放在web资源之前,可以在请求抵达它所应用的web资源(可以是一个Servlet、一个Jsp页面,甚至是一个html页面)之前截获进入的请求,并且在它返回到客户之前截获输出请求。Filter:用来拦截请求,处于客户端与被请求资源之间,目的是重用代码。Filter链,在web.xml中哪个先配置,哪个就先调用。在filter中也可以配置一些初始化参数。

Java中的Filter 并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。 

Filter 有如下几个用处:

l  在HttpServletRequest 到达Servlet 之前,拦截客户的HttpServletRequest 。 

l  根据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。 

l  在HttpServletResponse 到达客户端之前,拦截HttpServletResponse 。 

l  根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。

Filter 有如下几个种类:

l  用户授权的Filter: Filter 负责检查用户请求,根据请求过滤用户非法请求。 

l  日志Filter: 详细记录某些特殊的用户请求。 

l  负责解码的Filter: 包括对非标准编码的请求解码。 

l  能改变XML 内容的XSLTFilter 等。 

一个Filter 可负责拦截多个请求或响应:一个请求或响应也可被多个请求拦截。 

创建一个Filter 只需两个步骤: 
(1)创建Filter 处理类: 

(2)在web.xml 文件中配置Filter 。 
创建Filter 必须实现javax.servlet.Filter 接口,在该接口中定义了三个方法。 
• void init(FilterConfig config): 用于完成Filter 的初始化。 
• void destroy(): 用于Filter 销毁前,完成某些资源的回收。 
• void doFilter(ServletRequest request, ServletResponse response,FilterChain chain): 实现过滤功能,该方法就是对每个请求及响应增加的额外处理。 

过滤器Filter也具有生命周期:init()->doFilter()->destroy(),由部署文件中的filter元素驱动。在servlet2.4中,过滤器同样可以用于请求分派器,但须在web.xml中声明,<dispatcher>INCLUDE或FORWARD或REQUEST或ERROR</dispatcher>该元素位于filter-mapping中。 

Filter常用的场景:

一个实例

首先来看一下web.xml的配置:

   

 <!-- 请求url日志记录过滤器 -->    

    <filter>    
        <filter-name>logfilter</filter-name>    
        <filter-class>com.weijia.filterservlet.LogFilter</filter-class>    
    </filter>    
    <filter-mapping>    
        <filter-name>logfilter</filter-name>    
        <url-pattern>/*</url-pattern>    
    </filter-mapping>  
      
<!-- 编码过滤器 -->    
    <filter>    
        <filter-name>setCharacterEncoding</filter-name>    
        <filter-class>com.weijia.filterservlet.EncodingFilter</filter-class>    
        <init-param>    
            <param-name>encoding</param-name>    
            <param-value>utf-8</param-value>    
        </init-param>    
    </filter>    
    <filter-mapping>    
        <filter-name>setCharacterEncoding</filter-name>    
        <url-pattern>/*</url-pattern>    
    </filter-mapping>    

 

然后看一下编码过滤器:

package com.weijia.filterservlet;  
  
import java.io.IOException;  
import java.util.Enumeration;  
import java.util.HashMap;  
  
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 EncodingFilter implements Filter {    
    private String encoding;    
    private HashMap<String,String> params = new HashMap<String,String>();    
    // 项目结束时就已经进行销毁    
    public void destroy() {    
        System.out.println("end do the encoding filter!");    
        params=null;    
        encoding=null;    
    }    
    public void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, ServletException {    
        System.out.println("before encoding " + encoding + " filter!");    
        req.setCharacterEncoding(encoding);    
        chain.doFilter(req, resp);          
        System.out.println("after encoding " + encoding + " filter!");    
        System.err.println("----------------------------------------");    
    }    
     
    // 项目启动时就已经进行读取    
    public void init(FilterConfig config) throws ServletException {    
        System.out.println("begin do the encoding filter!");    
        encoding = config.getInitParameter("encoding");    
        for (Enumeration<?> e = config.getInitParameterNames(); e.hasMoreElements();) {    
            String name = (String) e.nextElement();    
            String value = config.getInitParameter(name);    
            params.put(name, value);    
        }    
    }    
 }    

 


日志过滤器:

package com.weijia.filterservlet;  
  
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;  
import javax.servlet.http.HttpServletRequest;  
  
public class LogFilter implements Filter {    
      
    public FilterConfig config;    
     
    public void destroy() {    
        this.config = null;    
        System.out.println("end do the logging filter!");  
    }    
     
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {    
        System.out.println("before the log filter!");    
        // 将请求转换成HttpServletRequest 请求    
        HttpServletRequest hreq = (HttpServletRequest) req;    
        // 记录日志    
        System.out.println("Log Filter已经截获到用户的请求的地址:"+hreq.getServletPath() );    
        try {    
            // Filter 只是链式处理,请求依然转发到目的地址。    
            chain.doFilter(req, res);    
        } catch (Exception e) {    
            e.printStackTrace();    
        }    
        System.out.println("after the log filter!");    
    }    
     
    public void init(FilterConfig config) throws ServletException {    
        System.out.println("begin do the log filter!");    
        this.config = config;    
    }    
     
 }    

 


测试Servlet:

package com.weijia.filterservlet;  
  
import java.io.IOException;  
  
import javax.servlet.ServletException;  
import javax.servlet.http.HttpServlet;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
  
public class FilterServlet extends HttpServlet {  
  
    private static final long serialVersionUID = 1L;  
  
    public void doGet(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
        response.setDateHeader("expires", -1);  
    }  
  
    public void doPost(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
    }  
  
}  

访问FilterServlet

运行结果:

before the log filter!
Log Filter已经截获到用户的请求的地址:/FilterServlet
before encoding utf-8 filter!
after encoding utf-8 filter!
----------------------------------------
after the log filter!


我们从运行结果可以看到这个过滤器的调用关系:

技术分享

类似于C++中的构造函数和析构函数的调用顺序,

这里我们在web.xml中注册的是先注册日志过滤器的,然后再注册

 

当我们重新部署应用的时候发现:

技术分享

会先销毁上次的过滤器,然后再重新注册一下

以上是关于Servlet过滤器的主要内容,如果未能解决你的问题,请参考以下文章

是否可以编写一个 servlet 过滤器来检查 HTTP 响应代码? [复制]

Servlet过滤器行为模棱两可?

servlet 过滤器(Filter)

javaweb-Servlet过滤器Filter

为什么我不能在此片段中生成唯一对象数组?

servlet 过滤器中的 StringBuffer 与 StringBuilder