java过滤器

过滤器

 

1、Filter工作原理(执行流程)       

 

       当客户端发出Web资源的请求时,Web服务器根据应用程序配置文件设置的过滤规则进行检查,若客户请求满足过滤规则,则对客户请求/响应进行拦截,对请求头和请求数据进行检查或改动,并依次通过过滤器链,最后把请求/响应交给请求的Web资源处理。请求信息在过滤器链中可以被修改,也可以根据条件让请求不发往资源处理器,并直接向客户机发回一个响应。当资源处理器完成了对资源的处理后,响应信息将逐级逆向返回。同样在这个过程中,用户可以修改响应信息,从而完成一定的任务。

 

         上面说了,当一个请求符合某个过滤器的过滤条件时该请求就会交给这个过滤器去处理。那么当两个过滤器同时过滤一个请求时谁先谁后呢?这就涉及到了过滤链FilterChain。

 

         所有的奥秘都在Filter的FilterChain中。服务器会按照web.xml中过滤器定义的先后循序组装成一条链,然后一次执行其中的doFilter()方法。执行的顺序就如下图所示,执行第一个过滤器的chain.doFilter()之前的代码,第二个过滤器的chain.doFilter()之前的代码,请求的资源,第二个过滤器的chain.doFilter()之后的代码,第一个过滤器的chain.doFilter()之后的代码,最后返回响应。

 这里还有一点想补充:大家有没有想过,上面说的执行请求的资源究竟是怎么执行的?对于执行第一个过滤器的chain.doFilter()之前的代码,第二个过滤器的chain.doFilter()之前的代码这些我可以理解,无非就是按顺序执行一句句的代码,但对于这个执行请求的资源我刚开始却是怎么也想不明白。其实是这样的:

        通常我们所访问的资源是一个servlet或jsp页面,而jsp其实是一个被封装了的servlet,于是我们就可以统一地认为我们每次访问的都是一个Servlet,而每当我们访问一个servlet时,web容器都会调用该Servlet的service方法去处理请求。而在service方法又会根据请求方式的不同(Get/Post)去调用相应的doGet()或doPost()方法,实际处理请求的就是这个doGet或doPost方法。写过servlet的朋友都应该知道,我们在doGet(或doPost)方法中是通过response.getWriter()得到客户端的输出流对象,然后用此对象对客户进行响应。

       到这里我们就应该理解了过滤器的执行流程了:执行第一个过滤器的chain.doFilter()之前的代码——>第二个过滤器的chain.doFilter()之前的代码——>……——>第n个过滤器的chain.doFilter()之前的代码——>所请求servlet的service()方法中的代码——>所请求servlet的doGet()或doPost()方法中的代码——>第n个过滤器的chain.doFilter()之后的代码——>……——>第二个过滤器的chain.doFilter()之后的代码——>第一个过滤器的chain.doFilter()之后的代码。

二、Servlet过滤器开发步骤

1、创建实现javax.servlet.Filter接口的类。

2、过滤器的xml配置。

Servlet过滤器API
 Servlet过滤器API包含了3个接口,它们都在javax.servlet包中,分别是Filter接口、FilterChain接口和FilterConfig接口。
public Interface Filter
所有的过滤器都必须实现Filter接口。该接口定义了init,doFilter0,destory()三个方法:
  (1) public void init (FilterConfig filterConfig) 
当开始使用servlet过滤器服务时,Web容器调用此方法一次,为服务准备过滤器;然后在需要使用过滤器的时候调用doFilter(),传送给此方法的FilterConfig对象,包含servlet过滤器的初始化参数。
  (2)public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)    
         每个过滤器都接受当前的请求和响应,且FilterChain过滤器链中的过滤器(应该都是符合条件的)都会被执行。doFilter方 法中,过滤器可以对请求和响应做它想做的一切,通过调用他们的方法收集数据,或者给对象添加新的行为。过滤器通过传送至 此方法的FilterChain参数,调用chain.doFilterO将控制权传送给下一个过滤器。当这个调用返回后,过滤器可以在它的 Filter方法的最后对响应做些其他的工作。如果过滤器想要终止请求的处理或得到对响应的完全控制,则可以不调用下一个过滤 器,而将其重定向至其它一些页面。当链中的最后一个过滤器调用chain.doFilterO方法时,将运行最初请求的Servlet。
 (3)public void destroy()
       一旦doFilterO方法里的所有线程退出或已超时,容器调用
此方法。服务器调用destoryO以指出过滤器已结束服务,用于释
放过滤器占用的资源。
public interface FilterChain
public void doFilter(ServletRequest request,ServletResponse response)
      此方法是由Servlet容器提供给开发者的,用于对资源请求过滤链的依次调用,通过FilterChain调用过滤链中的下一个过滤   器,如果是最后一个过滤器,则下一个就调用目标资源。
