Filter过滤器学习

一、Filter简介

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


二、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_filter2filter-name>
        <filter-class>cn.itcast.a_filter_hello.HelloFilter2filter-class>
    filter>
    <filter-mapping>
        <filter-name>hello_filter2filter-name>
        

         
         
          
          

          
          <url-pattern>/*url-pattern>
          
          <dispatcher>REQUESTdispatcher>
          
    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>
    <init-param>
        <param-name>encodingparam-name>
        <param-value>UTF-8param-value>
    init-param>
    <init-param>
        <param-name>pathparam-name>
        <param-value>D:\Program Files (x86)param-value>
    init-param>
    <filter-name>HelloFilter.javafilter-name>
    <filter-class>cn.chenkefo_01.HelloFilterfilter-class>
  filter>
  <filter-mapping>
    <filter-name>HelloFilter.javafilter-name>
    
    <url-pattern>/*url-pattern>
  filter-mapping>

  <filter>
    <filter-name>HelloFilter2.javafilter-name>
    <filter-class>cn.chenkefo_01.HelloFilter2filter-class>
  filter>
  <filter-mapping>
    <filter-name>HelloFilter2.javafilter-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>encodingfilter-name>
    <filter-class>cn.chenkefo_01.EcodingFilterfilter-class>
  filter>
  <filter-mapping>
    <filter-name>encodingfilter-name>
    <url-pattern>/*url-pattern>
  filter-mapping>

你可能感兴趣的:(java,JavaWeb学习)