Filter学习笔记

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:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值