public interface FilterConfig
 FilterConfig接口检索过滤器名、初始化参数以及活动的Servlet上下文。该接口提供了以下4个方法:
     (1)public Java.1ang.String getFilterName0
           返回web.xml部署文件中定义的该过滤器的名称。
     (2)public ServletContext getServletContextO
          返回调用者所处的servlet上下文。
     (3)public java.1ang.String getlnitParameter(java.1ang.String name)
返回过滤器初始化参数值的字符串形式,当参数不存在时,返回nul1.name是初始化参数名。
     (4)public java.util.Enumeration getlnitParameterNames()
      以Enumeration形式返回过滤器所有初始化参数值,如果没有初始化参数,返回为空。

三、应用实例

   从上面分析可知,实现Servlet过滤器,需要两步:第一步开发过滤器,设计个实现Fiker接口的类;第二步通过web.xml配置过滤器,实现过滤器和ServletJSP页面之间的映射。以下设计一个简单的IP地址过滤器,根据用户的IP地址进行对网站的访问控制。
(1)过滤器的设计ipfilter.java

 1 package ipf;  
 2 imp0rt java.io.IOException;  
 3 imp0rt javax.servlet.*;  
 4 public class ipfilter implements Filter//实现Filter接口  
 5 {protected FilterConfig config;  
 6 protected String rejectedlP;  
 7 public void init(FilterConfig filterConfig)throws  
 8 ServletException  
 9   
10 {this.config=filterConfig;//从Web务器获取过滤器配置对象  
11 rejectedlP=config.getlnitParameter( RejectedlP”):  
12 //从配置中取得过滤lP  
13 }  
14 public void doFilter(ServletRequest request,  
15 ServletResponse response.FilterChain chain)throws  
16 IOException,ServletException  
17 {RequestDispatcher dispatcher=request.getRequestDispatcher("");  
18 String remotelP=request.getRemoteAddrO;//获取客户请求lP  
19 int i=remotelP.1astlndexOf(".");  
20 int r=rejectedlP.1astlndexOf(”.”):  
21 String relPscope=rejectedlP.substring(0,r);//过滤lP段  
22 if(relPscope.equals(remotelP.substring(O.i)))  
23 {      dispatcher.forward(request,response);//重定向到rejectedError.jsp页面  
24         retum;//阻塞,直接返Web回客户端  
25 }  
26 else{chain.doFilter(request,response);//调用过滤链上的下一个过滤器  
27 }  
28 }  
29 public void destroy()  

//过滤器功能完成后,由Web服务器调用执行,回收过滤器资源
注意:chain.doFilterO语句以前的代码用于对客户请求的处理;以后的代码用于对响应进行处理。

配置过滤器

在web.xml中进行配置

 1 <filter>  
 2 <filter-name>ipfIter</filter-name>//过滤器名称  
 3 <filter-class>ipf.ipfiIter</filter-class>//实现过滤器的类  
 4 <init—param>  
 5 <param—name>RejectedlP</param-name>//过滤器初始化参数名RejectedlP  
 6 <param-value>192.168.12.*/param-value>  
 7 </init—pamm>  
 8 </filter>  
 9 <filter-mapping>//过滤器映射(规律规则)  
10 <filter-name>ipfiIter</filter-name>  
11 <url—pattem>/*</ud-pattem>  
12 //映射到Web应用根目录下的所有JSP文件  
13 </filter-mapping>  

四、Filter的应用场景

通过对filter过滤器的了解,可以得知在以下三种情况下可以做些处理:

1> 通过控制对chain.doFilter的方法的调用,来决定是否需要访问目标资源。

比如,可以在用户权限验证等等。判断用户是否有访问某些资源的权限,有权限放行,没权限不执行chain.doFilter方法。

2> 通过在调用chain.doFilter方法之前,做些处理来达到某些目的。

比如,解决中文乱码的问题等等。可以在doFilter方法前,执行设置请求编码与响应的编码。甚至可以对request接口进行封装装饰来处理get请求方式的中文乱码问题(重写相应的request.getParameter方法)。

3> 通过在调用chain.doFilter方法之后,做些处理来达到某些目的。

比如对整个web网站进行压缩。在调用chain.doFilter方法之前用类A对response对象进行封装装饰,重写getOutputStream和重写getWriter方法。在类A内部中,将输出内容缓存进ByteArrayOutputStream流中,然后在chain.doFilter方法执行后,获取类A中ByteArrayOutputStream流缓存数据,用GZIPOutputStream流进行压缩下。

五、Filter实现拦截的原理

Filter接口中有一个doFilter方法,当开发人员编写好Filter类实现doFilter方法,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前(服务器内部对资源的访问机制决定的),都会先调用一下filter的doFilter方法。

六、Filter生命周期

和Servlet一样Filter的创建和销毁也是由WEB服务器负责。不过与Servlet区别的是,它是1>在应用启动的时候就进行装载Filter类(与Servlet的load-on-startup配置效果相同)。2>容器创建好Filter对象实例后,调用init()方法。接着被Web容器保存进应用级的集合容器中去了等待着,用户访问资源。3>当用户访问的资源正好被Filter的url-pattern拦截时,容器会取出Filter类调用doFilter方法,下次或多次访问被拦截的资源时,Web容器会直接取出指定Filter对象实例调用doFilter方法(Filter对象常驻留Web容器了)。4>当应用服务被停止或重新装载了,则会执行Filter的destroy方法,Filter对象销毁。

注意:init方法与destroy方法只会直接一次。

七、Filter部署应用注意事项

1> filter-mapping标签中servlet-name与url-pattern。

Filter不仅可以通过url-pattern来指定拦截哪些url匹配的资源。而且还可以通过servlet-name来指定拦截哪个指定的servlet(专门为某个servlet服务了,servlet-name对应Servlet的相关配置)。

2> filter-mapping标签中dispatcher。

指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。

REQUEST:

当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问或ERROR情况时,那么该过滤器就不会被调用。

 

INCLUDE:

如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。

 

FORWARD:

如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。

 

ERROR:

如若在A.jsp页面page指令中指定了error属性=examError.jsp,那么A.jsp中若出现了异常,会跳转到examError.jsp中处理。而在跳转到examError.jsp时,若过滤器配置了ERROR的dispather那么则会拦截,否则不会拦截。

 

转载于:https://www.cnblogs.com/kuangwong/p/6393495.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/572737.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

memory php 变量,php入门-变量

打印一串字符。echo PHP学到家&#xff0c;走到哪儿都不怕&#xff01;;?>输出236的计算结果echo 236;?>.连接符echo "Good,"."morning!";?>注释//echo "欢迎同学们&#xff01;";echo 12345;?>什么是变量$var "学PHP&quo…

假设检验

假设检验分参数假设和非参数假设。 假设 先假设原假设H0&#xff0c;对应的反面叫做备择假设H1。SAS一般沿用的规则是NEYMAN和PEARSON提出的&#xff1a;在控制犯第一类错误的原则下&#xff0c;是犯第二类错误的概率尽量小&#xff08;即&#xff0c;原假设受到保护&#xff0…

jeesite在eclipse中部署

1&#xff1a;下载下来最新版本的jeesite&#xff0c;首先要在本地安装好maven运行环境 2&#xff1a;运行 bin/eclipse.bat 生成工程文件并下载jar依赖包 如果需要修改默认项目名&#xff0c;请打开pom.xml修改第7行artifactId&#xff0c;然后再执行eclipse.bat文件 3&…

php抖音关注列表,网页PHP抖音批量取消关注JS代码

在很多时候我们抖音关注的人太多&#xff0c;想要批量取消但是一个一个点击太麻烦了&#xff0c;如何解放双手批量取消关注呢&#xff1f;今天分享一段JS代码&#xff0c;可在线批量取消关注&#xff0c;需电脑才能操作。首先打开抖音创作服务平台登录&#xff1a;https://crea…

python 灰度改二值,Python Image 对验证码进行灰度和二值法处理 去掉边框

def binarizing(img, threashold):img img.convert("L") # 转灰度pixdata img.load()w, h img.sizefor y in range(h):for x in range(w):if pixdata[x, y] < threashold:pixdata[x, y] 0else:pixdata[x, y] 255return imgdef removeFrame(img, width)::para…

hadoop 2.7.3伪分布式安装

hadoop 2.7.3伪分布式安装 hadoop集群的伪分布式部署由于只需要一台服务器&#xff0c;在测试&#xff0c;开发过程中还是很方便实用的&#xff0c;有必要将搭建伪分布式的过程记录下来&#xff0c;好记性不如烂笔头。 hadoop 2.7.3 JDK 1.8.91 到Apache的官网下载hadoop的二进…

php 环境变量有什么用,什么是环境变量,Linux环境变量及作用

变量是计算机系统用于保存可变值的数据类型&#xff0c;我们可以直接通过变量名称来提取到对应的变量值。在 Linux 系统中&#xff0c;环境变量是用来定义系统运行环境的一些参数&#xff0c;比如每个用户不同的家目录(HOME)、邮件存放位置(MAIL)等。值得一提的是&#xff0c;L…

Web Api 转

GET&#xff1a;生到数据列表&#xff08;默认&#xff09;&#xff0c;或者得到一条实体数据 POST&#xff1a;添加服务端添加一条记录&#xff0c;记录实体为Form对象 PUT&#xff1a;添加或修改服务端的一条记录&#xff0c;记录实体的Form对象&#xff0c;记录主键以GET方式…

matlab 刻度非均匀控制,MATLAB 出一张好看的图

1、坐标轴的视点(viewpoint)&#xff1a;从哪个方向看整个坐标系统&#xff0c;这决定了坐标轴的方向和位置&#xff0c;通过view函数实现视点的设置&#xff1b;view([z y ])&#xff1a;(将坐标系统想象为一座房子&#xff0c;而自己是个会飞的天使&#xff0c;最初你在房子的…

weak_ptr打破环状引用

转自&#xff1a;http://blog.csdn.net/malong777/article/details/48974559 weak_ptr是一种不控制对象生存周期的智能指针&#xff0c;它指向一个shared_ptr管理的对象...它不会改变shared_ptr的引用计数——《C Primer .5th》。很明显&#xff0c;weak_ptr的特点是“弱引用”…

百度链接提交php获取状态码,新网站,在百度提交了首页链接,但是一直没有收录,也没有爬虫抓取,怎么回事呢?(悬赏1元) - 搜外SEO问答...

新站前期需要做哪些操作&#xff1a;1、上线前保证网站的内容已经有一定的丰富性&#xff0c;可供爬虫已经有20的主关键词相关的界面或文章&#xff0c;50为最佳。2、新站的标题不要堆彻关键词&#xff0c;以主关键词主关键词描述语句品牌词 这个类型的标题为最佳。3、标题中出…

使用 git-cherry-pick 迁移提交

参考 git-cherry-pick 后续补上

前端js模糊搜索(模糊查询)

1.html结构&#xff1a; <label for"searchShop" class"clear pos-a" style"top:17px;"> <input type"text" id"searchShop" placeholder"场所搜索"> <input type"but…

php代码审计思路,代码审计思路讨论

原标题&#xff1a;代码审计思路讨论前言首先感谢手电筒的建议&#xff0c;建议我从Bluecms来开始学习代码审计。感谢桑桑格&#xff0c;风哥的问题解答。文章主要是写下我自己在代码审计的时候所思所想。当然并不是太过严谨&#xff0c;也有可能存在错误。这里主要是写出了审计…

LinkedHashSet

特点: 有序 , 唯一 底层的数据结构为: 链表和哈希表 , 链表保证有序 , 哈希表保证唯一 import java.util.LinkedHashSet; public class Demo2_LinkedHashSet {/*** param args* LinkedHashSet* 底层是链表实现的,是set集合中唯一一个能保证怎么存就怎么取的集合对象* 因为是Has…

oracle如何自定义类型,Oracle 自定义类型

一、子类型这种类型最简单&#xff0c;类似类型的一个别名&#xff0c;主要是为了对常用的一些类型简单化&#xff0c;它基于原始的某个类型。如&#xff1a;有些应用会经常用到一些货币类型&#xff1a;number(16,2)。如果在全局范围各自定义这种类型&#xff0c;一旦需要修改…

Dubbo源码分析:ThreadPool

定义了通过URL对象作为参数获取Executor对象的get&#xff25;xecutor方法。所有实现ThreadPool接口的类都是基于ThreadPoolExecuotr对象来实现的。 类图 转载于:https://www.cnblogs.com/wspgbw/p/6409933.html

oracle查询并列,【问】oracle-查询各门课程的前2名和后2名

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼成绩表&#xff1a;studentscorecreate table studentScore(id int primary key not null,course varchar2(20),score int,studentname varchar2(20))数据&#xff1a;id course score studentname1 语文 100 张三2 语文 98 李四3 …

MySQL存储过程及触发器

一、存储过程 存储过程的基本格式如下&#xff1a; -- 声明结束符 -- 创建存储过程 DELIMITER $ -- 声明存储过程的结束符 CREATE PROCEDURE pro_test() --存储过程名称(参数列表) BEGIN-- 可以写多个sql语句; -- sql语句流程控制SELECT * FROM employee; END $ -- 结…

asp连接oracle6,asp下用OracleInProcServer完成对Oracle的连接和操作-ASP教程,数据库相关...

< % response.charset"gb2312"tblnamerequest("tb")dim objorasession,objoradbdim strdbuser,strdbpwd,strdbconncall connectdb()sub connectdb() 连接数据库on error resume nextstrdbuser "liujincai" 连接用户名strdbpwd "ljc100…