JavaWeb三大组件之一Filter(过滤器)

定义

拦截所有访问web资源的请求或者响应(servlet、Jsp页面、HTML页面),从而实现我们自己的业务逻辑,这些逻辑可以是实现访问权限的控制、过滤敏感词、压缩响应等功能。

原理 

过滤器是"链接"在容器的处理过程中的,它会在servlet处理器之前访问进入的请求,并且在响应信息返回客服端之前访问这些响应信息。这样就可以动态的修改请求和响应中的内容。

JavaWeb三大组件之一Filter(过滤器)_第1张图片

创建Filter

创建web项目:

JavaWeb三大组件之一Filter(过滤器)_第2张图片

JavaWeb三大组件之一Filter(过滤器)_第3张图片 

JavaWeb三大组件之一Filter(过滤器)_第4张图片

或者像这样建立web项目:

JavaWeb三大组件之一Filter(过滤器)_第5张图片 

JavaWeb三大组件之一Filter(过滤器)_第6张图片

JavaWeb三大组件之一Filter(过滤器)_第7张图片JavaWeb三大组件之一Filter(过滤器)_第8张图片 

JavaWeb三大组件之一Filter(过滤器)_第9张图片  

添加Tomcat服务器:

JavaWeb三大组件之一Filter(过滤器)_第10张图片 

如果没有SmartTomcat,只有Tomcat像下面图片中这样:

JavaWeb三大组件之一Filter(过滤器)_第11张图片 

则选择Tomcat里面的local,并向下面这样配置:

JavaWeb三大组件之一Filter(过滤器)_第12张图片 

JavaWeb三大组件之一Filter(过滤器)_第13张图片 

JavaWeb三大组件之一Filter(过滤器)_第14张图片 

启动程序:

 

 

 添加java包和servlet依赖:

JavaWeb三大组件之一Filter(过滤器)_第15张图片

创建过滤器并实现它的方法:

JavaWeb三大组件之一Filter(过滤器)_第16张图片 

在web.xml中注册Filter: 

JavaWeb三大组件之一Filter(过滤器)_第17张图片

 

当我们在执行的时候,发现会报404错误,那是因为我们没有重写Filter里面的init方法,在用Filter的时候必须重写init方法,因为web 工程启动的时候执行构造器方法和init 初始化方法 ,如果不重写初始化方法,就不会走过滤器。

重写Filter里面的init方法,然后执行过滤器:

JavaWeb三大组件之一Filter(过滤器)_第18张图片

 

JavaWeb三大组件之一Filter(过滤器)_第19张图片 

我们会发现在浏览器中什么都没有输出,但是控制台中输出了doFilter里面内容,说明我们的过滤器起作用了 ,他拦截了所有的请求。当我们在doFilter方法里面加上下面的逻辑,浏览器就会输出内容:

JavaWeb三大组件之一Filter(过滤器)_第20张图片 

 

JavaWeb三大组件之一Filter(过滤器)_第21张图片 

上面filterChain里面的doFilter方法它的作用就是请求放行到下一个资源,这个资源有可能是过滤器,也可能是客户端。

 

Filter的生命周期 

JavaWeb三大组件之一Filter(过滤器)_第22张图片 

上面每一步分别对应不同的方法:

实例化对应Filter的构造器方法,初始化对应init()方法、销毁对应的是destroy()方法 

Filter它是一个接口,该接口里面有如下几个方法:

 

destroy()

当web服务器调用该方法时,表示过滤器将被销毁。

init()

当web服务器调用该方法时,表示过滤器将被注册到服务中

doFilter()

当服务器调用Filter中的doFilter()方法,它会将每一个请求或者响应传递给下一个资源

具体实现:

JavaWeb三大组件之一Filter(过滤器)_第23张图片 

JavaWeb三大组件之一Filter(过滤器)_第24张图片 

1.可以看到Filter是在应用启动是被创建和初始化的。

 

JavaWeb三大组件之一Filter(过滤器)_第25张图片 

2.Filter是单例多线程的(创建和初始化只会被执行一次) 

3.doFilter()方法无论是那一个线程访问,只要由该Filter进行过滤,那么就会执行该Filter的doFilter()方法,并且是每过滤一次就会执行一次doFilter()。

JavaWeb三大组件之一Filter(过滤器)_第26张图片 

4.Filter中destroy方法是在应用被停止时调用的,它意味着销毁这个Filter。 

5.由于Filter是单列多线程的,所以为了保证线程安全,不能在Filter中定义可修改的成员变量,因为每个线程均可修改这个成员变量,这样就会带来线程安全问题。 

