服务器之家

服务器之家 > 正文

Java过滤器filter_动力节点Java学院整理

时间:2020-12-06 15:26     来源/作者:fjdingsd

filter过滤器技术。通过过滤器,可以对来自客户端的请求进行拦截,进行预处理或者对最终响应给客户端的数据进行处理后再输出。

要想使用filter过滤器,非常简单,只要实现servlet  api中的filter接口即可,同时在该web应用【web-inf】目录下的web.xml文件中配置<filter>和<filter-mapping>两个标签。其中可以根据配置指定过滤的页面或者servlet。

也就是说我们在web工程中光光写filter过滤器的java代码是不会起作用的,要在web.xml文件中对过滤器进行注册和映射,在学习filter之前我们先来学习如何注册和映射
关于注册:

需要在web.xml文件中配置<filter>标签,这还不够,<filter>标签下的<filter-name>与<filter-class>是必须要填的内容。

<filter>标签中有如下子元素:

  1. <description>用于描述该标签,非必须;
  2. <filter-name>为过滤器指定一个名称,必须的
  3. <filter-class>指定该过滤器使用的web工程中的哪一个filter类,包含包名与类名,必须的;
  4. <init-param>为过滤器的初始化提供参数,非必须,后面有例子。

关于映射:

需要在web.xml文件中配置<filter-mapping>标签,这还不够,<filter-mapping>标签下的<filter-name>以及<url-pattern>或<servlet-name>之一是必须的。

