•
Filter
的基本功能是
对
Servlet
容器调用
Servlet
的过程进行拦截
,
从而在
Servlet
进行响应处理的前后实现一些特殊的功能
。
•
在
Servlet
API
中定义了三个接口类来开供开发人员编写
Filter
程序:
Filter,
FilterChain
,
FilterConfig
•
Filter
程序是一个实现了
Filter
接口的
Java
类
,与
Servlet
程序相似,
它由
Servlet
容器进行调用和执行
•
Filter
程序需要在
web.xml
文件中进行注册和设置它所能拦截的资源
:
Filter
程序可以拦截
Jsp
,
Servlet
,
静态图片文件和静态
html
文件
1.Filter的基本工作原理
•
当
在
web.xml
中注册了一个
Filter
来对某个
Servlet
程序进行拦截处理时,这个
Filter
就成了
Servlet
容器与该
Servlet
程序的通信线路上的一道关卡,该
Filter
可以对
Servlet
容器发送给
Servlet
程序的请求和
Servlet
程序回送给
Servlet
容器的相应进行拦截,可以决定是否将请求继续传递给
Servlet
程序,以及对请求和相应信息是否进行修改
•
在一个
web
应用程序中可以注册多个
Filter
程序,每个
Filter
程序都可以对一个或一组
Servlet
程序进行拦截。
•
若有多个
Filter
程序对某个
Servlet
程序的访问过程进行拦截,当针对该
Servlet
的访问请求到达时,
web
容器将把这多个
Filter
程序组合成一个
Filter
链
(
过滤器链
)
。
Filter
链中各个
Filter
的拦截顺序与它们在应用程序的
web.xml
中
映射
的顺序一致
2.Filter 接口
1).init
(
FilterConfig
filterConfig
)throws
ServletException
:在
web
应用程序启动时,
web
服务器将根据
web.xml
文件中的配置信息来创建每个注册的
Filter
实例对象,并将其保存在服务器的内存中。
Web
容器创建
Filter
对象实例后,将立即调用该
Filter
对象的
init
方法
。
Init
方法在
Filter
生命周期中仅执行一次
,
web
容器在调用
init
方法时,会传递一个包含
Filter
的配置和运行环境的
FilterConfig
对象
(
FilterConfig的用法和ServletConfig类似
)
。
利用FilterConfig对象可以得到ServletContext对象,以及部署描述符中配置的过滤器的初始化参数
。
在这个方法中,可以抛出ServletException异常,通知容器该过滤器不能正常工作
。
2).destroy()
:在
Web
容器卸载
Filter
对象之前被调用。该方法在
Filter
的生命周期中仅执行一次。
在这个方法中,可以释放过滤器使用的资源
•
与开发Servlet不同的是,Filter接口并没有相应的实现类可供继承,要开发过滤器,只能直接实现Filter接口
。
3).doFilter
(
ServletRequest
request,ServletResponse
response,
FilterChainchain)throwsjava.io.IOException,ServletException:
doFilter()方法类似于Servlet接口的service()方法。当客户端请求目标资源的时候,容器就会调用与这个目标资源相关联的过滤器的doFilter()方法。其中参数request,response为 web 容器或Filter链的上一个Filter传递过来的请求和相应对象;参数chain为代表当前 Filter链的对象,在特定的操作完成后,可以在当前Filter对象的 doFilter方法内部需要调用FilterChain对象的chain.doFilter(request,response)方法才能把请求交付给Filter链中的下一个 Filter 或者目标 Servlet程序去处理,也可以直接向客户端返回响应信息,或者利用RequestDispatcher的forward()和include()方法,以及HttpServletResponse的sendRedirect()方法将请求转向到其他资源。这个方法的请求和响应参数的类型是ServletRequest和ServletResponse,也就是说,过滤器的使用并不依赖于具体的协议。
3.FilterChain接口
•
FilterChain
接口:
代表当前
Filter
链的对象
。由容器实现,容器将其实例作为参数传入过滤器对象的
doFilter
()
方法中。
过滤器对象使用
FilterChain
对象调用过滤器链中的下一个过滤器
,如果该过滤器是链中最后一个过滤器,那么将调用目标资源。
1).doFilter
(
ServletRequest
request,ServletResponse
response)throws
java.io.IOException
:调用该方法将使过滤器链中的下一个过滤器被调用。如果是最后一个过滤器,会调用目标资源。
4.FilterConfig接口
•
javax.servlet.FilterConfig
接口:该接口类似于
ServletConfig
接口,由容器实现。
Servlet
规范将代表
ServletContext
对象和
Filter
的配置参数信息都封装在该对象中。
Servlet
容器将其作为参数传入过滤器对象的
init()
方法中。
•
String
getFilterName
()
:得到描述符中指定的过滤器的名字。
•
String
getInitParameter
(Stringname)
: 返回在部署描述中指定的名字为
name
的初始化参数的值。如果不存在返回
null.
•
Enumeration
getInitParameterNames
()
:返回过滤器的所有初始化参数的名字的枚举集合。
•
public
ServletContext
getServletContext
()
:返回
Servlet
上下文对象的引用。
5.映射 Filter
•
<
filter-mapping>
元素用于设置一个
Filter
所负责拦截的资源。一个
Filter
拦截的资源可通过两种方式来指定:
Servlet
名称和资源访问的请求路径
(
url
样式
)
–
<filter-name>
子元素用于设置
filter
的注册名称。该值必须是在
<filter>
元素中声明过的过滤器的名字
–
<
url
-pattern>
设置
filter
所拦截的请求路径
(
过滤器关联的
URL
样式
)
–
<
servlet
-name>
指定过滤器所拦截的
Servlet
名称。
–
<dispatcher>
指定过滤器所拦截的资源被
Servlet
容器调用的方式
,可以是
REQUEST,INCLUDE,FORWARD
和
ERROR
之一,默认
REQUEST.
可以设置多个
<dispatcher>
子元素用来指定
Filter
对资源的多种调用方式进行拦截
•
<dispatcher>
子元素可以设置的值及其意义:
–
REQUEST
:当用户直接访问页面时,
Web
容器将会调用过滤器。如果目标资源是通过
RequestDispatcher
的
include()
或
forward()
方法访问时,那么该过滤器就不会被调用。通过 GET 或 POST 请求直接访问。
–
INCLUDE
:如果目标资源是通过
RequestDispatcher
的
include()
方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。<jsp:include file="/..." />
–
FORWARD
:如果目标资源是通过
RequestDispatcher
的
forward()
方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。 <jsp:forward page="/..." /> 或 通过 page 指令的 errorPage 转发页面. <%@ page errorPage="test.jsp" %>
–
ERROR
:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。在 web.xml 文件中通过 error-page 节点进行声明:
•
在同一个
web.xml
文件中可以为同一个
Filter
设置多个映射。若一个
Filter
链中多次出现了同一个
Filter
程序,这个
Filter
程序的拦截处理过程将被多次执行
6.典型应用:
1•使浏览器不缓存页面的过滤器:
–
有
3
个
HTTP
响应头字段都可以禁止浏览器缓存当前页面,它们在
Servlet
中的示例代码如下:
•
response.setDateHeader
("Expires",-1);
•
response.setHeader
("Cache-
Control","no
-cache");
•
response.setHeader
("
Pragma","no
-cache");
–
并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用上面的三个响应头
2.字符编码的过滤器
–
通过配置参数
encoding
指明使用何种字符编码
,
以处理
HtmlForm
请求参数的中文问题
3.检测用户是否登陆的过滤器:
–
情景:系统中的某些页面只有在正常登陆后才可以使用,用户请求这些页面时要检查
session
中有无该用户信息,但在所有必要的页面加上
session
的判断相当麻烦的事情
–
解决方案:编写一个用于检测用户是否登陆的过滤器,如果用户未登录,则重定向到指的登录页面
–
要求:需检查的在
Session
中保存的关键字;如果用户未登录,需重定向到指定的页面
(URL
不包括
ContextPath
);
不做检查的
URL
列表
(
以分号分开,并且
URL
中不包括
ContextPath
)
都要采取可配置的方式
4.利用Filter限制用户浏览权限
5.装饰 HttpServletRequest对象
•
需求
:在
HttpServletRequest
对象到达
Servlet
之前把用户输入的多余空格都去掉
•
情景:因为
HttpServletRequest
对象里的请求参数都实际包含在
java.util.Map
对象里,而
Map
是不允许修改的,所以包含在
HttpServletRequest
对象里的请求参数不能被修改
•
解决方案:采取
Decorator(
装饰器
)
模式
7、Decorator 模式
•
因为
继承的关系,当需要改变某个对象的行为时,只须扩展这个对象所属的类并重写其有关的方法就可以达到目的。但是,
当想要改变其行为的对象是由应用程序里的另一个子系统
(
例如:一个对象工厂或是一个
Servlet
容器
)
负责构造,继承机制将无能为力
•
需求:让
broadcast
方法打印的字母都是大写字母
•
方案:从
Messager
类派生一个子类,把子类对象传递给
broadcast
方法。因为只有对象工厂知道如何初始化
Messager
对象,所以该方案无意义
•
Decorator
模式:
–
从
Messager
类派生一个子类
MessagerDecorator
,把子类对象传递给
broadcast
方法
–
在
MessagerDecorator
类里实现构造器:接受一个
Messager
对象作为输入参数,而这个
Messager
就是想要装饰的对象:
public
MessagerDecorator
(
Messager
messager
)
–
重写
getMessage
方法,让重写的方法用大写字母来返回
message
属性
典型应用5:为论坛过滤不雅文字和HTML特殊字符
•
开发论坛模块时要解决以下两个问题
:
–
1.
用户回复或发帖时可能会输入
HTML
代码
(
例如:
<,>
等
)
,这可能会破坏论坛的正常显示,也可能会带来安全隐患。
–
2.
某些用户在回复时可能会输入不雅子句,这些子句会给论坛带来不好的影响
–
3.
实现对不雅文字的可配置
要求:不雅文字及其替换内容实现可配置。如i shit you i **** you
例子:开发一个留言板程序