Filter

Filter

过滤器

Filter:过滤器,是 JavaWeb 三大组件之一,另外两个是 Servlet 和 Listener

工作流程:在程序访问服务器资源时,当一个请求到来,服务器首先判断是否有过滤器与去请求资源相关联,如果有过滤器可以将请求拦截下来,完成一些特定的功能,再由过滤器决定是否交给请求资源,如果没有就直接请求资源,响应同理

作用:过滤器一般用于完成通用的操作,例如:登录验证、统一编码处理、敏感字符过滤等


相关类

Filter

Filter是一个接口,如果想实现过滤器的功能,必须实现该接口

  • 核心方法

    方法 说明
    void init(FilterConfig filterConfig) 初始化,开启过滤器
    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 对请求资源和响应资源过滤
    void destroy() 销毁过滤器
  • 配置方式

    注解方式

    1
    2
    @WebFilter("/*")
    ()内填拦截路径,/*代表全部路径

    配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    <filter>
    <filter-name>filterDemo01</filter-name>
    <filter-class>filter.FilterDemo01</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>filterDemo01</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>

FilterChain

  • FilterChain 是一个接口,代表过滤器对象。由Servlet容器提供实现类对象,直接使用即可。

  • 过滤器可以定义多个,就会组成过滤器链

  • 核心方法:void doFilter(ServletRequest request, ServletResponse response) 用来放行方法

    如果有多个过滤器,在第一个过滤器中调用下一个过滤器,以此类推,直到到达最终访问资源。
    如果只有一个过滤器,放行时就会直接到达最终访问资源。

FilterConfig

FilterConfig 是一个接口,代表过滤器的配置对象,可以加载一些初始化参数

方法 作用
String getFilterName() 获取过滤器对象名称
String getInitParameter(String name) 获取指定名称的初始化参数的值,不存在返回null
Enumeration getInitParameterNames() 获取所有参数的名称
ServletContext getServletContext() 获取应用上下文对象

Filter使用

设置页面编码

请求先被过滤器拦截进行相关操作

过滤器放行之后执行完目标资源,仍会回到过滤器中

  • Filter 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @WebFilter("/*")
    public class FilterDemo01 implements Filter{
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    System.out.println("filterDemo01拦截到请求...");
    //处理乱码
    servletResponse.setContentType("text/html;charset=UTF-8");
    //过滤器放行
    filterChain.doFilter(servletRequest,servletResponse);
    System.out.println("filterDemo1放行之后,又回到了doFilter方法");
    }
    }
  • Servlet 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @WebServlet("/servletDemo01")
    public class ServletDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("servletDemo01执行了...");
    resp.getWriter().write("servletDemo01执行了...");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    doGet(req,resp);
    }
    }
  • 控制台输出:

    1
    2
    3
    filterDemo01拦截到请求...
    servletDemo01执行了...
    filterDemo1放行之后,又回到了doFilter方法

多过滤器顺序

多个过滤器使用的顺序,取决于过滤器映射的顺序。

  • 两个 Filter 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class FilterDemo01 implements Filter{
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    System.out.println("filterDemo01执行了...");
    filterChain.doFilter(servletRequest,servletResponse);
    }
    }
    public class FilterDemo02 implements Filter{
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    System.out.println("filterDemo02执行了...");
    filterChain.doFilter(servletRequest,servletResponse);
    }
    }
  • Servlet代码:System.out.println("servletDemo02执行了...");

  • web.xml配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <filter>
    <filter-name>filterDemo01</filter-name>
    <filter-class>filter.FilterDemo01</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>filterDemo01</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter>
    <filter-name>filterDemo02</filter-name>
    <filter-class>filter.FilterDemo02</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>filterDemo02</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
  • 控制台输出:

    1
    2
    3
    filterDemo01执行了
    filterDemo02执行了
    servletDemo02执行了...

在过滤器的配置中,有过滤器的声明和过滤器的映射两部分,到底是声明决定顺序,还是映射决定顺序呢?

答案是:<filter-mapping>的配置前后顺序决定过滤器的调用顺序,也就是由映射配置顺序决定。


Filter生命周期

**创建:**当应用加载时实例化对象并执行init()初始化方法

**服务:**对象提供服务的过程,执行doFilter()方法

销毁:当应用卸载时或服务器停止时对象销毁,执行destroy()方法

  • Filter代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    @WebFilter("/*")
    public class FilterDemo03 implements Filter{
    /*
    初始化方法
    */
    @Override
    public void init(FilterConfig filterConfig) {
    System.out.println("对象初始化成功了...");
    }
    /*
    提供服务方法
    */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    System.out.println("filterDemo03执行了...");
    //过滤器放行
    filterChain.doFilter(servletRequest,servletResponse);
    }
    /*
    对象销毁方法,关闭Tomcat服务器
    */
    @Override
    public void destroy() {
    System.out.println("对象销毁了...");
    }
    }

  • Servlet 代码:System.out.println("servletDemo03执行了...");

  • 控制台输出:

    1
    2
    3
    4
    对象初始化成功了...
    filterDemo03执行了...
    servletDemo03执行了...
    对象销毁了

