过滤器和监听器.docx
- 文档编号:9958404
- 上传时间:2023-02-07
- 格式:DOCX
- 页数:33
- 大小:404.89KB
过滤器和监听器.docx
《过滤器和监听器.docx》由会员分享,可在线阅读,更多相关《过滤器和监听器.docx(33页珍藏版)》请在冰豆网上搜索。
过滤器和监听器
过滤器和监听器
1、过滤器
过滤器概念
Servlet过滤器是在Servlet2.3规范中定义的,它是一种可以插入的Web组件,能够对Web服务器接收到的客户端请求和向客户端发出的响应进行拦截过滤,过滤器支持对Servlet程序和JSP页面的基本请求处理功能。
Servlet过滤器是Servlet的一种特殊用法,主要用来完成一些通用的操作,如性能评测、用户验证、字符替换、编码设置、详细的日志、对响应数据进行压缩处理、改变图像文件、对用户数据的安全性处理等。
Servlet/JSP提供的过滤器机制,其实是设计模式中InterceptorFilter模式的实现。
介于service()方法运行前、后的需求
过滤器工作流程
Servlet过滤器本身不产生请求和响应,它只提供过滤作用。
当Web请求发起时,Web服务器首先判断是否存在过滤器和这个请求的目标资源相关,如果存在关联Web服务器将把请求交给过滤器去处理,在过滤器中可以对请求的内容做出改变(可以修改request对象的头部和request对象的内容),然后再将请求转交给被请求的目标资源。
当被请求的资源做出响应时,Web服务器同样会将响应先转发给过滤器,在过滤器中可以对响应做出处理(可以修改response对象的头部和response对象的内容),然后再将响应发送给客户端。
过滤器链
在一个Web应用程序中可以配置多个过滤器,从而形成过滤器链。
FilterChain(过滤器链)由Servlet容器提供,表示资源请求调用时过滤器的链表。
过滤器使用FilterChain来调用链表里的下一个过滤器。
FilterChain的实现就是将多个过滤器类在web.xml文件中进行设置,只要在过滤器类中调用doFilter方法,Servlet就自动按web.xml文件中配置过滤器(
在请求目标资源时,过滤器链中的过滤器依次对请求作出处理,在接收到响应时再按照相反的顺序对响应做出处理。
过滤器链的工作流程图如下:
将服务需求设计为可插拔的元件
在请求转发时应用过滤器
Filter接口
所有的Servlet过滤器类都必须实现javax.servlet.filter接口,该接口中定义了3个过滤器必须实现的方法。
(1)publicvoidinit(FilterConfigfilterConfig):
过滤器的初始化方法,通常用来做资源的初始化工作。
Servlet容器在创建过滤器实例时调用这个方法,在这个方法中可以利用FilterConfig对象的getInitParameter方法读出在web.xml文件中为该过滤器配置的初始化参数。
(2)publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain):
用于完成实际的过滤操作,当客户请求访问与过滤器关联的URL时,Web服务器将先调用过滤器的这个方法。
FilterChain对象负责将请求和响应向后传递。
(3)publicvoiddestroy():
过滤器在即将被销毁时执行这个方法,通常用于释放过滤器申请的资源。
过滤器开发步骤
(1)创建一个实现了javax.servlet.Filter接口的类。
(2)实现init(FilterConfigfilterConfig)方法,该方法中一般编写初始化Filter需要执行的代码。
(3)实现方法doFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain),该方法中编写实现过滤操作的代码,调用FilterChain参数的doFilter(request,response)方法。
(4)实现destroy()方法,大多数简单过滤器为此方法提供一个空实现。
(5)针对被访问的目标Web组件(Servlet程序或者JSP页面)注册过滤器:
在部署描述文件web.xml中使用
过滤器配置
配置需要用到部署描述符文件web.xml
过滤器配置需要用到部署描述符文件web.xml的两个元素
(1)
这是一个必需的元素,它给过滤器分配一个选定的名字。
这是一个必需的元素,它指定过滤器实现类的完全限定名即类的全名。
这是一个可选的元素,它定义可利用FilterConfig的getInitParameter方法读取的初始化参数。
(2)
这个一个必需的元素,该名称必须与用
此元素声明一个以斜杠/开始的模式,它指定过滤器应用的URL。
触发过滤器的时机,默认是浏览器直接发出请求。
如果不设置任何dispatcherTypes,则默认为REQUEST。
FORWARD就是指通过RequestDispatcher的forward()而来的请求可以套用过滤器。
INCLUDE就是指通过RequestDispatcher的include()而来的请求可以套用过滤器。
ERROR是指由容器处理异常而转发过来的请求可以触发过滤器。
ASYNC是指异步处理的请求可以触发过滤器(之后还会说明异步处理)。
如果是那些通过Request-Dispatcher的forward()或include()的请求,若要在web.xml中设置,则可以使用
例如:
使用@WebFilter注解进行配置
@WebFilter用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。
该注解具有下表给出的一些常用属性(以下所有属性均为可选属性,但是value、urlPatterns、servletNames三者必需至少包含一个,且value和urlPatterns不能共存,如果同时指定,通常忽略value的取值)。
常用属性:
属性名
类型
描述
filterName
String
指定过滤器的name属性,等价于
value
String[]
该属性等价于urlPatterns属性。
但是两者不应该同时使用。
urlPatterns
String[]
指定一组过滤器的URL匹配模式。
等价于
servletNames
String[]
指定过滤器将应用于哪些Servlet。
取值是@WebServlet中的name属性的取值,或者是web.xml中
dispatcherTypes
DispatcherType
指定过滤器的转发模式。
具体取值包括:
ASYNC、ERROR、FORWARD、INCLUDE、REQUEST。
initParams
WebInitParam[]
指定一组过滤器初始化参数,等价于
asyncSupported
boolean
声明过滤器是否支持异步操作模式,等价于
description
String
该过滤器的描述信息,等价于
displayName
String
该过滤器的显示名,通常配合工具使用,等价于
如果是那些通过Request-Dispatcher的forward()或include()的请求,设置@WebFilter的dispatcherTypes。
例如:
@WebFilter(
filterName="some",
urlPatterns={"/some"},
dispatcherTypes={
DispatcherType.FORWARD,
DispatcherType.INCLUDE,
DispatcherType.REQUEST,
DispatcherType.ERROR,DispatcherType.ASYNC
}
)
例程
1、利用过滤器实现对整个Web应用的HTTP请求响应做相应的编码处理。
//编码过滤器:
如果在初始化参数中配置了encode,那么将所有的过滤的请求和响应均设置为指定的编码;否则,直接通过过滤器不做任何处理。
//@WebFilter(filterName="EncodeFilter",urlPatterns={"/*"},initParams={
@WebInitParam(name="encode",value="UTF-8")})//①使用@WebFilter注解标注过滤器
publicclassEncodeFilterimplementsFilter{
privateFilterConfigconfig;
privatestaticfinalStringINIT_PARAM_ENCODE="encode";//初始化配置参数
publicvoidinit(FilterConfigconfig)throwsServletException{this.config=config;}//初始化方法
publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)
throwsIOException,ServletException{
HttpServletRequestreq=(HttpServletRequest)request;
HttpServletResponseres=(HttpServletResponse)response;
Stringencode=config.getInitParameter(INIT_PARAM_ENCODE);
if(encode!
=null&&!
encode.isEmpty()){
req.setCharacterEncoding(encode);
System.out.println("EncodeFilter");
}
chain.doFilter(request,response);
if(encode!
=null&&!
encode.isEmpty()){
res.setCharacterEncoding(encode);
}
}
publicvoiddestroy(){}
}
2、使用过滤器过滤未登录用户或者登录失败用户使其重新返回到登录页面登录。
login.jsp
<%
Stringmessage=(String)session.getAttribute("message");
if(message!
=null){
out.println(message);
session.removeAttribute("message");
}
%>
用户名:
密码:
LoginServlet.java
publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException{
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
Stringname=request.getParameter("name");
Stringpassword=request.getParameter("password");
System.out.println(name);
HttpSessionsession=request.getSession();
if("张三".equals(name)&&"123".equals(password)){
session.setAttribute("name",name);
session.setAttribute("message","恭喜您,登录成功!
");
request.getRequestDispatcher("/index.jsp").forward(request,response);
}else{
session.setAttribute("message","对不起,登录信息有误,请重新登录!
");
response.sendRedirect(request.getContextPath()+"/login.jsp");
}
}
LoginFilter.java
publicclassLoginFilterimplementsFilter{
publicvoidinit(FilterConfigarg0)throwsServletException{
/*包含初始化Filter时需要执行的代码,该代码执行一次**/
}
publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,
FilterChainchain)throwsIOException,ServletException{
HttpServletRequestreq=(HttpServletRequest)request;
HttpServletResponseres=(HttpServletResponse)response;
HttpSessionsession=req.getSession();
Stringname=(String)session.getAttribute("name");
if(name!
=null){
chain.doFilter(req,res);
}else{
res.sendRedirect(req.getContextPath()+"/login.jsp");
}
}
publicvoiddestroy(){/*包含资源释放的代码,通常对init()中的初始化的资源执行收尾工作;*/}
}
index.jsp。
LoginFilter.java配置代码
LoginServlet.java配置代码
滤器执行流程
请求封装器
以下举两个实际的例子,来说明请求封装器的实现与应用,分别是字符替换过滤器与编码设置过滤器。
1.实现字符替换过滤器
假设有个留言版程序已经上线并正常运作中,但是现在发现,有些用户会在留言中输入一些HTML标签。
基于安全性的考量,不希望用户输入的HTML标签直接出现在留言中而被浏览器当作HTML的一部分。
例如,并不希望用户在留言中输入 //openhome.cc">OpenHome.cc这样的信息,你不想信息在留言显示中直接变成超链接,让用户有机会在留言版中打广告,如图5.7所示。 图5.7留言版被拿来打广告了 希望将一些HTML过滤掉,如将<、>角括号置换为HTML实体字符<与>。 如果不想直接修改留言版程序,则可以使用过滤器的方式,将用户请求参数中的角括号字符进行替换。 但问题在于,虽然可以使用HttpServletRequest的getParameter()取得请求参数值,但就是没有一个像setParameter()的方法,可以将处理过后的请求参数重新设置给HttpServletRequest。 对于容器产生的HttpServletRequest对象,无法直接修改某些信息,如请求参数值就是一个例子。 你也许会想要亲自实现HttpServletRequest接口,让getParameter()返回过滤后的请求参数值,但这么做的话,HttpServletRequest接口定义的方法都要实现,实现所有方法非常麻烦。 所幸,有个HttpServletRequestWrapper帮你实现了HttpServletRequest接口,只要继承HttpServletRequestWrapper类,并编写想要重新定义的方法即可。 相对应于ServletRequest接口,也有个ServletRequestWrapper类可以使用。 如图5.8所示。 图5.8ServletRequestWrapper与HttpServletWrapper 以下的范例通过继承HttpServletRequestWrapper实现了一个请求封装器,可以将请求参数中的HTML符号替换为HTML实体字符。 FilterDemoEscapeWrapper.java importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletRequestWrapper; importmons.lang3.StringEscapeUtils; publicclassEscapeWrapperextendsHttpServletRequestWrapper{//1继承HttpServletRequestWrapper publicEscapeWrapper(HttpServletRequestrequest){ super(request);//2必须调用父类构造器,传入HttpServletRequest实例 } @Override publicStringgetParameter(Stringname){//3重新定义getParameter()方法 Stringvalue=getRequest().getParameter(name); returnStringEscapeUtils.escapeHtml4(value);//4将取得的请求参数值进行字符替换 } } EscapeWrapper类继承了HttpServletRequestWrapper,并定义了一个接受HttpServletRequest的构造器,真正的HttpServletRequest将通过此构造器传入,必须使用super
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 过滤器 监听器