FilterConfig 

FilterConfig指的是Filter在web.xml中的注册信息 ,它将注册信息进行封装,然后通过形参的方式传给初始化方法。

FilterConfig里面的方法:

JavaWeb三大组件之一Filter(过滤器)_第27张图片 

演示使用:

package com.xihua;

import javax.servlet.*;
import java.io.IOException;
import java.util.Enumeration;


public class MyFilter implements Filter {
    private FilterConfig filterConfig;
    public MyFilter() {
        System.out.println("执行了MyFilter的构造方法");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        System.out.println("执行了init方法");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //获取过滤器的名字
        String filterName = filterConfig.getFilterName();
        System.out.println("过滤器的名字:" + filterName);
        //获取过滤器中所有的初始化参数名称
        Enumeration names = filterConfig.getInitParameterNames();
        while (names.hasMoreElements()){
            String name = names.nextElement();
            //获取过滤器中初始化参数对应的值
            String value = filterConfig.getInitParameter(name);
            System.out.println(name + "=" + value);
        }
        //获取全局域
        ServletContext sc = filterConfig.getServletContext();
        System.out.println("servletContext=" + sc);

        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println("执行了destory方法");
    }
}


    
        MyFilter
        com.xihua.MyFilter
        
            school
            xihua
        
        
            researcher
            jack
        
    

    
        MyFilter
        /*
    

运行结果:

JavaWeb三大组件之一Filter(过滤器)_第28张图片 

 

标签表示拦截匹配,也就是要拦截那些请求。

:要拦截的过滤器名称

:拦截那些路径

注意Filter中在写拦截所有路径的时候只能写成/*,而不能写成/,因为写成/它就不走拦截器中的doFilter方法了。 

在Servlet中/*即会拦截动态资源又会拦截静态资源,而/不会拦截动态资源

演示Filter拦截动态和静态资源如下:

package com.xihua;

import javax.servlet.*;
import java.io.IOException;
import java.util.Enumeration;


public class MyFilter implements Filter {
    public MyFilter() {
        System.out.println("执行了MyFilter的构造方法");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("执行了init方法");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("执行doFilter之前");
        System.out.println("执行doFilter之后");
    }

    @Override
    public void destroy() {
        System.out.println("执行了destory方法");
    }
}
package com.xihua.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class SomeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("执行SomeServlet");
    }
}


    
        MyFilter
        com.xihua.MyFilter
    
    
        MyFilter
        /*
    
    
    
        SomeServlet
        com.xihua.servlet.SomeServlet
    
    
        SomeServlet
        /SomeServlet
    

JavaWeb三大组件之一Filter(过滤器)_第29张图片 

JavaWeb三大组件之一Filter(过滤器)_第30张图片 

JavaWeb三大组件之一Filter(过滤器)_第31张图片  

当将Filter中的拦截改为/时,过滤器将不起作用:

JavaWeb三大组件之一Filter(过滤器)_第32张图片 

下面演示Servlet/*和/的区别: 

JavaWeb三大组件之一Filter(过滤器)_第33张图片 

JavaWeb三大组件之一Filter(过滤器)_第34张图片  

JavaWeb三大组件之一Filter(过滤器)_第35张图片 

JavaWeb三大组件之一Filter(过滤器)_第36张图片 

标签中可以不使用标签,但是需要指定,这样就能指定拦截某个servlet而不拦截其他请求:



    
        MyFilter
        com.xihua.MyFilter
    
    
        MyFilter
        
        SomeServlet
    
    
        SomeServlet
        com.xihua.servlet.SomeServlet
    
    
        SomeServlet
        /SomeServlet
    

 JavaWeb三大组件之一Filter(过滤器)_第37张图片

 

Filter里面的标签

dispatcher表示分发器,表示过滤器所拦截的资源被servlet容器调用的方式,可以是REQUEST,INCLUDE,FORWARD,ERROR中的任何一个,默认是REQUEST。用户可以设置多个子元素用来指定过滤器对资源的多种调用方式进行拦截。

FORWARD 表示当前过滤器只会拦截由一个Servlet通过RequestDispatcher的forward()完成跳转
INCLUDE 表示当前过滤器只会拦截由一个Servlet通过RequestDispatcher的include()完成跳转
REQUEST 表示当前过滤器会拦截普通请求,但对于forward()与include()的跳转不进行拦截,REQUEST是默认的。
ERROR 表示当跳转到指定的错误处理页面时,这个跳转请求会被当前过滤器拦截

下面演示上面四个子元素的区别:

两个servlet:SomeServlet、OtherServelt

package com.xihua.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class SomeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("执行SomeServlet");
        req.getRequestDispatcher("/otherServlet").forward(req,resp);
    }
}
package com.xihua.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class OtherServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("执行了otherServlet");
    }
}

 在xml文件做如下配置:



    
    
        MyFilter
        com.xihua.MyFilter
    
    
        MyFilter
        /*
    
    
    
        SomeServlet
        com.xihua.servlet.SomeServlet
    
    
        SomeServlet
        /someServlet
    
    
    
        OtherServlet
        com.xihua.servlet.OtherServlet
    
    
        OtherServlet
        /otherServlet
    

执行someServlet请求,因为在someServlet中我们设定了一个请求转发,观察拦截器的拦截效果:

JavaWeb三大组件之一Filter(过滤器)_第38张图片 

再来看一下在标签里面添加标签,并设定子元素为FORWARD:

    
        MyFilter
        /*
        FORWARD
    

JavaWeb三大组件之一Filter(过滤器)_第39张图片 

JavaWeb三大组件之一Filter(过滤器)_第40张图片   

将请求转发的关键字换成include:

JavaWeb三大组件之一Filter(过滤器)_第41张图片 

JavaWeb三大组件之一Filter(过滤器)_第42张图片  

出现上面的原因是因为:

JavaWeb三大组件之一Filter(过滤器)_第43张图片

JavaWeb三大组件之一Filter(过滤器)_第44张图片 

 

请求转发中forward和include的区别在于响应的标准输出流开启时间不一样,forward会请求传递给最后一个servlet,当最后一个servet执行完以后才会开启/返回响应。而include它是将其他请求包在第一个请求里面,并由第一个请求开启/返回响应。

 

Filter对请求和响应的修改 

JavaWeb三大组件之一Filter(过滤器)_第45张图片 

JavaWeb三大组件之一Filter(过滤器)_第46张图片 

JavaWeb三大组件之一Filter(过滤器)_第47张图片 

JavaWeb三大组件之一Filter(过滤器)_第48张图片 

多个Filter的执行顺序

两个Filter:MyFilter、UsFilter,在xml文件中先配置MyFilter,后配置UsFilter



    
    
        MyFilter
        com.xihua.MyFilter
    
    
        MyFilter
        /*
    

    
    
        UsFilter
        com.xihua.UsFilter
    
    
        UsFilter
        /*
    
    
    
        SomeServlet
        com.xihua.servlet.SomeServlet
    
    
        SomeServlet
        /someServlet
    

JavaWeb三大组件之一Filter(过滤器)_第49张图片 

JavaWeb三大组件之一Filter(过滤器)_第50张图片 

交换xml文件中的配置顺序:

JavaWeb三大组件之一Filter(过滤器)_第51张图片 

总结:多个Filter的执行顺序,与Filter的配置顺序有关。 

JavaWeb三大组件之一Filter(过滤器)_第52张图片 

Filter的执行原理 

Servlet的执行原理:在Servlet中有两个Map,这两个Map的key均为Servlet注册时的值,但value是不同的。第一个Map的value是Servlet实例对象的引用,第二个Map的value为的值,即Servlet类的全限定类名。

执行原理:

当对Servlet的请求到达Servlet容器时,会先对请求进行解析,使用该解析出的URL,作为比较对象,从第一个Map中查找是否有匹配的key,若不存在匹配的key,那么读取其value,即Servlet对象的引用,执行该Servlet的service()方法。

若不存在匹配的key ,那么再从第二个Map中查找是否有匹配的key。若存在,这读取其value,即读取其value,即要访问的Servlet的全限定类名。然后使用反射机制创建该Servlet实例,并将该实例写入到第一个Map中,然后在执行该Servlet的service()方法。

若第二个Map中也没有找到匹配的key,那么就跳转到错误处理页面404。

Filter的执行原理:

一个数组与一个Map :

一个Map:Map的key为的值,value为Filter实例对象的引用

一个数组:存在着与请求相匹配的所有Filter

执行原理:

当对某资源的请求到达Web容器时,会先对请求进行解析,使用解析出的URI作为比较对象,从Map中查找是否存在相匹配的key。若存在,那么读取其value,即Filter对象的引用,将该应用存入到数组中。然后继续向后查找,直到将Map查找完毕。这样在数组中就会存在按照查找顺序排好序的Filter引用。

数组初始化完毕后,开始按照数组元素顺序进行执行。所有数组中的Filter全部执行完毕后,再跳转到请求的目标资源。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(网络编程,servlet,前端)