15. JSP 过滤器

过滤器filter简介

Filter 是 Servlet 规范的三大组件之一另外两个分别是servlet和listener。filter中文意思是过滤,可以在请求到达目标资源之前先对请求进行拦截过滤,即对请求进行一些处理也可以在响应到达客户端之前先对响应进行拦截过滤,即对响应进行一些处理。
WEB开发人员通过Filter技术,可以对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息、计算系统的响应时间等一些高级功能

 

在 Servlet 规范中,有一个 javax.servlet.Filter 接口。实现了该接口的类称为过滤器,接口中有三个方法可以重写:

  • init():初始化方法,即 Filter 被创建后,在后面用到的资源的初始化工作,可以在这里完成。
  • doFilter():Filter 的核心方法,对于请求与响应的过滤,就是在这个方法中完成的。
  • destroy():销毁方法。 Filter 被销毁前所调用执行的方法。对于资源的释放工作,可以在这里完成。

这里主要是 doFilter 方法 ,他就是中间那个是过滤器,有两种可能 一种发给目标资源 一种返回去

创建Filter过滤器的步骤

1.创建一个类实现javax.servlet.Filter接口
2.重写接口中的方法
3.在web.xml文件中配置Filter

例:

1.Filter.java

package filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;


public class filter_test implements Filter {

  
    public filter_test() {
      
    }

    
    public void destroy() {
        System.out.println("过滤器已销毁×");
    }

    
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("过滤请求");
        
        chain.doFilter(request, response);    //通过过滤请求后 继续访问资源【如果没这句话 会直接返回给用户 用户就什么也不能干了 等于请求被拦截了】
        
        System.out.println("过滤响应");
    }


    public void init(FilterConfig fConfig) throws ServletException {
        System.out.println("过滤器已创建√");
    }

}

2.配置XML  【和Servlet配置差不多】

  <!-- 过滤器  和Servlet 配置的XML差不多的 -->
  <filter>
    <filter-name>filter_test</filter-name>
    <filter-class>filter.filter_test</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>filter_test</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