<filter-mapping>标签中有如下子元素:

  1. <filter-name>设置要映射过滤器的名称,该名称必须同<filter>标签下的<filter-name>的值一致。
  2. <url-pattern>设置过滤器要拦截过滤的请求路径,例如“/*”则表示对该web应用下所有的请求都进行拦截过滤。
  3. <servlet-name>如果只要拦截过滤访问某个servlet,就可以使用该标签来替代<url-pattern>。
  4. <dispatcher>设置拦截过滤客户端请求的方式,有request,include,forward,error四种(请注意均为大写)。非必须则默认为request,使用多个<dispatcher>标签来设置多种请求方式。

关于<dispathcer>的四种方式,这里再简单的介绍一下:

  1. request:当用户直接访问我们的资源时,这时我们设置的过滤器就会进行拦截。但如果以转发和包含方式访问资源,那么该过滤器则不会被调用。
  2. include:当使用requestdispatch的include方法请求时,该过滤器会被调用。
  3. forward:当使用requestdispatch的forward方法时请求资源时,该过滤器会被调用,尤其是在mvc设计模式下,jsp都被保护起来,必须要通过servlet进行转发才能访问jsp,那么该过滤器就是在servlet转发到jsp这个过程中被执行。
  4. error:当请求是通过错误异常进行跳转时就会调用该过滤器。

一个简单的对过滤器的注册和映射的示例:

 
?
1
 
2
3
4
5
6
7
8
9
10
11
<filter>
  <filter-name>filterdemo1</filter-name>
  <filter-class>com.bjpowernode.web.filter.filterdemo1</filter-class>
 </filter>
  
 <filter-mapping>
  <filter-name>filterdemo1</filter-name>
  <url-pattern>/*</url-pattern>
  <dispatcher>request</dispatcher>
  <dispatcher>forward</dispatcher>
</filter-mapping>

在servlet api 中关于filter举例了使用过滤器能用来做些什么:

Java过滤器filter_动力节点Java学院整理

这里我也说明下平时filter能在哪些方面会被经常用到:

① filter可以作用在请求资源执行之前,进行权限检查,检查用户是否有权限,如有权限则放行请求;如果没有,则拒绝访问。

② filter可以作用在请求资源执行之前,对request和response对象进行预处理操作,从而实现一些web应用的全局性设置,比如解决中文乱码问题。

③ filter可以作用在最终响应输出之前,对输出response对象中的数据进行处理,例如将输出的数据进行压缩。

filter只有3个方法:

Java过滤器filter_动力节点Java学院整理

其中destroy()方法和init(…)方法是生命周期方法,因为过滤器无论如何都要在请求任何资源之前进行,所以任何web应用在部署的时候,服务器就会调用filter过滤器的init方法进行初始化,而关于过滤器的销毁,则是将该过滤器移除或者服务器关闭就会执行destory方法。

而我们通常要使用过滤器处理请求,则重点在于dofilter(…)方法。当请求要经过一个过滤器的时候,就会由服务器调用dofilter方法。

我们先来看看一个带有过滤器filter的web应用的请求和响应流程:

Java过滤器filter_动力节点Java学院整理

记住:从请求到响应这个流程会经过filter对象两次!

在dofilter这一个方法中就可以对着两次经过的过程进行处理,那么这里就有一个问题了,如果能通过过滤器,那么就到过滤器后面了,貌似应该是执行完dofilter方法了,而服务器的响应又经过过滤器,难道又要执行dofilter方法一次?但是这个方法里面的代码不是也有处理最开始请求的吗?

这就跟dofilter方法中的第三个参数filterchain有关了,filterchain对象是过滤器链,这个我们稍后会介绍。在filterchain对象中只有一个方法:

Java过滤器filter_动力节点Java学院整理

=也是叫dofilter方法(千万别和filter接口的dofilter方法弄混了)。简单的说下这个方法,只要调用了这个方法,就会将请求交给后面一个filter进行过滤(一个web应用中可以有多个filter),如果该filter是最后一个,那么调用该方法则将执行请求,也就是到我们的应用中获取资源。

因此从请求到响应这个流程经过filter的两次处理分别是在filterchain.dofilter方法的前面和后面!如下图所示:

Java过滤器filter_动力节点Java学院整理

那么下面我们就先以一个简单的例子来熟悉下filter吧:

例1:

创建web工程filterlearning,创建一个filterdemo1类,同时这个类要实现javax.servlet.filter接口。如下代码:

 
?
1
 
2
3
4
5
6
7
8
9
10
11
public class filterdemo implements filter {
 
   @override
   public void dofilter(servletrequest request, servletresponse response,
       filterchain chain) throws ioexception, servletexception {
     
     system.out.println("hello filter");
   }
 
   //此处省略init方法和destory方法
 }

写好filter的java代码还没完,还要在web应用下的web.xml文件中配置如下信息:

 
?
1
 
2
3
4
5
6
7
8
9
<filter>
   <filter-name>filterdemo1</filter-name>
   <filter-class>com.bjpowernode.web.filter.filterdemo</filter-class>
 </filter>
 
 <filter-mapping>
   <filter-name>filterdemo1</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

注意:因为我在<url-pattern>中配置为“/*”,则访问我wen应用中任何资源都会经过该filter过滤器。如果只想对于index.jsp主页的请求进行过滤,可以设为<url-pattern>/index.jsp</url-pattern>。

我们在index.jsp中简单的使用jsp脚本来演示如果有请求来就输入一段文本到控制台上:

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@ page language="java" import="java.util.*" pageencoding="utf-8"%>
 
 <!doctype html>
 <html>
  <head> 
   <title>index</title>
  </head>
  
  <body>
   <%
     system.out.println("long live sd !");
   %>
  </body>
 </html>

接下来将该web应用部署到服务器中,我们就访问index.jsp,以下是我们访问了index.jsp后控制台的情况:

Java过滤器filter_动力节点Java学院整理

首先,我们可以保证在我们访问index.jsp后这个请求确实经过了filter过滤器,但是我们的请求好像就只到过滤器而没有到我们真正需要的资源index.jsp?这是因为我们没有在filter的dofilter方法中调用过滤器链filterchain对象的dofilter方法,自然无法将请求继续往后面传递。我们将在例2中修改。

例2:

我们将例1中的filterdemo1类进行修改,使其能访问到我们所需要的资源,很简单,在dofilter的方法中添加过滤器链filterchain对象的dofilter方法即可:

 
?
1
 
2
3
4
5
6
7
8
9
10
11
public class filterdemo implements filter {
 
   @override
   public void dofilter(servletrequest request, servletresponse response,
       filterchain chain) throws ioexception, servletexception {
     
     system.out.println("hello filter");
     chain.dofilter(request, response);
   }
   //此处省略init方法和destory方法
 }

其他如web.xml中的配置和index.jsp中的代码保持不变,现在我们再来访问下该web应用中的index.jsp,并观察控制台:

Java过滤器filter_动力节点Java学院整理

可以看到我们的请求经过过滤器,执行了过滤器的一段代码(system.out.println(“hello filter”)),然后将请求继续执行!正是因为filterchain.dofilter方法才使我们通过过滤器继续向后寻找我们所需的资源。

那么还记得我们之前说过的从请求到响应会经过两次过滤器吗,是的在获取了我们所需的资源后还会到过滤器一趟,而至于这时候是否将响应再做处理取决于过滤器链filterchain.dofilter方法后面还是否有代码。我们将在例3中完整的展现从请求到响应经过过滤器两次的流程。

例3:

我们将例2中的filterdemo1类进行修改,只要在filterchain.dofilter方法后面添加代码,就是第二次(即响应)经过过滤器所要执行的处理:

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
public class filterdemo implements filter {
 
   @override
   public void dofilter(servletrequest request, servletresponse response,
       filterchain chain) throws ioexception, servletexception {
     
     system.out.println("hello filter");
     chain.dofilter(request, response);
     system.out.println("goodbye filter");
   }
   //此处省略init方法和destory方法
 }

其他如web.xml中的配置和index.jsp中的代码保持不变,现在我们再来访问下该web应用中的index.jsp,并观察控制台:

Java过滤器filter_动力节点Java学院整理

这个结果证明了从请求到响应确实经过过滤器两次,同时也说明了在filter的dofilter方法中“过滤——取资源——再过滤”执行的顺序。

现在我们再回到filter接口的init方法,我们可以看到在这个方法内有一个参数filterconfig,这个是由服务器传给我们的对象。如果我们在web.xml文件中配置了过滤器的初始化参数,就可以通过该filterconfig对象来在代码中获取使用。

这个过滤器参数的初始化配置可以在<filter>标签中配置<init-param>,并在这个<init-param>标签下再配置<param-name>和<param-value>。

filterconfig有如下方法:

Java过滤器filter_动力节点Java学院整理

当然如果我们是要获取配置的初始化参数则只需关注getinitparameter方法或getinitparameternames方法。

一般来说我们可以在init方法中获取配置初始化参数并进行处理;也可以通过对象引用将filterconfig对象在dofilter方法中处理参数,如例4所示。

例4:

在web.xml文件中配置过滤器和初始化参数:

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
<filter>
   <filter-name>filterdemo1</filter-name>
  <filter-class>com.bjpowernode.web.filter.filterdemo1</filter-class>
   <init-param>
     <param-name>love</param-name>
     <param-value>lrr</param-value>
   </init-param>
 </filter>
 
 <filter-mapping>
   <filter-name>filterdemo1</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

在java中编写filter接口的实现类filterdemo1:

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class filterdemo implements filter {
   private filterconfig filterconfig ;
   
   @override
   public void dofilter(servletrequest request, servletresponse response,
       filterchain chain) throws ioexception, servletexception {
     
     string value = filterconfig.getinitparameter("love");
     system.out.println(value);
   }
   
   @override
   public void init(filterconfig filterconfig) throws servletexception {
     this.filterconfig = filterconfig;
   }
   //此处省略destroy方法
 }

因为配置的原因,所以我们随便访问个资源都可以经过该过滤器,那么就访问index.jsp好了,看看控制台的结果:

Java过滤器filter_动力节点Java学院整理

正如我们在web.xml文件所配置的初始化参数一样。

上面介绍的都是只有一个filter过滤器的情况下,有时候我们会因为要过滤的功能不同添加多个过滤器,这就有一个顺序的问题了,尤其是从取得资源后再返回到过滤器的顺序。下面这张图就能很清晰的看到我们要注意的顺序了:

Java过滤器filter_动力节点Java学院整理

例5:

来写两个filter来说明下从请求到响应过滤器的处理顺序。

创建一个web工程,创建一个filterdemo1类,同时这个类要实现javax.servlet.filter接口。如下代码:

 
?
1
 
2
3
4
5
6
7
8
9
10
11
public class filterdemo1 implements filter {
   
   public void dofilter(servletrequest request, servletresponse response,
       filterchain chain) throws ioexception, servletexception {
     
     system.out.println("hello filter 1");
     chain.dofilter(request, response);
     system.out.println("goodbye filter 1");
   }
 //此处省略init方法和destroy方法
 }

创建第二个filter接口实现类filterdemo2,代码如下:

 
?
1
 
2
3
4
5
6
7
8
9
10
public class filterdemo2 implements filter {
 
  public void dofilter(servletrequest request, servletresponse response,
      filterchain chain) throws ioexception, servletexception {
    system.out.println("hello filter 2");
    chain.dofilter(request, response);
    system.out.println("goodbye filter 2"); 
  }
//此处省略init方法和destroy方法
}

过滤器要想能被服务器调用,还必须要在该web工程下的web.xml中配置过滤器及其映射,而这个配置的顺序就是影响多个过滤器工作先后的顺序:

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<filter>
   <filter-name>filterdemo1</filter-name>
  <filter-class>com.bjpowernode.web.filter.filterdemo1</filter-class>
</filter>
 
 <filter-mapping>
   <filter-name>filterdemo1</filter-name>
   <url-pattern>/*</url-pattern>
 </filter-mapping>
 
 <filter>
   <filter-name>filterdemo2</filter-name>
   <filter-class>com.bjpowernode.web.filter.filterdemo2</filter-class>
 </filter>
 
 <filter-mapping>
   <filter-name>filterdemo2</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

而我们要访问的资源文件就以index.jsp为例好了,那么我们用一段jsp脚本通过在控制台打印来验证过滤器工作的顺序过程:

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@ page language="java" import="java.util.*" pageencoding="utf-8"%>
 
<!doctype html>
<html>
 <head> 
  <title>index</title>
 </head>
 
 <body>
  <%
    system.out.println("long live sd !");
  %>
 </body>
</html>

现在启动服务器,部署该工程,通过访问index.jsp来看看控制台情况:

Java过滤器filter_动力节点Java学院整理

标签:

相关文章

热门资讯

2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
Intellij idea2020永久破解,亲测可用!!!
Intellij idea2020永久破解,亲测可用!!! 2020-07-29
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享 2020-04-07
电视剧《琉璃》全集在线观看 琉璃美人煞1-59集免费观看地址
电视剧《琉璃》全集在线观看 琉璃美人煞1-59集免费观看地址 2020-08-12
最新idea2020注册码永久激活(激活到2100年)
最新idea2020注册码永久激活(激活到2100年) 2020-07-29
返回顶部