第9章 过滤器和监听器_第1页
第9章 过滤器和监听器_第2页
第9章 过滤器和监听器_第3页
第9章 过滤器和监听器_第4页
第9章 过滤器和监听器_第5页
已阅读5页,还剩26页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第9章过滤器和监听器本章主要内容过滤器过滤器创建和配置过滤器为过滤器设置参数过滤器串联在过滤器中包装请求在过滤器中包装响应监听器监听器创建和配置监听器9.1过滤器在多个Web组件中分别编写相同操作的程序代码,会导致代码重复,降低开发效率和增加软件维护的工作量。Servlet2.3规范中出现了过滤器技术,采取“横切”的方式,将与业务无关、却被业务模块共同调用的逻辑封装到一个可重用模块中。便于减少系统的重复代码,实现功能的高度内聚,提高可操作性和可维护性。9.1.1什么是过滤器过滤器是一种小型的、可插入的Web组件,用来拦截Servlet容器的请求和响应过程,以便查看、提取或以某种方式操作正在客户端和服务器之间交互的数据。过滤器的典型应用包括处理请求和响应数据,管理会话属性等,它可以用路径的方式配置给一个Web应用的多个组件,实现功能的复用,当客户端请求此URL时,Servlet容器就会先触发过滤器工作。ServletRequest对象ServletResponse对象

9.1.2创建和配置过滤器自定义过滤器必须实现javax.servlet.Filter接口,并在web.xml中进行配置。Filter接口中包含3个方法init(FilterConfigconfig),过滤器的初始化方法。doFilter(ServletRequestreq,ServletResponseres,FilterChainchain),过滤操作方法。destroy(),Servlet容器在销毁过滤器对象前调用该方法,可以用于释放过滤器占用的资源。

9.1.2创建和配置过滤器【例】演示过滤器的生命周期。创建过滤器CircleDemoFilter,实现Filter接口,重写接口中的3个方法。每个方法在控制台打印输出其所处的阶段。doFilter()方法在chain.doFilter()调用前是一个阶段,可以对向下传递的请求进行预处理;chain.doFilter()之后是另一个阶段,当从某个Web组件返回后,可以在doFilter()中继续对响应进行处理。packagefilter;public