里面那个 /*  表示过滤任何的网址- 【可以过滤指定网址 * 为通配符】

注意:

1. 在Filter的doFilter方法内如果没有执行doFilter(request, response)方法,那么服务器中的资源是不会被访问到的。

2.Filter的全路径匹配只支持/*,不支持/

 

可以得出Filter的生命周期如下:

  • 当服务器启动,会创建Filter对象,并调用init方法,只调用一次.
  • 当访问资源时,路径与Filter的拦截路径匹配,会执行Filter中的doFilter方法,这个方法是真正拦截操作的方法.
  • 当服务器关闭时,会调用Filter的destroy方法来进行销毁操作.

一个Filter的生命周期跟servlet有些类似,需要经历实例化—>初始化—>doFilter—>销毁四个过程。

dispatcher 标签

在 filter-mapping 中还有一个子标签 dispatcher用于设置过滤器所过滤的请求类型
其有五种取值:REQUEST、FORWARD、INCLUDE、ASYNC、ERROR,默认是REQUEST

    • FORWARD【forward】
      若请求是由一个 Servlet 通过 RequestDispatcher 的 forward()方法所转发的, 那么这个请求将被值为 FORWARD 的 Filter 拦截。即当前 Filter 只会拦截由RequestDispatcher 的 forward()方法所转发的请求。其它请求均不拦截
    • INCLUDE【include】
      只要是通过<jsp:include page=”xxx.jsp” />,嵌入进来的页面,每嵌入的一个页面,都会走一次指定的过滤器
    • ERROR【error】
      在 web.xml 中可以配置错误页面 error-page当发生指定状态码的错误后,会跳转到指定的页面。而这个跳转同样是发出的请求。若的值设置为 EEROR,则当前过滤器只会拦截转向错误页面的请求,其它请求不会拦截。例:
    • <error-page>
          <error-code>404</error-code>
          <location>/error.jsp</location>
      </error-page>
  • ASYNC【async】

会拦截AsyncContext对象发出的请求

    • REQUEST 【request】
      默认值。即不设置 dispatcher 标签也相当于指定了其值为 REQUEST只要请求不是由 RequestDispatcher 的 forward()方法或 include()方法转发的那么该 Filter均会被拦截,即使是向错误页面的跳转请求,同样会被拦截

Filter特征

  1. Filter 是单例多线程的。
  2. Filter 是在应用被加载时创建并初始化这是与 Servlet 不同的地方Servlet 是在该 Servlet被第一次访问时创建 Filter 与 Servlet 的共同点是,其无参构造器与 init()方法只会执行一次
  3. 用户每提交一次该 Filter 可以过滤的请求,服务器就会执行一次 doFilter()方法即doFilter()方法是可以被多次执行的
  4. 当应用被停止时执行 destroy()方法,Filter 被销毁,即 destroy()方法只会执行一次
  5. 由于 Filter 是单例多线程的,所以为了保证其线程安全性,一般情况下是不为 Filter 类定义可修改的成员变量的因为每个线程均可修改这个成员变量,会出现线程安全问题

FilterConfig

在Filter中的init方法上有一个参数叫FilterConfig,这是Filter的配置对象通过FilterConfig对象可以获取当前 Filter 在 web.xml中的配置信息这与ServletConfig类似一个 Filter 对象一个 FilterConfig 对象,多个 Filter 对象会有多个 FilterConfig 对象。它的作用:

    • 获取Filter的名称
    • 获取初始化参数
    • 获取ServletContext对象
      FilterConfig 接口中的方法与 ServletConfig 接口中的方法,方法名与意义完全相同。【所以很好记住】

 所以 这玩意 和 Servlet 很相似:Servlet有初始化参数 他也有 、而且 一个Servlet 对应一个 Config 他也是,啥都差不多....

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>filter</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <filter>
    <filter-name>filter_test</filter-name>
    <filter-class>filter.filter_test</filter-class>
       <!-- 重点: 初始化对象要写在对应的 过滤器中! 除了ServletContext, Servlet的和 filter的都要写在指定的标签中  -->
    <init-param>
      <param-name>姓名</param-name>
      <param-value>小涵</param-value>
    </init-param>
    
    <init-param>
      <param-name>年龄</param-name>
      <param-value>20</param-value>
    </init-param>
    
    <init-param>
      <param-name>身高</param-name>
      <param-value>168</param-value>
    </init-param>
    
    <init-param>
      <param-name>爱好</param-name>
      <param-value>干饭</param-value>
    </init-param>
    
    <init-param>
      <param-name>工作</param-name>
      <param-value>打工人</param-value>
    </init-param>
    
  </filter>
  <filter-mapping>
    <filter-name>filter_test</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  

</web-app>

filter_test.java :【过滤器】

package filter;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;


public class filter_test implements Filter {

    FilterConfig fc = null;
    
    public filter_test() {
      
    }

    
    public void destroy() {
        System.out.println("过滤器已销毁×");
    }

    
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            System.out.println("监听器的名称:"  + this.fc.getFilterName());
            System.out.println("监听器的初始化对象:");
            //遍历
            Enumeration<String> parmenters = this.fc.getInitParameterNames();
            while(parmenters.hasMoreElements()) {
                String name = parmenters.nextElement();
                System.out.println("监听器初始化名:" + name  + " --- 监听器初始化值:" + fc.getInitParameter(name));
                    
            }
    }


    public void init(FilterConfig fConfig) throws ServletException {
        System.out.println("过滤器已创建√");
        this.fc = fConfig;
        if(fc != null) {
            System.out.println("获取fConfig成功!");
        }
    }

}

多个Filter的执行过程

若web应用中配置了多个 Filter,那么这些 Filter 的执行过程是以“链”的方式执行的。即会将这
些与请求相匹配的 Filter 串成一个可执行的“链”然后按照这个链中的顺序依次执行这些 Filter 在链中的顺序与它们在 web.xml 中的注册顺序相同,即 web.xml 中的注册顺序就是 Filter 的执行顺序。
一个 Filter 的执行完毕,转而执行另一个 Filter这个转向工作是由 FilterChain 的 doFilter()方法完成的当然,若当前 Filter 是最后一个 Filter,则 FilterChain 的 doFilter()会自动转向最终的请求资源
当请求到达 Filter 后,Filter 可以拦截到请求对象,并对请求进行修改。修改过后,再将
该修改过的请求转向下一个资源
当最终的资源执行完毕,并形成响应对象后,会按照请求访问 Filter 的倒序,再次访问Filter此时 Filter 可以拦截到响应对象,并对响应进行修改。最终,客户端可以收到已被修改过的响应

本文来自博客园,作者:咸瑜,转载请注明原文链接:https://www.cnblogs.com/bi-hu/p/14863182.html

原文地址:https://www.cnblogs.com/bi-hu/p/14863182.html