FilterConfig使用

Filter初始化函数init的参数是FilterConfig 对象

  • Filter代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class FilterDemo04 implements Filter{

    //初始化方法
    @Override
    public void init(FilterConfig filterConfig) {
    System.out.println("对象初始化成功了...");

    //获取过滤器名称
    String filterName = filterConfig.getFilterName();
    System.out.println(filterName);

    //根据name获取value
    String username = filterConfig.getInitParameter("username");
    System.out.println(username);
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    System.out.println("filterDemo04执行了...");
    filterChain.doFilter(servletRequest,servletResponse);
    }
    @Override
    public void destroy() {}
    }
  • web.xml配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <filter>
    <filter-name>filterDemo04</filter-name>
    <filter-class>filter.FilterDemo04</filter-class>
    <init-param>
    <param-name>username</param-name>
    <param-value>zhangsan</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>filterDemo04</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
  • 控制台输出:

    1
    2
    3
    对象初始化成功了...
    filterDemo04
    zhangsan

拦截行为

Filter过滤器默认拦截的是请求,但是在实际开发中,我们还有请求转发和请求包含,以及由服务器触发调用的全局错误页面。默认情况下过滤器是不参与过滤的,需要配置web.xml

开启功能后,当访问页面发生相关行为后,会执行过滤器的操作

五种拦截行为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!--配置过滤器-->
<filter>
<filter-name>FilterDemo5</filter-name>
<filter-class>filter.FilterDemo5</filter-class>
<!--配置开启异步支持,当dispatcher配置ASYNC时,需要配置此行-->
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>FilterDemo5</filter-name>
<url-pattern>/error.jsp</url-pattern>
<!--<url-pattern>/index.jsp</url-pattern>-->
<!--过滤请求:默认值。-->
<dispatcher>REQUEST</dispatcher>
<!--过滤全局错误页面:开启后,当由服务器调用全局错误页面时,过滤器工作-->
<dispatcher>ERROR</dispatcher>
<!--过滤请求转发:开启后,当请求转发时,过滤器工作。-->
<dispatcher>FORWARD</dispatcher>
<!--过滤请求包含:当请求包含时,过滤器工作。它只能过滤动态包含,jsp的include指令是静态包含-->
<dispatcher>INCLUDE</dispatcher>
<!--过滤异步类型,它要求我们在filter标签中配置开启异步支持-->
<dispatcher>ASYNC</dispatcher>
</filter-mapping>

  • web.xml:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <filter>
    <filter-name>FilterDemo5</filter-name>
    <filter-class>filter.FilterDemo5</filter-class>
    <!--配置开启异步支持,当dispatcher配置ASYNC时,需要配置此行-->
    <async-supported>true</async-supported>
    </filter>
    <filter-mapping>
    <filter-name>FilterDemo5</filter-name>
    <url-pattern>/error.jsp</url-pattern>
    <dispatcher>ERROR</dispatcher>
    <filter-mapping>
  • ServletDemo03:

    1
    2
    3
    4
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("servletDemo03执行了...");
    int i = 1/ 0;
    }
  • FilterDemo05:

    1
    2
    3
    4
    5
    6
    7
    8
    public class FilterDemo05 implements Filter{
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    System.out.println("filterDemo05执行了...");
    //放行
    filterChain.doFilter(servletRequest,servletResponse);
    }
    }
  • 访问URL:http://localhost:8080/filter/servletDemo03

  • 控制台输出(注意输出顺序):

    1
    2
    servletDemo03执行了...
    filterDemo05执行了...

对比Servlet

方法/类型 Servlet Filter 备注
初始化 方法 void init(ServletConfig); void init(FilterConfig); 几乎一样,都是在web.xml中配置参数,用该对象的方法可以获取到。
提供服务方法 void service(request,response); void dofilter(request,response,FilterChain) Filter比Servlet多了一个FilterChain,它不仅能完成Servlet的功能,而且还可以决定程序是否能继续执行。所以过滤器比Servlet更为强大。 在Struts2中,核心控制器就是一个过滤器。
销毁方法 void destroy(); void destroy(); 方法/类型

Liste