servlet API中最重要的一个功能就是能够ؓ(f)servlet和JSP面定义qo(h)器。过滤器提供了某些早期服务器所支持的非标准“servlet链接”的一U功能强大且标准的替代品?br />
qo(h)器提供了几个重要好处 Q?/p>
<xml version="1.0" encoding="ISO-8859-1"?> xml version="1.0" encoding="ISO-8859-1"?> <filter> <filter> xml version="1.0" encoding="ISO-8859-1"?> web.xml加配|?/p>
<!-- qo(h)?--> EncodingFilter.java package com.hibernate.util; import java.io.IOException; import javax.servlet.Filter; public class EncodingFilter implements Filter { protected String Encoding = null; public void init(FilterConfig config) throws ServletException { this.config = config; } public void doFilter(ServletRequest request, ServletResponse response, if (request.getCharacterEncoding() == null) { OK!!!
qo(h)器是一个程序,它先于与之相关的servlet或JSP面q行在服务器上。过滤器可附加到一个或多个servlet或JSP面上,q且可以(g)查进入这些资源的h信息。在q之后,qo(h)器可以作如下的选择Q?br />
1. 以常规的方式调用资源Q即Q调用servlet或JSP面Q?br />
2.利用修改q的h信息调用资源?br />
3. 调用资源Q但在发送响应到客户机前对其q行修改
4. L该资源调?/font>Q代之以转到其他的资源,q回一个特定的状态代码或生成替换输出?/p>
首先Q它以一U模块化的或可重用的方式装公共的行为。你?0个不同的serlvet或JSP面Q需要压~它们的内容以减下载时间吗Q没问题Q构造一个压~过滤器Q然后将它应用到30个资源上卛_?br />
其次Q利用它能够高U访问决{与表现代码相分R这对于JSP特别有h(hun)|其中一般希望将几乎整个面集中在表CQ而不是集中在业务逻辑上。例如,?
望阻塞来自某些站点的讉K而不用修改各面Q这些页面受到访问限Ӟ吗?没问题:(x)建立一个访问限制过滤器q把它应用到惌限制讉K的页面上卛_?br />
最后,qo(h)器你能够对许多不同的资源进行批量性的更改。你有许多现存资源,q些资源除了公司名要更改外其他的保持不变Q能办到么?没问题:(x)构造一个串替换qo(h)器,只要合适就使用它?br />
但要注意Q过滤器只在与servlet规范2.3版兼容的服务器上有作用。如果你的Web应用需要支持旧版服务器Q就不能使用qo(h)器?br />
1Q?nbsp; 建立基本qo(h)?/span>
建立一个过滤器涉及(qing)下列五个步骤Q?br />
1Q徏立一个实现Filter接口的类。这个类需要三个方法,分别是:(x)doFilter、init和destroy?br />
doFilterҎ(gu)包含主要的过滤代码(见第2步)QinitҎ(gu)建立讄操作Q而destroyҎ(gu)q行清楚?br />
2Q在doFilterҎ(gu)中放入过滤行为。doFilterҎ(gu)的第一个参Cؓ(f)ServletRequest对象。此对象l过滤器提供了对q入的信?
Q包括表单数据、cookie和HTTPh_(d)的完全访问。第二个参数为ServletResponseQ通常在简单的qo(h)器中忽略此参数。最后一个参
Cؓ(f)FilterChainQ如下一步所qͼ此参数用来调用servlet或JSPc(din)?br />
3Q调用FilterChain对象的doFilterҎ(gu)。Filter接口的doFilterҎ(gu)取一个FilterChain对象作ؓ(f)它的一个参
数。在调用此对象的doFilterҎ(gu)ӞȀzM一个相关的qo(h)器。如果没有另一个过滤器与servlet或JSP面兌Q则servlet或JSP
面被激zR?br />
4Q对相应的servlet和JSP面注册qo(h)器。在部v描述W文Ӟweb.xmlQ中使用filter和filter-mapping元素?br />
5Q禁用激zdservlet。防止用户利用缺省servlet URLl过qo(h)器设|?br />
1.1 建立一个实现Filter接口的类
所有过滤器都必d现javax.servlet.Filter。这个接口包含三个方法,分别为doFilter、init和destroy?br />
public void doFilter(ServletRequset request,
ServletResponse response,
FilterChain chain)
thows ServletException, IOException
每当调用一个过滤器Q即Q每ơ请求与此过滤器相关的servlet或JSP面Q时Q就执行其doFilterҎ(gu)。正是这个方法包含了大部分过滤逻辑?
W一个参Cؓ(f)与传入请求有关的ServletRequest。对于简单的qo(h)器,大多数过滤逻辑是基于这个对象的。如果处理HTTPhQƈ且需要访问诸
如getHeader或getCookies{在ServletRequest中无法得到的Ҏ(gu)Q就要把此对象构造成
HttpServletRequest?br />
W二个参Cؓ(f)ServletResponse。除了在两个情Ş下要使用它以外,通常忽略q个参数。首先,如果希望完全d对相关servlet或JSP?
面的讉K。可调用response.getWriterq直接发送一个响应到客户机。其ơ,如果希望修改相关的servlet或JSP面的输出,可把?
应包含在一个收集所有发送到它的输出的对象中。然后,在调用serlvet或JSP面后,qo(h)器可(g)查输出,如果合适就修改它,之后发送到客户机?br />
DoFilter的最后一个参Cؓ(f)FilterChain对象。对此对象调用doFilter以激zMservlet或JSP面相关的下一个过滤器。如果没有另一个相关的qo(h)器,则对doFilter的调用激zservlet或JSP本n?br />
public void init(FilterConfig config) thows ServletException
initҎ(gu)只在此过滤器W一ơ初始化时执行,不是每次调用qo(h)器都执行它。对于简单的qo(h)器,可提供此Ҏ(gu)的一个空体,但有两个原因需要用init?
首先QFilterConfig对象提供对servlet环境?qing)web.xml文g中指zqo(h)器名的访问。因此,普遍的办法是利用init?
FilterConfig对象存放在一个字D中Q以便doFilterҎ(gu)能够讉Kservlet环境或过滤器?其次QFilterConfig对象?
有一个getInitParameterҎ(gu)Q它能够讉K部v描述W文Ӟweb.xmlQ中分配的过滤器初始化参数?br />
public void destroy( )
大多数过滤器单地为此Ҏ(gu)提供一个空体,不过Q可利用它来完成诸如关闭qo(h)器用的文g或数据库q接池等清除d?br />
1.2 过滤行为放入doFilterҎ(gu)
doFilterҎ(gu)为大多数qo(h)器地关键部分。每当调用一个过滤器Ӟ都要执行doFilter。对于大多数qo(h)器来_(d)doFilter执行的步骤是
Z传入的信息的。因此,可能要利用作为doFilter的第一个参数提供的ServletRequest。这个对象常常构造ؓ(f)
HttpServletRequestcdQ以提供对该cȝ更特D方法的讉K?br />
1.3 调用FilterChain对象的doFilterҎ(gu)
Filter接口的doFilterҎ(gu)以一个FilterChain对象作ؓ(f)它的W三个参数。在调用该对象的doFilterҎ(gu)ӞȀzM一个相关的
qo(h)器。这个过E一般持l到链中最后一个过滤器为止。在最后一个过滤器调用其FilterChain对象的doFilterҎ(gu)ӞȀzservlet?
面自n?br />
但是Q链中的Lqo(h)器都可以通过不调用其FilterChain的doFilterҎ(gu)中断q个q程。在q样的情况下Q不再调用JSP面的serlvetQƈ且中断此调用q程的过滤器负责输出提供给客户机?br />
1.4 寚w当的servlet和JSP面注册qo(h)?/span>
部v描述W文件的2.3版本引入了两个用于过滤器的元素,分别是:(x)filter和filter-mapping。filter元素向系l注册一个过滤对象,filter-mapping元素指定该过滤对象所应用的URL?br />
1.filter元素
filter元素位于部v描述W文Ӟweb.xmlQ的前部Q所有filter-mapping、servlet或servlet-mapping元素之前。filter元素h如下六个可能的子元素Q?br />
1?icon q是一个可选的元素Q它声明IDE能够使用的一个图象文件?br />
2、filter-name q是一个必需的元素,它给qo(h)器分配一个选定的名字?br />
3、display-name q是一个可选的元素Q它l出IDE使用的短名称?br />
4?description q也是一个可选的元素Q它l出IDE的信息,提供文本文档?br />
5?filter-class q是一个必需的元素,它指定过滤器实现cȝ完全限定名?br />
6?init-param q是一个可选的元素Q它定义可利用FilterConfig的getInitParameterҎ(gu)d的初始化参数。单个过滤器元素可包含多个init-param元素?br />
h意,qo(h)是在serlvet规范2.3版中初次引入的。因此,web.xml文g必须使用DTD?.3版本。下面介l一个简单的例子Q?/p>
DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<filter>
<filter-name>MyFilterfilter-name>
<filter-class>myPackage.FilterClassfilter-class>
filter>
<filter-mapping>...filter-mapping>
<web-app>
2.filter-mapping元素
filter-mapping元素位于web.xml文g中filter元素之后serlvet元素之前。它包含如下三个可能的子元素Q?br />
1?filter-name q个必需的元素必M用filter元素声明时给予过滤器的名U相匚w?br />
2?url-pattern
此元素声明一个以斜杠Q?Q开始的模式Q它指定qo(h)器应用的URL。所有filter-mapping元素中必L供url-pattern?
servlet-name。但不能对单个filter-mapping元素提供多个url-pattern元素V如果希望过滤器适用于多个模式,可重?
整个filter-mapping元素?br />
3?servlet-name
此元素给Z个名Uͼ此名U必M利用servlet元素l予servlet或JSP面的名U相匚w。不能给单个filter-mapping元素提供
多个servlet-name元素V如果希望过滤器适合于多个servlet名,可重复这个filter-mapping元素?br />
下面举一个例子:(x)
DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<filter>
<filter-name>MyFilterfilter-name>
<filter-class>myPackage.FilterClassfilter-class>
filter>
<filter-mapping>
<filter-name>MyFilterfilter-name>
<url-pattern>/someDirectory/SomePage.jspurl-pattern>
filter-mapping>
web-app>
1.5 用Ȁzdservlet
在对资源应用qo(h)器时Q可通过指定要应用过滤器的URL模式或servlet名来完成。如果提供servlet名,则此名称必须与web.xml?
servlet元素中给出的名称相匹配。如果用应用到一个serlvet的URL模式Q则此模式必M利用web.xml的元素servlet-
mapping指定的模式相匚w。但是,多数服务器?#8220;Ȁzdservlet”为servlet体统一个缺省的URLQhttp:
//host/WebAppPrefix/servlet/ServletName。需要保证用户不利用q个URL讉KservletQ这样会(x)l过qo(h)?
讄Q?br />
例如Q假如利用filter和filter-mapping指示名ؓ(f)SomeFilter的过滤器应用到名为SomeServlet的servletQ则如下Q?/font>
<filter-name>SomeFilterfilter-name>
<filter-class>somePackage.SomeFilterClassfilter-class>
<filter>
<filter-mapping>
<filter-name>SomeFilterfilter-name>
<servlet-name>SomeServletservlet-name>
<filter-mapping>
接着Q用servlet和servlet-mapping规定URL http://host/webAppPrefix/Blah 应该调用SomeSerlvetQ如下所C:(x)
<filter-name>SomeFilterfilter-name>
<filter-class>somePackage.SomeFilterClassfilter-class>
filter>
<filter-mapping>
<filter-name>SomeFilterfilter-name>
<servlet-name>/Blahservlet-name>
<filter-mapping>
现在Q在客户Z用URL http://host/webAppPrefix/Blah 时就?x)调用过滤器。过滤器不应用到
http://host/webAppPrefix/servlet/SomePackage.SomeServletClass?br />
管有关闭激zd的服务器专用Ҏ(gu)。但是,可移植最强的Ҏ(gu)旉新映Web应用钟的/servlet模式Q这样所有包含此模式的请求被送到相同?
servlet中。ؓ(f)了重新映此模式Q首先应该徏立一个简单的servletQ它打印一条错误消息,或重定向用户到顶层页。然后,使用servlet?
servlet-mapping元素发送包?servlet模式的请求到该servlet。程序清?-1l出了一个简短的例子?br />
E序清单9-1 web.xmlQ重定向~省servlet URL的摘录)
DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>Errorservlet-name>
<servlet-class>somePackage.ErrorServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>Errorservlet-name>
<url-pattern>/servlet/*url-pattern>
servlet-mapping>
<web-app>
解决q
<filter>
<filter-name>Filter</filter-name>
<filter-class>
com.util.EncodingFilter<!-- qo(h)器类 -->
</filter-class>
<init-param>
<param-name>Encoding</param-name>
<param-value>gb2312</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
protected FilterConfig config;
this.Encoding = config.getInitParameter("Encoding");
FilterChain chain) throws IOException, ServletException {
if (Encoding != null) {
request.setCharacterEncoding(Encoding);
response.setCharacterEncoding(Encoding);
}
}
chain.doFilter(request,response);
}
public void destroy() {}
}
很简单的qo(h)器,是Z记录一个url的请求时?filter:
一般情况下是没什么问题,但是当我下蝲一个稍微大的文件时Q蟩出确认窗口,如果选择的是cancelQ?
׃(x)发现filterq没有返回,也就是说
q没有执? 原因?
chain.doFilter(request, response);
执行到这里时?x)从q里调用剩下的filter和servletQ所以这个调用将?x)是一个很长的q程?
在这个调用里Q将?x)完全通过request和resonseL作连接,取得/发送数据,如果q接出现异常Q将直接弹出Exception
你的代码里没有捕获异常,所以如果出现异常,chain.doFilter后面的就不会(x)执行?
可以把chain.doFilter攑ֈtry finallyl构中,保证后箋?x)被执?