javaweb之Servlet(五)过滤器

过滤器介绍

过滤器是Servlet的高级特性之一,也别把它想得那么高深,只不过是实现Filter接口的Java类罢了!
javaweb之Servlet(五)过滤器
从上面的图可以发现,当浏览器发送请求给服务器的时候,先执行过滤器,然后才访问Web的资源。服务器响应Response,从Web资源抵达浏览器之前,也会途径过滤器。

过滤器可以做什么?
:过滤一些敏感的字符串【规定不能出现敏感字符串】、避免中文乱码【规定Web资源都使用UTF-8编码】、权限验证【规定只有带Session或Cookie的浏览器,才能访问web资源】等等等,过滤器的作用非常大,只要发挥想象就可以有意想不到的效果。

总结:当需要限制用户访问某些资源时、在处理请求时提前处理某些资源、服务器响应的内容对其进行处理再返回、我们就是用过滤器来完成的!

为什么要用过滤器?

这里用解决中文乱码为例。
1、如果没有用过滤器的话,发送http请求到 servlet 时,中文乱码是需要在代码中设定编码来解决的。
2、如果使用过滤器的话,只要我在过滤器中指定了编码,可以使全站的Web资源都是使用该编码,并且重用性是非常理想的!

过滤器 API

只要Java类实现了Filter接口就可以称为过滤器!
javaweb之Servlet(五)过滤器
其中init()和destory()方法就不用多说了,他俩跟Servlet是一样的。只有在Web服务器加载和销毁的时候被执行,只会被执行一次!

值得注意的是doFilter()方法,它有三个参数(ServletRequest,ServletResponse,FilterChain)从前两个参数我们可以发现:过滤器可以完成任何协议的过滤操作!

过滤器不单单只有一个,那么我们怎么管理这些过滤器呢?

答:在Java中就使用了链式结构。把所有的过滤器都放在FilterChain里边,如果符合条件,就执行下一个过滤器(如果没有过滤器了,就执行目标资源)。

使用过滤器

1、实现Filter接口的Java类就被称作为过滤器


  public class FilterDemo1 implements Filter {
      public void destroy() {
      }
  
      public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
  
          //执行这一句,说明放行(让下一个过滤器执行,如果没有过滤器了,就执行执行目标资源)
          chain.doFilter(req, resp);
      }
  
      public void init(FilterConfig config) throws ServletException {
          
      }
  }

2、过滤器部署

过滤器和Servlet是一样的,需要部署到Web服务器上的。

第一种方式:在web.xml文件中配置

1、<filter>用于注册过滤器

<filter>
           <filter-name>FilterDemo1</filter-name>
          <filter-class>FilterDemo1</filter-class>
          <init-param>
          <param-name>word_file</param-name>    
          <param-value>/WEB-INF/word.txt</param-value>
          </init-param>
 </filter>
  • <filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。
  • <filter-class>元素用于指定过滤器的完整的限定类名。
  • <init-param>元素用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,
  • <param-value>指定参数的值。在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。

2、<filter-mapping>元素用于设置一个Filter 所负责拦截的资源。

一个Filter拦截的资源可通过两种方式来指定Servlet 名称和资源访问的请求路径

<filter-mapping>
    <filter-name>FilterDemo1</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  • <filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字
  • <url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
  • <servlet-name>指定过滤器所拦截的Servlet名称。
  • <dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。

3、<dispatcher> 子元素可以设置的值及其意义:

  • REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
  • INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
  • FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
  • ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。

第二种方式:通过注解配置

@WebFilter(filterName = "FilterDemo1",urlPatterns = "/*")

上面的配置是“/*”,所有的Web资源都需要途径过滤器

如果想要部分的Web资源进行过滤器过滤则需要指定Web资源的名称即可!

3、过滤器的执行顺序

首先执行一个案例:

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

     System.out.println("准备放行");

     //执行这一句,说明放行(让下一个过滤器执行,或者执行目标资源)
     chain.doFilter(req, resp);

     System.out.println("放行完成");
 }

它的完整流程顺序是这样的:客户端发送http请求到Web服务器上,Web服务器执行过滤器,执行到”准备放行“时,就把字符串输出到控制台上,接着执行doFilter()方法,Web服务器发现没有过滤器了,就执行目标资源(也就是test.jsp)。目标资源执行完后,回到过滤器上,继续执行代码,然后输出”放行完成“

再看一个案例,写两个过滤器:

过滤器1

System.out.println("过滤器1开始执行");

 //执行这一句,说明放行(让下一个过滤器执行,或者执行目标资源)
 chain.doFilter(req, resp);

 System.out.println("过滤器1开始完毕");

过滤器2


System.out.println("过滤器2开始执行");
chain.doFilter(req, resp);
System.out.println("过滤器2开始完毕");

servlet

System.out.println("我是Servlet1");

当我们访问Servlet1的时候,看看控制台会出现什么:
javaweb之Servlet(五)过滤器
执行顺序是这样的:先执行FilterDemo1,放行,执行FilterDemo2,放行,执行Servlet1,Servlet1执行完回到FilterDemo2上,FilterDemo2执行完毕后,回到FilterDemo1上

**注意:**过滤器之间的执行顺序看在web.xml文件中mapping的先后顺序的,如果放在前面就先执行,放在后面就后执行!如果是通过注解的方式配置,就比较urlPatterns的字符串优先级

filter的三种典型应用

1、可以在filter中根据条件决定是否调用chain.doFilter(request, response)方法,即是否让目标资源执行
2、在让目标资源执行之前,可以对requestresponse作预处理,再让目标资源执行
3、在目标资源执行之后,可以捕获目标资源的执行结果,从而实现一些特殊的功能

上一篇:【自动驾驶】:卡尔曼滤波器Kalman Filter


下一篇:Django 路由系统