欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Filter过滤器学习

程序员文章站 2022-05-23 08:46:06
...

一、Filter简介

 Filter也称之为过滤器,它是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
 Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,如下所示:
 Filter过滤器学习


二、Filer是如何实现拦截的?

 Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源进行拦截后,web服务器每次在调用web资源的service方法之前,都会先调用一下Filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
  (1)、调用目标资源之前,让一段代码执行
  (2)、是否调用目标资源(即是否让用户访问web资源)
     web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。
  (3)、调用目标资源之后,让一段代码执行
  


三、Filter开发入门

    Filter开发分为两个步骤:
  (1)、编写java类实现filter接口,并实现其doFilter方法。
  (2)、在 web.xml 文件中使用和元素对编写的filter类进行注册,并设置它所能拦截的资源


四、Filter链

    (1)、在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。
    (2)、web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。


五、Filter的生命周期

public void init(FilterConfig filterConfig) throws ServletException;//初始化

    和我们编写的Servlet程序一样,Filter的创建和销毁由WEB服务器负责。 web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(注:filter对象只会创建一次,init方法也只会执行一次。
    开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。


public void doFilter(ServletRequest request, ServletResponse response, 
                            FilterChain chain) throws IOException, ServletException;//拦截请求

    这个方法完成实际的过滤操作。当客户请求访问与过滤器关联的URL的时候,Servlet过滤器将先执行doFilter方法。FilterChain参数用于访问后续过滤器。

public void destroy();//销毁

    在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。


六、FilterConfig接口

    用户在配置filter时,可以使用为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。因此开发人员在编写filter时,通过filterConfig对象的方法,就可获得:
    String getFilterName():得到filter的名称。
    String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.
    Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。
    public ServletContext getServletContext():返回Servlet上下文对象的引用。

七、Filter的XML配置:

    <!-- 演示: 拦截指定的请求 -->
    <filter>
        <filter-name>hello_filter2</filter-name>
        <filter-class>cn.itcast.a_filter_hello.HelloFilter2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hello_filter2</filter-name>
        <!-- 1. 拦截所有
        <url-pattern>/*</url-pattern>
         -->

         <!-- 2. 拦截指定的jsp 
         <url-pattern>/index.jsp</url-pattern>
         <url-pattern>/list.jsp</url-pattern>
         -->
         <!-- 拦截所有的jsp
         <url-pattern>*.jsp</url-pattern>
          -->
          <!-- 3. 根据servlet的内部名称拦截
          <servlet-name>IndexServlet</servlet-name>
           -->
          <!-- 拦截指定的servlet 
          <url-pattern>/index</url-pattern>
          -->

          <!-- 4. 指定拦截指定的类型 -->
          <url-pattern>/*</url-pattern>
          <!-- 拦截直接访问的请求或者重定向的资源 -->
          <dispatcher>REQUEST</dispatcher>
          <!--<dispatcher>FORWARD</dispatcher>-->
    </filter-mapping>

代码演示:

第一个过滤器:
public class HelloFilter implements Filter {

    //创建实例
    public HelloFilter(){
        System.out.println("1.创建过滤器实例");
    }

    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
        System.out.println("2.执行过滤器初始化方法");
        //获取过滤器在web.xml中的配置的初始化参数
        String initParameter = filterConfig.getInitParameter("encoding");
        System.out.println("encoding:"+initParameter);
        //获取过滤器在web.xml中配置的初始化参数的名称
        Enumeration initParameterNames = filterConfig.getInitParameterNames();
        while(initParameterNames.hasMoreElements()){
            String nextElement = (String)initParameterNames.nextElement();
            String initParameter2 = filterConfig.getInitParameter(nextElement);
            System.out.println(nextElement+":"+initParameter2);
        }
    }

    // 过滤器业务处理方法:在请求到达Servlet之前先进入此方法处理公用的业务逻辑操作
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("3.执行过滤器业务处理方法");
        //放行(去到Servlet)
        //如果有下一个过滤器,进入下一个过滤器,否则就执行访问Servlet
        chain.doFilter(request, response);
        System.out.println("6.Servlet处理完成,又回到过滤器");
    }

    public void destroy() {
        // TODO Auto-generated method stub
        System.out.println("7.销毁过滤器实例");
    }

}
第二个过滤器:
public class HelloFilter2 implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("4.第二个过滤器");
        //放行
        chain.doFilter(request, response);
        System.out.println("5.第二个过滤器执行结束");
    }

    public void destroy() {
        // TODO Auto-generated method stub
    }

    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
    }
}
XML配置:
  <!--Filter配置  -->
  <filter>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>path</param-name>
        <param-value>D:\Program Files (x86)</param-value>
    </init-param>
    <filter-name>HelloFilter.java</filter-name>
    <filter-class>cn.chenkefo_01.HelloFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>HelloFilter.java</filter-name>
    <!-- 拦截所有资源 -->
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <filter>
    <filter-name>HelloFilter2.java</filter-name>
    <filter-class>cn.chenkefo_01.HelloFilter2</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>HelloFilter2.java</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

运行结果:

1.创建过滤器实例
2.执行过滤器初始化方法
encoding:UTF-8
path:D:\Program Files (x86)
encoding:UTF-8
3.执行过滤器业务处理方法
4.第二个过滤器
5.第二个过滤器执行结束
6.Servlet处理完成,又回到过滤器
7.销毁过滤器实例

应用实例-编码统一处理:

public class EcodingFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {
        // TODO Auto-generated method stub
        //转型
        final HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        //处理公用业务
        //解决中文乱码现象(仅Post有效)
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        /**
         * 出现get中文乱码,是因为在request.getParameter方法内部没有进行提交方式判断处理.
         * 解决:对指定接口的某一个方法进行功能扩展,可以使用代理,
         *     对request对象(目标对象),进行代理对象
         */
        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 {
                //定义方法返回值
                Object returnValue = null;
                //获取方法名称
                String methodName = method.getName();
                //判断:对getParameter方法的get提交进行中文处理
                if("getParameter".equals(methodName)){
                    //获取请求参数
                    String value = request.getParameter(args[0].toString());
                    //获取提交方式
                    String methodSubmit = request.getMethod();
                    //判断提交方式,若果是get提交,需要对数据进行处理(post提交以经处理过了)
                    if("GET".equals(methodSubmit)){
                        if(value!=null && !"".equals(value.trim())){
                            //处理get中文问题,先编码,在解码
                            returnValue = new String(value.getBytes("ISO8859-1"),"UTF-8");
                        }
                    }
                }else{
                    returnValue = method.invoke(request, args);
                }

                return returnValue;
            }
        });
        chain.doFilter(proxy, response);
    }

    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
        System.out.println("初始化完成");
    }


    public void destroy() {
        // TODO Auto-generated method stub

    }

}

过滤器配置:

  <filter>
    <filter-name>encoding</filter-name>
    <filter-class>cn.chenkefo_01.EcodingFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
相关标签: java