classCircleDemoFilterimplementsFilter{

public

voiddestroy(){ System.out.println("过滤器被销毁");//⑤ }

public

voiddoFilter(ServletRequestreq,ServletResponseres,FilterChainchain)throwsIOException,ServletException{ System.out.println("chain.doFilter()调用前,可以对请求进行预处理...");//② chain.doFilter(req,res);//③ System.out.println("chain.doFilter()调用后,可以对响应进行处理...");//④ }

public

voidinit(FilterConfigarg0)throwsServletException{ System.out.println("过滤器初始化"); //① }}<filter> <filter-name>demo</filter-name> <filter-class>filter.CircleDemoFilter</filter-class></filter><filter-mapping> <filter-name>demo</filter-name> <url-pattern>/*</url-pattern></filter-mapping>对所有URL均起作用9.1.3为过滤器设置参数在web.xml中配置<filter>元素时,可以使用<init-param>子元素为过滤器设置初始化参数,参数名和参数值分别放在<param-name>和<param-value>中。【例】使用过滤器解决Web组件的中文乱码问题。<filter> <filter-name>encode</filter-name> <filter-class>filter.EncodingFilter</filter-class>

<init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param></filter><filter-mapping> <filter-name>encode</filter-name> <url-pattern>/*</url-pattern></filter-mapping>9.1.3为过滤器设置参数public

classEncodingFilterimplementsFilter{

privateStringencoding;

public

void

init(FilterConfigconfig)throwsServletException{

encoding=config.getInitParameter("encoding"); }

public

voiddoFilter(ServletRequestreq,ServletResponseres,FilterChainchain) throwsIOException,ServletException{

req.setCharacterEncoding(encoding); res.setContentType("text/html;charset="+encoding); chain.doFilter(req,res); }public

voiddestroy(){ }}9.1.4过滤器串联多个过滤器可以串联起来协同工作,Servlet容器根据它们在web.xml中定义的先后顺序,依次调用它们的doFilter()方法。9.1.4过滤器串联【例】编写登录处理过滤器。网站中进行用户的首次身份认证之后都会在session中保存用户信息作为标识,之后在需要身份认证的页面查看session即可。网站中通常很多功能都需要进行身份认证,例如购物网站中查看购物车、我的订单、进行结账等等。为了避免出现代码冗余问题,下面设计一个过滤器完成身份认证。public

classLoginFilterimplementsFilter{

public

voiddoFilter(ServletRequestreq,ServletResponseres,FilterChainchain)throwsIOException,ServletException{ HttpServletRequestrequest=(HttpServletRequest)req; HttpServletResponseresponse=(HttpServletResponse)res; HttpSessionsession=request.getSession(); Stringusername=(String)session.getAttribute("user");

if(username==null){//未登录 response.sendRedirect(request.getContextPath()+"/login.html");

return; }

chain.doFilter(request,res); }

public

voidinit(FilterConfigconfig)throwsServletException{ }

public

voiddestroy(){ }}<filter> <filter-name>encode</filter-name> <filter-class>filter.EncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param></filter><filter-mapping> <filter-name>encode</filter-name> <url-pattern>/*</url-pattern></filter-mapping><filter> <filter-name>login</filter-name> <filter-class>filter.LoginFilter</filter-class></filter><filter-mapping> <filter-name>login</filter-name> <url-pattern>/getcart.do</url-pattern> <url-pattern>/getorder.do</url-pattern></filter-mapping>①②9.1.5在过滤器中包装请求在Filter中可以对得到的请求和响应进行再包装。包装(Wrapper)模式:request和response对象由Web容器直接管理,无法直接重写HttpServletRequest和HttpServletResponse类中的方法,所以用包装模式为两个对象赋予更多的功能(增强)包装模式以对客户端透明的方式扩展对象的功能,是继承重写的一个替代方案。在不改变类的源代码及原有继承关系的情况下,动态的扩展对象的功能。HttpServletRequestWrapper:request对象的包装模式的实现类,实现了HttpServletRequest接口中的所有方法。9.1.5在过滤器中包装请求对request对象进行增强的包装模式编程方法(1)创建一个类,继承包装实现类HttpServletRequestWrapper。(2)定义一个构造方法,以增强对象request为参数,在创建包装对象时接收原始的request对象。(3)重写需要增强的方法,编写request的增强功能。9.1.5在过滤器中包装请求【例】使用过滤器解决Web组件的中文乱码问题—2.0版。通用的过滤器,对get和post方式的请求均进行编码处理。public

classCharacterEncodingFilterimplementsFilter{

privateStringencoding;

public

voiddoFilter(ServletRequestreq,ServletResponseres,FilterChainchain)throwsIOException,ServletException{ req.setCharacterEncoding(encoding);//post方式有效 res.setContentType("text/html;charset=UTF-8"); HttpServletRequestrequest=(HttpServletRequest)req;//获取增强后的request对象

MyCharacterEncodingRequestrequestWrapper=newMyCharacterEncodingRequest(request); //传递增强后的request对象requestWrapper

chain.doFilter(requestWrapper,res); }

public

voidinit(FilterConfigconfig)throwsServletException{ encoding=config.getInitParameter("encoding"); }

public

voiddestroy(){ }}classMyCharacterEncodingRequestextendsHttpServletRequestWrapper{ //构造方法:request为被增强对象

publicMyCharacterEncodingRequest(HttpServletRequestrequest){

super(request); } //覆盖需要增强的getParameter()方法

publicStringgetParameter(Stringname){

try{ Stringvalue=super.getParameter(name);

if(value==null){

return

null; }

//如果不是以get方式提交,直接返回参数的取值

if(!super.getMethod().equalsIgnoreCase("get")){

returnvalue; }else{//如果是以get方式提交,对获参数取值进行转码处理 Stringencoding=super.getCharacterEncoding(); value=newString(value.getBytes("ISO8859-1"),encoding);

returnvalue; } }catch(Exceptione){

throw

newRuntimeException(e); } }}9.1.5在过滤器中包装请求9.1.6在过滤器中包装响应ServletAPI为response对象提供的包装模式的实现类为HttpServletResponseWrapper,它实现了HttpServletRsponse接口中的所有方法,对response对象进行增强时只需重写涉及到的方法。【例】页面缓存的实现。某些页面的生成结果可以用缓存的方式完整的保存起来,存储在内存或者文件中,从而减轻数据库的访问压力,提高系统响应速度。页面的内容由response响应对象产生,response.getWriter()获取字符输出流对象,response.getOutputStream()获取字节输出流对象,response使用这两个对象实现向客户端返回字符数据或者二进制数据。页面缓存要修改输出流的去向,不是输出给客户端,而是输出到自定义的缓存区域,因此需要对response的两个输出对象进行重写,重写利用HttpServletResponseWrapper包装类完成。9.1.6在过滤器中包装响应classMyServletOutputStreamextendsServletOutputStream{

privateByteArrayOutputStreambout;

publicMyServletOutputStream(ByteArrayOutputStreambout){//包装

this.bout=bout;}

public

voidwrite(intb)throwsIOException{bout.write(b);//数据写出至bout对象的缓冲区}public

booleanisReady(){return

false;}public

voidsetWriteListener(WriteListenerarg0){}}9.1.6在过滤器中包装响应classResponseToBufferextendsHttpServletResponseWrapper{

privateByteArrayOutputStreambout=newByteArrayOutputStream();

privatePrintWriterpw;

publicResponseToBuffer(HttpServletResponseresponse){

super(response);}

publicServletOutputStreamgetOutputStream()throwsIOException{//返回包装后的ServletOutputStream对象,数据会写入bout对象缓冲区

return

newMyServletOutputStream(bout);}

publicPrintWritergetWriter()throwsIOException{//将bout字节流按response的编码包装为字符流pw=newPrintWriter(newOutputStreamWriter(bout,super.getCharacterEncoding()));

returnpw;}

public

byte[]getBuffer(){

try{pw.flush();//输出缓冲区的数据

returnbout.toByteArray();//返回缓冲区的数据}catch(Exceptione){

throw

newRuntimeException(e);}finally{

if(pw!=null){pw.close();}

if(bout!=null){try{bout.close();}catch(IOExceptione){}}}}}public

classCacheFilterimplementsFilter{//缓存对应的Map容器<uri:缓存数据>

privateMap<String,byte[]>map=newHashMap<String,byte[]>();

public

voidinit(FilterConfigfilterConfig)throwsServletException{}

public

voiddoFilter(ServletRequestreq,ServletResponseres,FilterChainchain)throwsIOException,ServletException{ HttpServletRequestrequest=(HttpServletRequest)req;HttpServletResponseresponse=(HttpServletResponse)res;//1.获取用户请求的URI地址,例如目录文件URI:/chap9/main/category.jspStringuri=request.getRequestURI();//2.查看缓存中是否存在URI对应的数据

bytebuffer[]=map.get(uri);//3.如果缓存中有,直接将缓存的页面发送给客户端,程序返回

if(buffer!=null){response.getOutputStream().write(buffer);//缓存数据

return;}//4.如果没有缓存,执行目标资源,并捕获目标资源的输出至缓冲区ResponseToBuffermyResponse=newResponseToBuffer(response);chain.doFilter(request,myResponse);//传递包装后的响应对象

//5.从目标资源返回后,获取缓冲区的数据

byteout[]=myResponse.getBuffer();//6.将数据以请求的URI为关键字保存到Mapmap.put(uri,out);//7.向客户端输出响应结果(无缓存的原始页面)response.getOutputStream().write(out);}

public

voiddestroy(){}}9.2监听器Servlet2.3规范引入监听Web应用程序事件模拟模型,当Web应用中的某些状态发生改变时,Servlet容器就会产生相应的事件。9.2.1什么是监听器监听器用来监听Servlet容器产生的事件并进行相应的处理。容器产生的事件分为两类,一类是与生命周期相关的事件,另一类是与绑定数据(属性变量)相关的事件。生命周期相关事件监听器接口事件方法描述ServletContextListenercontextInitialized(ServletContextEventsce)创建ServletContext对象时触发contextDestoryed(ServletContextEventsce)销毁ServletContext对象时触发HttpSessionListenersessionCreated(HttpSessionEventse)创建HttpSession对象时触发sessionDestoryed(HttpSessionEventse)销毁HttpSession对象时触发ServletRequestListenerrequestInitialized(ServletRequestEventsre)创建ServletRequest对象时触发requestDestoryed(ServletRequestEventsre)销毁ServletRequest对象时触发绑定数据相关事件监听器接口事件方法描述ServletContextAttributeListenerattributeAdded(ServletContextAttributeEventscae)添加属性时触发attributeRemoved(ServletContextAttributeEventscae)删除属性时触发attributeReplaced(ServletContextAttributeEventscae)修改属性时触发HttpSessionAttributeListenerattributeAdded(HttpSessionBindingEventhsbe)添加属性时触发attributeRemoved(HttpSessionBindingEventhsbe)删除属性时触发attributeReplaced(HttpSessionBindingEventhsbe)修改属性时触发ServletRequestAttributeListenerattributeAdded(ServletRequestAttributetEventsrae)添加属性时触发attributeRemoved(ServletRequest

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论