过滤器
过滤器是一种代码重用的技术,它可以改变
HTTP
请求的内容,响应,及
header
信息。过滤器通常不产生响应或像servlet
那样对请求作出响应,而是修改或调整到资源的请求,修改或调整来自资源的响应。
供开发人员使用的过滤器功能有六种类型:
在执行请求之前访问资源
在执行请求之前处理资源的请求
用请求对象的自定义版本包装请求,对请求的
header
和数据进行修改
用响应对象的自定义版本包装响应,对响应的
header
和数据进行修改
拦截资源调用之后的调用
按指定顺序执行的零个、一个或多个拦截器作用于
Servlet
,一组
Servlet
或静态内容
基础开发
应用开发人员通过实现
javax.servlet.Filter
接口并提供一个公共的空参构造器来创建过滤器。该类及构建Web应用的静态资源和
Servlet
打包在
Web
应用归档文件中。
Filter
在部署描述符中通过
元素声 明。一个过滤器或一组过滤器可以通过在部署描述符中定义
-
mapping>
来为调用配置。可以使 用servlet
的逻辑视图名把过滤器映射到一个特定的
servlet
,或者使用
URL
模式把一组
Servlet
和静态资源
内容映射到过滤器。
需求:编码字符集问题
定义过滤器类实现
Filter
接口
web.xml
中配置
在部署描述符中声明的每个
在每个
JVM
的容器中仅实例化一个实例。容器提供了声明在过滤器 的部署描述符的过滤器config
(
FilterConfig
),对
Web
应用的
ServletContext
的引用和一组初始化参数。
public class
EncodingFilter
implements
Filter
{
@Override
public
void
doFilter
(
ServletRequest request
,
ServletResponse response
,
FilterChain chain
)
throws
IOException
,
ServletException
{
request
.
setCharacterEncoding
(
"UTF-8"
);
response
.
setCharacterEncoding
(
"UTF-8"
);
//
前置处理
chain
.
doFilter
(
request
,
response
);
//
执行下一个过滤器
//
后置处理
}
}
encoder
com.yan.filters.EncodingFilter
encoder
/aa.do
在
web.xml
中针对
Filter
添加初始化参数
可以在
Filter
实现类的
init
方法中通过
FilterConfig
进行获取
过滤器的核心概念是包装请求或响应,以便它可以覆盖行为执行过滤任务。在这个模型中,开发人员不
仅可以覆盖请求和响应对象上已有的方法,也能提供新的
API
以适用于对过滤器链中剩下的过滤器或目标
web
资源做特殊的过滤任务。
encoder
com.yan.filters.EncodingFilter
配置初始化参数
public class
EncodingFilter
implements
Filter
{
public
EncodingFilter
(){
//
过滤器对象在服务器启动后自动加载创建对象
System
.
out
.
println
(
"
构造器
..."
);
}
private
String
encoding
=
"UTF-8"
;
@Override
public
void
init
(
FilterConfig filterConfig
)
throws
ServletException
{
//
初始化方法在对象创建完成后自动执行,可以通过
filterConfig
对象获取配置参数值。在整个
Filter
对象的生命周期中运行且只运行一次
System
.
out
.
println
(
"init
方法
...."
);
String
ss
=
filterConfig
.
getInitParameter
(
"encoding"
);
//
通过服务器调
用
init
方法时传入的
FilterConfig
对象读取配置参数值,名称已知
if
(
ss
!=
null
&&
ss
.
trim
().
length
()
>
0
)
this
.
encoding
=
ss
.
trim
();
}
@Override
public
void
destroy
() {
//Filter
对象处理完成后常驻内存,只有在关闭服务器等特殊
情况下才会销毁对象。在销毁对象前执行
destroy
方法,可以用于执行资源回收操作
System
.
out
.
println
(
"destroy...."
);
}
@Override
public
void
doFilter
(
ServletRequest request
,
ServletResponse response
,
FilterChain chain
)
throws
IOException
,
ServletException
{
//
以单实例多线程的方
式执行过滤处理
request
.
setCharacterEncoding
(
encoding
);
response
.
setCharacterEncoding
(
encoding
);
System
.
out
.
println
(
"EncodingFilter....begin...."
);
//
前置处理
chain
.
doFilter
(
request
,
response
);
//
执行下一个过滤器
//
后置处理
System
.
out
.
println
(
"EncodingFilter....end...."
);
}
}
可以使用部署描述符中的
-
params>
元素把一组初始化参数关联到过滤器。这些参数的名字和值在
过滤器运行期间可以使用过滤器的
FilterConfig
对象的
getInitParameter
和
getInitParameterNames
方法
得到。另外,
FilterConfig
提供访问
Web
应用的
ServletContext
用于加载资源,记录日志,在
ServletContext
的属性列表存储状态。链中最后的过滤器和目标
servlet
或资源必须执行在同一个调用线 程。
过滤器可以通过
@WebFilter
注解定义或者在部署描述符中使用
元素定义。在这个元素中,可声明三种内容:
filter-name
:用于映射过滤器到
servlet
或
URL
value
用于定义对应的
URL
地址,是
urlPatterns
的别名
init-params
:过滤器的初始化参数
容器必须为部署描述符中定义的每个过滤器声明实例化一个
Java
类实例。因此,如果开发人员对一个过 滤器类声明了两次,则容器将实例化两个相同的过滤器类的实例。
容器实例过滤器对象时是通过反射实现的,所以要求无参构造器
一旦在部署描述符中声明了过滤器,配置人员使用
-
mapping>
定义
Web
应用中的
servlet
和静态 资源到过滤器的应用。过滤器可以使用
-
name>
元素关联到一个
Servlet
。过滤器可以使用
-
pattern>
风格的过滤器映射关联到一组
servlet
和静态内容。
当使用
-
pattern>
风格配置
-
mapping>
元素,容器必须使用路径映射规则决定
pattern>
是否匹配请求
URI
。
容器使用的用于构建应用到一个特定请求
URI
的过滤器链的顺序:
@WebFilter
(
filterName
=
"encoder"
,
value
=
{
"*.do"
,
"/bb.did"
,
"/images/*"
},
initParams
=
{
@WebInitParam
(
name
=
"encoding"
,
value
=
"ISO8859-1"
)
})
public class
EncodingFilter
implements
Filter
{
encoder
com.yan.filters.EncodingFilter
encoder
test
test
com.yan.action.TestServlet
test
/test.do
1
)首先
-
pattern>
按照在部署描述符中的出现顺序匹配过滤器映射。
2
)接下来
-
name>
按照在部署描述符中的出现顺序匹配过滤器映射。
如果过滤器映射同时包含了
-
name>
和
-
pattern>
,容器必须展开过滤器映射为多个过滤
器映射(每一个
-
name>
和
-
pattern>
一个),保持
-
name>
和
-
pattern>
元素顺序。
通过在部署描述符中使用心得
元素,开发人员可以为
filter-mapping
指定是否想要过滤器
应用到请求,当:
1
)请求直接来自客户端。可以由一个带有
REQUEST
值的
元素,或者没有任何
元素来表示。
2
)使用表示匹配
-
pattern>
或
-
name>
的
web
组件的请求分配器的
forward()
调用情况下
处理请求。可以由一个带有
FORWARD
值的
元素表示。
3
)使用表示匹配
-
pattern>
或
-
name>
的
Web
组件的请求分派器的
include()
调用情况下
处理请求。可以由一个带有
INCLUDE
值的
元素表示。
4
)使用错误处理指定的错误页面机制处理匹配
-
pattern>
的错误资源的请求。可以由一个带有
ERROR
值的
元素表示。
5
)使用异步处理中的异步上下文分派机制对
web
组件使用
dispatche
调用处理请求。可以由一个带有
ASYNC
值的
元素表示。
6
)也可以是
1,2,3,4,5
的任何组合。
FilterConfig
类
FilterConfig
是
Filter
过滤器的的配置类,
Tomcat
启动创建
Filter
时就会创建一个
FilterConfig
类对象,这
里包含了
Filter
的配置信息。
FilterConfig
类的作用是获取
filter
过滤器的配置内容
1
、获取过滤器的名称即
Filter-name
标签的值。
2
、获取过滤器的初始参数即
init-param
标签的值。
3
、获取
ServletContext
对象。
FilterChain
过滤链
String
ss
=
filterConfig
.
getInitParameter
(
"encoding"
);
用于获取指定的配置参数
值,如果没有配置指定的参数则返回为
null
String
filterName
=
filterConfig
.
getFilterName
();
获取配置的
filter
的名称,例如对应
<
filter
-
name
>
final
Enumeration
<
String
>
names
=
filterConfig
.
getInitParameterNames
();
获取
所有的配置参数名称的迭代器
while
(
names
.
hasMoreElements
()){
String
name
=
names
.
nextElement
();
String
value
=
filterConfig
.
getInitParameter
(
name
);
}
final
ServletContext application
=
filterConfig
.
getServletContext
();
获取应用
上下文对象
作用:往下继续执行过滤器或者执行目标资源
针对不同的信息处理写不同的
Filter
,然后把
Filter
放在一个
FilterChain
中,以实现信息处理的热拔插,
这样一个
FilterChain
就像一条职责链,链上的每个节点处理不同的功能
当
FilterChain
过滤器有多个
Filter
时的特点:
多个
Filter
的执行顺序的先后是由在
web.xml
中定义的先后(从上到下)顺序决定的。注意:由于
Filter
是根据
URL
进行过滤的,最先走到的是
filter-mapping
标签,所以上面所说的定义的先后顺序
是指
filter-mapping
标签的位置顺序。
多个
Filter
执行的时候默认是同一个线程目标资源也是同一个线程
执行的时候是同一个
request
对象。(因为同一次请求)
Filter
拦截器路径
1
、精确匹配。例
/target.jsp
表示
URL
地址必须是
http://
服务地址
:
端口
/
工程目录
/target.jsp
2
、目录匹配。例
/admin/*
表示
URL
地址必须是以
http://
服务地址
:
端口
/
工程目录
/admin/
开头
3
、后缀名匹配。例如
*.jsp
表示
URL
地址必须以
.jsp
结尾;
*.do
表示
URL
地址必须以
.do
结尾,注
意不能是含有
/
否则错误
Filter
过滤器它只关心请求的地址是否匹配, 不关心请求的资源是否存在
责任链模式
责任链模式
Chain of Responsibility Pattern
为请求创建了一个接收者对象的链。这种模式给予请求的类
型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式
意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条
链,并且沿着这条链传递请求,直到有对象处理它为止。
主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的
处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
优点:
1
、降低耦合度。它将请求的发送者和接收者解耦。
2
、简化了对象。使得对象不需要知道链的
结构。
3
、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增
或者删除责任。
4
、增加新的请求处理类很方便。
缺点:
1
、不能保证请求一定被接收。
2
、系统性能将受到一定影响,而且在进行代码调试时不太方
便,可能会造成循环调用。
3
、可能不容易观察运行时的特征,有碍于除错。
首先定义接口
Filter
。所有的
Filter
必须遵循这个规范,才能装载在
FilterChain
中
定义
FilterChain
以及各个
Filter
public interface Filter {
void doFilter(Request request,Response response,FilterChain chain);
}
public class
FilterChain
implements
Filter
{
List
<
Filter
>
fs
=
new
ArrayList
<
Filter
>
();
int
index
=
0
;
public
FilterChain addFilter
(
Filter f
) {
fs
.
add
(
f
);
return this
;
}
public
void
doFilter
(
Request request
,
Response response
,
FilterChain chain
) {
定义过滤器
测试程序
Filter
生命周期
1
、加载和实例化。
Web
容器启动时,即会根据
web.xml
中声明的
filter
顺序依次实例化这些
filter
2
、初始化。
Web
容器调用
init(FilterConfig)
来初始化过滤器。容器在调用该方法时,向过滤器传递
FilterConfig
对象,
FilterConfig
的用法和
ServletConfig
类似。利用
FilterConfig
对象可以得到
ServletContext
对象,以及在
web.xml
中配置的过滤器的初始化参数。在这个方法中,可以抛出
ServletException
异常,通知容器该过滤器不能正常工作。此时的
Web
容器启动失败,整个应用
if
(
index
==
fs
.
size
())
return
;
Filter f
=
fs
.
get
(
index
);
index
++
;
f
.
doFilter
(
request
,
response
,
chain
);
}
}
public class
HTMLFilter
implements
Filter
{
public
void
doFilter
(
Request request
,
Response response
,
FilterChain
chain
) {
request
.
requestStr
=
request
.
requestStr
.
replace
(
"<"
,
"
["
).
replace
(
">"
,
"]"
)
+
"--HTML--"
;
chain
.
doFilter
(
request
,
response
,
chain
);
response
.
responseStr
+=
"--HTML--"
;
}
}
public class
SensitiveFilter
implements
Filter
{
public
void
doFilter
(
Request request
,
Response response
,
FilterChain
chain
) {
request
.
requestStr
=
request
.
requestStr
.
replace
(
"
被就业
"
,
"
就
业
"
).
replace
(
"
敏感
"
,
"**"
)
+
"--Sensitive--"
;
chain
.
doFilter
(
request
,
response
,
chain
);
response
.
responseStr
+=
"--Sensitive--"
;
}
}
String msg = "
测试,
,被就业,敏感信息
";
FilterChain fc = new FilterChain();
fc.addFilter(new HTMLFilter()).addFilter(new SensitiveFilter());
Request request = new Request();
request.setRequestStr(msg);
Response response = new Response();
response.setResponseStr("response");
fc.doFilter(request, response,fc);
System.out.println(request.getRequestStr());
System.out.println(response.getResponseStr());
程序不能够被访问。实例化和初始化的操作只会在容器启动时执行,而且只会执行一次
3
、
doFilter
doFilter
方法类似于
Servlet
接口的
service
方法。当客户端请求目标资源的时候,容器会筛选出
符合
filter-mapping
中的
url-pattern
的
filter
,并按照声明
filter-mapping
的顺序依次调用这些
filter
的
doFilter
方法。在这个链式调用过程中,可以调用
chain.doFilter(ServletRequest,
ServletResponse)
将请求传给下一个过滤器
(
或目标资源
)
,也可以直接向客户端返回响应信息,或
者利用
RequestDispatcher
的
forward
和
include
方法,以及
HttpServletResponse
的
sendRedirect
方法将请求转向到其它资源。需要注意的是,这个方法的请求和响应参数的类型是
ServletRequest
和
ServletResponse
,也就是说,过滤器的使用并不依赖于具体的协议
4
、销毁
Web
容器调用
destroy
方法指示过滤器的生命周期结束。在这个方法中可以释放过滤器使用的资
源。