Java Web編程技術(shù) 課件 第7章過濾器與監(jiān)聽器_第1頁
Java Web編程技術(shù) 課件 第7章過濾器與監(jiān)聽器_第2頁
Java Web編程技術(shù) 課件 第7章過濾器與監(jiān)聽器_第3頁
Java Web編程技術(shù) 課件 第7章過濾器與監(jiān)聽器_第4頁
Java Web編程技術(shù) 課件 第7章過濾器與監(jiān)聽器_第5頁
已閱讀5頁,還剩58頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

JavaWeb編程技術(shù)本章首先紹Web過濾器的開發(fā)與配置,然后介紹Web應(yīng)用中事件和事件監(jiān)聽器,最后討論Servlet多線程問題。過濾器的開發(fā)與配置Web應(yīng)用事件類型及事件對象使用監(jiān)聽器處理Web事件Servlet的多線程問題第7章過濾器和監(jiān)聽器過濾器用于攔截傳入的請求或傳出的響應(yīng),并監(jiān)視、修改或以某種方式處理這些通過的數(shù)據(jù)流。Web應(yīng)用程序運(yùn)行過程中可能發(fā)生各種事件,如應(yīng)用上下文事件、會話事件及請求有關(guān)的事件等,Web容器采用監(jiān)聽器模型處理這些事件。Web過濾器過濾器(filter)是Web服務(wù)器上的組件,它攔截客戶對某個資源的請求和響應(yīng),對其進(jìn)行過濾。7.1.1什么是過濾器7.1.2過濾器API7.1.3簡單的編碼過濾器7.1.4@WebFilter注解7.1.5在web.xml中配置過濾器7.1什么是過濾器7.1.1圖7-1說明了過濾器的一般概念,其中F1是一個過濾器。它顯示了請求經(jīng)過濾器F1到達(dá)Servlet,Servlet產(chǎn)生響應(yīng)再經(jīng)過濾器F1到達(dá)客戶。這樣,過濾器就可以在請求和響應(yīng)到達(dá)目的地之前對它們進(jìn)行監(jiān)視??梢栽诳蛻艉唾Y源之間建立多個過濾器,從而形成過濾器鏈(filterchain)。圖7-2說明了這個過程。什么是過濾器7.1.11.過濾器是如何工作的當(dāng)容器接收到對某個資源的請求時,它首先檢查是否有過濾器與該資源關(guān)聯(lián)。如果有過濾器與該資源關(guān)聯(lián),容器先把該請求發(fā)送給過濾器,而不是直接發(fā)送給資源。在過濾器處理完請求后,它將做下面三件事:將請求發(fā)送到目標(biāo)資源。如果有過濾器鏈,它將把請求(修改過或沒有修改過)發(fā)送給下一個過濾器。直接產(chǎn)生響應(yīng)并將其返回給客戶。當(dāng)請求返回到客戶時,它將以相反的方向經(jīng)過同一組過濾器。過濾器鏈中的每個過濾器都可能修改響應(yīng)。2.過濾器的用途Servlet規(guī)范中提到的過濾器的一些常見應(yīng)用包括:驗證過濾器、登錄和審計過濾器、數(shù)據(jù)壓縮過濾器、加密過濾器和XSLT過濾器等。過濾器API7.1.1表7-1描述了過濾器API,其中HttpFilte類定義在jakarta.servle.httpt包中,其他接口和類定義在jakarta.servlet包中。接口說明Filter所有的過濾器都需要實現(xiàn)該接口FilterConfig過濾器配置對象。容器提供了該對象,其中包含了該過濾器的初始化參數(shù)GenericFilter該抽象類實現(xiàn)了FilterConfig接口的方法和Filter接口的init()方法HttpFilter該抽象類擴(kuò)展了GenericFilter類,實現(xiàn)針對HTTP協(xié)議的過濾器FilterChain過濾器鏈對象過濾器API7.1.21.Filter接口Filter接口是過濾器API的核心,所有的過濾器都必須實現(xiàn)該接口。該接口聲明了三個方法,分別是init()、doFilter()和destroy(),它們是過濾器的生命周期方法。init()是過濾器初始化方法。在過濾器的生命周期中,init()僅被調(diào)用一次。在該方法結(jié)束之前,容器并不向過濾器轉(zhuǎn)發(fā)請求。該方法的聲明格式為:publicvoidinit(FilterConfigfilterConfig)參數(shù)FilterConfig是過濾器配置對象,通常將FilterConfig參數(shù)保存起來以備以后使用。該方法拋出ServletException異常。過濾器API7.1.2doFilter()是實現(xiàn)過濾的方法。如果客戶請求的資源與該過濾器關(guān)聯(lián),容器將調(diào)用該方法,格式如下:publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException;該方法執(zhí)行過濾功能,對請求進(jìn)行處理或者將請求轉(zhuǎn)發(fā)到下一個組件或者直接向客戶返回響應(yīng)。注意,request和response參數(shù)被分別聲明為ServletRequest和ServletResponse的類型。因此,過濾器并不只限于處理HTTP請求。如果過濾器用在使用HTTP協(xié)議的Web應(yīng)用程序中,這些變量就分別指HttpServletRequest和HttpServletResponse類型的對象。在使用它們之前應(yīng)把這些參數(shù)轉(zhuǎn)換為相應(yīng)的HTTP類型。過濾器API7.1.2destroy()是容器在過濾器對象上調(diào)用的最后一個方法,聲明格式為:publicvoiddestroy();該方法給過濾器對象一個釋放其所獲得資源的機(jī)會,在結(jié)束服務(wù)之前執(zhí)行一些清理工作。過濾器API7.1.22.FilterConfig接口FilterConfig對象是過濾器配置對象,通過該對象可以獲得過濾器名、過濾器運(yùn)行的上下文對象以及過濾器的初始化參數(shù)。它聲明了如下4個方法。publicStringgetFilterName():返回過濾器名。publicServletContextgetServletContext():返回ServletContext對象。publicStringgetInitParameter(Stringname):返回過濾器初始化參數(shù)值。publicEnumerationgetInitParameterNames():返回參數(shù)名的一個枚舉。容器提供了FilterConfig接口的一個具體實現(xiàn)類,容器創(chuàng)建該類的一個實例、使用初始化參數(shù)值對它初始化,然后將它作為一個參數(shù)傳遞給過濾器的init()。過濾器API7.1.23.FilterChain接口FilterChain接口只有一個方法,如下所示。publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)throwsIOException,ServletException在Filter對象的doFilter()中調(diào)用該方法使過濾器繼續(xù)執(zhí)行,它將控制轉(zhuǎn)到過濾器鏈的下一個過濾器或?qū)嶋H的資源。容器提供了該接口的一個實現(xiàn)并將它的一個實例作為參數(shù)傳遞給Filter接口的doFilter()。在doFilter()內(nèi),可以使用該接口將請求傳遞給鏈中的下一個組件,它可能是另一個過濾器或?qū)嶋H的資源。該方法的兩個參數(shù)將被鏈中下一個過濾器的doFilter()或Servlet的service()接收。過濾器API7.1.24.GenericFilter和HttpFilter類GenericFilter抽象類實現(xiàn)了FilterConfig接口的方法和Filter接口的init()方法。HttpFilter抽象類擴(kuò)展了GenericFilter類,實現(xiàn)了doFilter()方法。voiddoFilter(HttpServletRequestrequest,HttpServletResponseresponse,FilterChainchain)throwsIOException,ServletException;HttpFilter主要用來開發(fā)針對HTTP協(xié)議的過濾器。我們編寫的過濾器類通常繼承HttpFilter類。簡單的編碼過濾器7.1.3在本書前面的例子中看到,由于表單數(shù)據(jù)傳輸默認(rèn)使用ISO-8859-1編碼,這種編碼不能正確解析中文,我們通過將請求對象的字符編碼和響應(yīng)的內(nèi)容類型都設(shè)置為UTF-8或者在程序中將從客戶端讀取的中文以編碼的方式進(jìn)行轉(zhuǎn)換,從而正確顯示中文。下面通過一個簡單的編碼過濾器實現(xiàn)編碼轉(zhuǎn)換,這個過濾器攔截所有的請求并將請求參數(shù)編碼轉(zhuǎn)換為UTF-8,從而解決中文亂碼問題。程序聲明的EncodingFilter類繼承了HttpFilter類,覆蓋了其中的init()和doFilter()方法。EncodingFilter.java清單7.1@WebFilter(filterName="EncodingFilter",urlPatterns={"/*"},initParams={@WebInitParam(name="encoding",value="UTF-8")})publicclassEncodingFilterextendsHttpFilter{ protectedStringencoding=null; protectedFilterConfigconfig; @Overridepublicvoidinit(FilterConfigfilterConfig)throwsServletException{ this.config=filterConfig; //返回過濾器的初始化參數(shù) this.encoding=filterConfig.getInitParameter("encoding");

}@OverridepublicvoiddoFilter(ServletRequestrequest,

ServletResponseresponse,FilterChainchain)

throwsIOException,ServletException{if(request.getCharacterEncoding()==null){ //得到指定的編碼 Stringencode=getEncoding(); if(encode!=null){ //設(shè)置request和response的字符編碼request.setCharacterEncoding(encode);

response.setCharacterEncoding(encode); }}chain.doFilter(request,response);}protectedStringgetEncoding(){ returnencoding;}@Overridepublicvoiddestroy(){}程序在init()方法中通過FilterConfig對象獲得過濾器初始化參數(shù)encoding的值“UTF-8”,然后在doFilter()中將請求和響應(yīng)對象的編碼都設(shè)置為參數(shù)指定的編碼。簡單的編碼過濾器7.1.3要使過濾器起作用必須配置過濾器。對支持Servlet3.0規(guī)范的容器,可以使用注解或部署描述文件的<filter>元素兩種方法配置過濾器。本程序使用的是注解配置過濾器,如下所示。@WebFilter(filterName="EncodingFilter",urlPatterns={"/*"},initParams={@WebInitParam(name="encoding",value="UTF-8")})有了該過濾器,對用戶的任何請求都將其請求和響應(yīng)編碼設(shè)置為UTF-8,這樣對含有中文的請求參數(shù)就不會出現(xiàn)亂碼的情況。讀者可通過2.5節(jié)的程序測試過濾器的作用。@WebFilter注解7.1.4@WebFilter注解用于將一個類聲明為過濾器,該注解在部署時被容器處理,容器根據(jù)具體的配置將相應(yīng)的類部署為過濾器。表7-2給出該注解包含的常用屬性。屬性名類型說

明filterNameString指定過濾器的名稱,等價于web.xml中的<filter-name>元素。如果沒有顯式指定,則使用Filter的完全限定名作為名稱valueString[]指定一組過濾器的URL匹配模式,該元素等價于web.xml文件中的<url-pattern>元素。等價于urlPatterns屬性。dispatcherTypesDispatcherType指定過濾器的轉(zhuǎn)發(fā)類型。具體取值包括:ASYNC、ERROR、FORWARD、INCLUDE和REQUESTinitParamsWebInitParam[]指定一組過濾器初始化參數(shù),等價于<init-param>元素dispalyNameString指定該過濾器的顯示名稱,等價于<display-name>元素@WebFilter注解7.1.4

上表中所有屬性均為可選屬性,但是value、urlPatterns、servletNames三者必須至少包含一個,且value和urlPatterns不能共存,如果同時指定,通常忽略value的取值。

過濾器接口Filter與Servlet非常相似,它們具有類似的生命周期行為,區(qū)別只是Filter的doFilter()中多了一個FilterChain的參數(shù),通過該參數(shù)可以控制是否放行用戶請求。

像Servlet一樣,F(xiàn)ilter也可以具有初始化參數(shù),這些參數(shù)可以通過@WebFilter注解或部署描述文件定義。在過濾器中獲得初始化參數(shù)使用FilterConfig實例的getInitParameter()。在web.xml中配置過濾器7.1.5

還可以使用部署描述文件web.xml配置過濾器類并把請求URL映射到該過濾器上。配置過濾器要用下面兩個元素:<filter>和<filter-mapping>。每個<filter>元素向Web應(yīng)用程序引進(jìn)一個過濾器,每個<filter-mapping>元素將一個過濾器與一組請求URI關(guān)聯(lián)。兩個元素都是<web-app>的子元素。1.<filter>元素每個過濾器都需要一個<filter-name>元素和一個<filter-class>元素。其他元素如<description>、<display-name>、<icon>與<init-param>具有通常的含義并且是可選的。下面代碼說明了<filter>元素的使用。<filter><!--指定過濾器名和過濾器類--><filter-name>validatorFilter</filter-name><filter-class>filter.ValidatorFilter</filter-class><init-param><param-name>locale</param-name><param-value>USA</param-value></init-param></filter>定義了一個名為validatorFilter的過濾器,同時為該過濾器定義了一個名為locale的初始化參數(shù)。這樣,在應(yīng)用程序啟動時容器將創(chuàng)建一個filter.ValidatorFilter類的實例。在初始化階段,過濾器將調(diào)用FilterConfig對象的getParameterValue("locale")檢索locale參數(shù)的值。在web.xml中配置過濾器7.1.52.<filter-mapping>元素該元素的作用定義過濾器映射。下面代碼說明了<filter-mapping>元素的使用。<filter-mapping><filter-name>validatorFilter</filter-name><url-pattern>*.jsp</url-pattern></filter-mapping><filter-mapping><filter-name>validatorFilter</filter-name><servlet-name>reportServlet</servlet-name></filter-mapping><filter-name>元素是在<filter>元素中定義的過濾器名,<url-pattern>用來將過濾器應(yīng)用到一組通過URI標(biāo)識的請求,<servlet-name>用來將過濾器應(yīng)用到通過該名標(biāo)識的Servlet提供服務(wù)的所有請求。在使用<servlet-name>情況下,模式匹配遵循與Servlet映射同樣的規(guī)則。在web.xml中配置過濾器7.1.53.配置過濾器鏈在某些情況下,對一個請求可能需要應(yīng)用多個過濾器,這樣的過濾器鏈可以使用多個<filter-mapping>元素配置。當(dāng)容器接收到一個請求,它將查找所有與請求URI匹配的過濾器映射的URL模式,這是過濾器鏈中的第一組過濾器。接下來,它將查找與請求URI匹配的Servlet名,這是過濾器鏈中的第二組過濾器。在這兩組過濾器中,過濾器的順序是它們在DD文件中的順序。<servlet-mapping><servlet-name>FrontController</servlet-name><url-pattern>*.do</url-pattern></servlet-mapping><filter-mapping><filter-name>perfFilter</filter-name><servlet-name>FrontController</servlet-name></filter-mapping><filter-mapping><filter-name>auditFilter</filter-name><url-pattern>*.do</url-pattern></filter-mapping><filter-mapping><filter-name>transformFilter</filter-name><url-pattern>*.do</url-pattern></filter-mapping>如果一個請求URI為/admin/addCustomer.do,將以下面的順序應(yīng)用過濾器:auditFilter、transformFilter、perfFilter。在web.xml中配置過濾器7.1.54.為轉(zhuǎn)發(fā)的請求配置過濾器通常,過濾器只應(yīng)用在直接來自客戶的請求。但從Servlet2.4開始,過濾器還可以應(yīng)用在從組件內(nèi)部轉(zhuǎn)發(fā)的請求上,這包括使用RequestDispatcher的include()和forward()轉(zhuǎn)發(fā)的請求以及對錯誤處理調(diào)用的資源的請求。要為轉(zhuǎn)發(fā)的請求配置過濾器,可以使用<filter-mapping>元素的子元素<dispatcher>實現(xiàn),該元素的取值包括下面4個:REQUEST、INCLUDE、FORWARD和ERROR。REQUEST表示過濾器應(yīng)用在直接來自客戶的請求上。INCLUDE表示過濾器應(yīng)用在與調(diào)用RequestDispatcher的include()匹配的請求。FORWARD表示過濾器應(yīng)用在與調(diào)用RequestDispatcher的forward()匹配的請求。ERROR表示過濾器應(yīng)用于由在發(fā)生錯誤而引起轉(zhuǎn)發(fā)的請求上。在web.xml中配置過濾器7.1.5在<filter-mapping>元素中可以使用多個<dispatcher>元素使過濾器應(yīng)用在多種情況下,例如:<filter-mapping><filter-name>auditFilter</filter-name><url-pattern>*.do</url-pattern><dispatcher>INCLUDE</dispatcher><dispatcher>FORWARD</dispatcher></filter-mapping>上述過濾器映射將只應(yīng)用在從內(nèi)部轉(zhuǎn)發(fā)的且其URL與*.do匹配的請求上,任何直接來自客戶的請求,即使其URL與*.do匹配也將不應(yīng)用auditFilter過濾器。Web監(jiān)聽器7.2Web應(yīng)用程序中的事件主要發(fā)生在三個對象上:ServletContext、HttpSession和ServletRequest對象。

事件的類型主要包括對象的生命周期事件和屬性改變事件。例如,對于ServletContext對象,當(dāng)它初始化和銷毀時會發(fā)生ServletContextEvent事件,當(dāng)在該對象上添加屬性、刪除屬性或替換屬性時會發(fā)生ServletContextAttributeEvent事件。對于會話對象和請求對象也有類似的事件。

為了處理這些事件,Servlet容器采用了監(jiān)聽器模型,即需要實現(xiàn)有關(guān)的監(jiān)聽器接口。在ServletAPI中定義了7個事件類和9個監(jiān)聽器接口,根據(jù)監(jiān)聽器所監(jiān)聽事件的類型和范圍,可以把它們分為三類:ServletContext事件監(jiān)聽器;HttpSession事件監(jiān)聽器;ServletRequest事件監(jiān)聽器。監(jiān)聽ServletContext事件7.2.1在ServletContext對象上可能發(fā)生兩種事件,對這些事件可使用兩個事件監(jiān)聽器接口處理,如表7-3所示。監(jiān)聽對象事件監(jiān)聽器接口ServletContextServletContextEventServletContextListenerServletContextAttributeEventServletContextAttributeListener監(jiān)聽ServletContext事件7.2.11.

處理ServletContextEvent事件該事件是Web應(yīng)用程序生命周期事件,當(dāng)容器對ServletContext對象進(jìn)行初始化或銷毀操作時,將發(fā)生ServletContextEvent事件。要處理這類事件,需實現(xiàn)ServletContextListener接口,該接口定義了如下兩個方法。? publicvoidcontextInitialized(ServletContextEventsce):當(dāng)ServletContext對象初始化時調(diào)用。publicvoidcontextDestroyed(ServletContextEventsce):當(dāng)ServletContext對象銷毀時調(diào)用。上述方法的參數(shù)是一個ServletContextEvent事件類對象,該類只定義了一個方法,如下所示。publicServletContextgetServletContext()該方法返回狀態(tài)發(fā)生改變的ServletContext對象。監(jiān)聽ServletContext事件7.2.12.處理ServletContextAttributeEvent事件當(dāng)ServletContext對象上屬性發(fā)生改變時,如添加屬性、刪除屬性或替換屬性等,將發(fā)生ServletContextAttributeEvent事件,要處理該類事件,需要實現(xiàn)ServletContextAttributeListener接口。該接口定義了如下三個方法。publicvoidattributeAdded(ServletContextAttributeEventsre):當(dāng)在ServletContext對象中添加屬性時調(diào)用該方法。publicvoidattributeRemoved(ServletContextAttributeEventsre):當(dāng)從ServletContext對象中刪除屬性時調(diào)用該方法。publicvoidattributeReplaced(ServletContextAttributeEventsre):當(dāng)在ServletContext對象中替換屬性時調(diào)用該方法。監(jiān)聽ServletContext事件7.2.1上述方法的參數(shù)是ServletContextAttributeEvent類的對象,它是ServletContextEvent類的子類,它定義了下面三個方法。publicServletContextgetServletContext():返回屬性發(fā)生改變的ServletContext對象。publicStringgetName():返回發(fā)生改變的屬性名。publicObjectgetValue():返回發(fā)生改變的屬性值對象。注意,當(dāng)替換屬性時,該方法返回的是替換之前的屬性值。下面程序?qū)崿F(xiàn)當(dāng)Web應(yīng)用啟動時就創(chuàng)建一個數(shù)據(jù)源對象并將它保存在ServletContext對象上,當(dāng)應(yīng)用程序銷毀時將數(shù)據(jù)源對象從ServletContext對象上清除,當(dāng)ServletContext上屬性發(fā)生改變時登記日志。MyContextListener.java清單7.2@WebListener//使用注解注冊監(jiān)聽器publicclassMyContextListenerimplementsServletContextListener,ServletContextAttributeListener{privateServletContextcontext=null;publicvoidcontextInitialized(ServletContextEventsce){

Contextctx=null;DataSourcedataSource=null;context=sce.getServletContext();try{if(ctx==null){ ctx=newInitialContext();}dataSource=(DataSource)ctx.lookup("java:comp/env/jdbc/webstoreDS");

}catch(NamingExceptionne){ context.log("發(fā)生異常:"+ne);}

context.setAttribute("dataSource",dataSource);//添加屬性 context.log("應(yīng)用程序已啟動:"+LocalTime.now());}publicvoidcontextDestroyed(ServletContextEventsce){context=sce.getServletContext();context.removeAttribute("dataSource"); context.log("應(yīng)用程序已關(guān)閉:"+LocalTime.now());}publicvoidattributeAdded(ServletContextAttributeEventsce){ context=sce.getServletContext(); context.log("添加一個屬性:"+sce.getName()+":"+sce.getValue());}publicvoidattributeRemoved(ServletContextAttributeEventsce){ context=sce.getServletContext(); context.log("刪除一個屬性:"+sce.getName()+":"+sce.getValue());}publicvoidattributeReplaced(ServletContextAttributeEventsce){ context=sce.getServletContext(); context.log("替換一個屬性:"+sce.getName()+":"+sce.getValue());}listenerTest.jsp清單7.3<%@pagecontentType="text/html;charset=UTF-8"%><%@pageimport="java.sql.*,javax.sql.*"%><%DataSourcedataSource=(DataSource)application.getAttribute("dataSource");Connectionconn=dataSource.getConnection();Statementstmt=conn.createStatement();ResultSetrst=stmt.executeQuery("SELECT*FROMbooks");%>下面的listenerTest.jsp頁面是對監(jiān)聽器的測試,這里使用了監(jiān)聽器對象創(chuàng)建的數(shù)據(jù)源對象。<tableborder="1"><caption>圖書表中信息</caption><tr><td>編號</td><td>圖書名</td><td>作者</td><td>出版社</td><td>價格</td>/tr><%while(rst.next()){%><tr><td><%=rst.getInt(1)%></td><td><%=rst.getString(2)%></td><td><%=rst.getString(3)%></td><td><%=rst.getString(4)%></td>

<td><%=rst.getFloat(5)%></td>

</tr><%}%></table>監(jiān)聽ServletContext事件7.2.1在該頁面中首先通過隱含對象application的getAttribute()得到數(shù)據(jù)源對象,然后創(chuàng)建ResultSet對象訪問數(shù)據(jù)庫。該頁面運(yùn)行結(jié)果如圖7-3所示。監(jiān)聽請求事件7.2.2在ServletRequest對象上可能發(fā)生兩種事件,對這些事件使用兩個事件監(jiān)聽器處理,如表7-4所示。1.處理ServletRequestEvent事件ServletRequestEvent事件是請求對象生命周期事件,當(dāng)一個請求對象初始化或銷毀時將發(fā)生該事件,處理該類事件需要使用ServletRequestListener接口,該接口定義了如下兩個方法:監(jiān)聽對象事件監(jiān)聽器接口ServletRequestServletRequestEventServletRequestListenerServletRequestAttributeEventServletRequestAttributeListenerpublicvoidrequestInitialized(ServletRequestEventsce):當(dāng)請求對象初始化時調(diào)用。publicvoidrequestDestroyed(ServletRequestEventsce):當(dāng)請求對象銷毀時調(diào)用。上述方法的參數(shù)是ServletRequestEvent類對象,該類定義了下面兩個方法:publicServletContextgetServletContext():返回發(fā)生該事件的ServletContext對象。publicServletRequestgetServletRequest():返回發(fā)生該事件的ServletRequest對象。監(jiān)聽請求事件7.2.22.處理ServletRequestAttributeEvent事件在請求對象上添加、刪除和替換屬性時將發(fā)生ServletRequestAttributeEvent事件,處理該類事件需要使用ServletRequestAttributeListener接口,它定義了如下三個方法。在上述方法中傳遞的參數(shù)為ServletRequestAttributeEvent類的對象,該類定義了下面兩個方法。publicvoidattributeAdded(ServletRequestAttributeEventsrc):在請求中添加屬性時調(diào)用方法。publicvoidattributeRemoved(ServletRequestAttributeEventsrc):從請求中刪除屬性時調(diào)用方法。publicvoidattributeReplaced(ServletRequestAttributeEventsrc):在請求中替換屬性時調(diào)用方法。publicStringgetName():返回在請求對象上添加、刪除或替換的屬性名。publicObjectgetValue():返回在請求對象上添加、刪除或替換的屬性值。注意,當(dāng)替換屬性時,該方法返回的是替換之前的屬性值。MyRequestListener.java清單7.4@WebListenerpublicclassMyRequestListener

implementsServletRequestListener{privateintcount=0;publicvoidrequestInitialized(ServletRequestEventre){HttpServletRequestrequest=(HttpServletRequest)re.getServletRequest();if(request.getRequestURI().endsWith("onlineCount.jsp")){count++;

re.getServletContext().setAttribute("count",newInteger(count));}}publicvoidrequestDestroyed(ServletRequestEventre){}}onlineCount.jsp清單7.5<%@pagecontentType="text/html;charset=UTF-8"%><html><head><title>請求監(jiān)聽器示例</title></head><body>歡迎您,您的IP地址是${pageContext.request.remoteAddr}<br><p>自應(yīng)用程序啟動以來,該頁面被訪問了<fontcolor="blue">${applicationScope.count}</font>次<br></body></html>監(jiān)聽請求事件7.2.2監(jiān)聽會話事件7.2.3在HttpSession對象上可能發(fā)生兩種事件,對這些事件可使用四個事件監(jiān)聽器處理,這些類和接口如表7-5所示。監(jiān)聽對象事件監(jiān)聽器接口HttpSessionHttpSessionEventHttpSessionListenerHttpSessionActivationListenerHttpSessionBindingEventHttpSessionAttributeListenerHttpSessionBindingListener監(jiān)聽會話事件7.2.31.處理HttpSessionEvent事件HttpSessionEvent事件是會話對象生命周期事件,當(dāng)一個會話對象被創(chuàng)建和銷毀時發(fā)生該事件,處理該事件應(yīng)該使用HttpSessionListener接口,該接口定義了兩個方法:上述方法的參數(shù)是一個HttpSessionEvent類對象,該類中只定義了一個getSession(),它返回狀態(tài)發(fā)生改變的會話對象,格式如下。publicvoidsessionCreated(HttpSessionEventse):當(dāng)會話創(chuàng)建時調(diào)用該方法。publicvoidsessionDestroyed(HttpSessionEventse):當(dāng)會話銷毀時調(diào)用該方法。publicHttpSessiongetSession()監(jiān)聽會話事件7.2.32.處理會話屬性事件當(dāng)在會話對象上添加屬性、刪除屬性、替換屬性時將發(fā)生HttpSessionBindingEvent事件,處理該事件需使用HttpSessionAttributeListener接口,該接口定義了下面三個方法:HttpSessionBindingEvent類中定義了下面三個方法。publicvoidattributeAdded(HttpSessionBindingEventse):當(dāng)在會話對象上添加屬性時調(diào)用該方法。publicvoidattributeRemoved(HttpSessionBindingEventse):當(dāng)從會話對象上刪除屬性時調(diào)用該方法。publicvoidattributeReplaced(HttpSessionBindingEventse):當(dāng)替換會話對象上的屬性時調(diào)用該方法。publicHttpSessiongetSession():返回發(fā)生改變的會話對象。publicStringgetName():返回綁定到會話對象或從會話對象解除綁定的屬性名。publicObjectgetValue():返回在會話對象上添加、刪除或替換的屬性值。MySessionListener.java清單7.6@WebListenerpublicclassMySessionListenerimplementsHttpSessionListener{privateServletContextcontext=null;publicvoidsessionCreated(HttpSessionEventse){HttpSessionsession=se.getSession();context=session.getServletContext();ArrayList<HttpSession>sessionList=(ArrayList<HttpSession>)context.getAttribute("sessionList");if(sessionList==null){sessionList=newArrayList<HttpSession>(); context.setAttribute("sessionList",sessionList);}else{sessionList.add(session);}context.log("創(chuàng)建一個會話:"+session.getId()); }publicvoidsessionDestroyed(HttpSessionEventse){ HttpSessionsession=se.getSession();context=session.getServletContext();ArrayList<HttpSession>sessionList=(ArrayList<HttpSession>)context.getAttribute("sessionList");sessionList.remove(session);context.log("銷毀一個會話:"+session.getId());}}sessionDisplay.jsp清單7.7<head><title>會話監(jiān)聽器示例</title></head><body><tableborder="1"><c:forEachvar="s"items="${applicationScope.sessionList}"><tr><td><c:outvalue="${s.id}"/></td>

<td><c:outvalue="${s.creationTime}"/></td></tr></c:forEach></table></body>下面的JSP頁面通過applicationScope訪問存有會話對象的ArrayList,然后顯示出每個會話對象的信息。監(jiān)聽會話事件7.2.33.處理會話屬性綁定事件當(dāng)一個對象綁定到會話對象或從會話對象中解除綁定時發(fā)生HttpSessionBindingEvent事件,應(yīng)該使用HttpSessionBindingListener接口來處理這類事件,該接口定義的方法有:下面定義的User類實現(xiàn)了HttpSessionBindingListener接口。當(dāng)將該類的一個對象綁定到會話對象上時,容器將調(diào)用valueBound(),當(dāng)從會話對象上刪除該類的對象時,容器將調(diào)用valueUnbound(),這里向日志文件寫入有關(guān)信息。publicvoidvalueBound(HttpSessionBindingEventevent):當(dāng)對象綁定到一個會話上時調(diào)用該方法。publicvoidvalueUnbound(HttpSessionBindingEventevent):當(dāng)對象從一個會話上解除綁定時調(diào)用該方法。User.java清單7.8publicclassUserimplementsHttpSessionBindingListener{publicStringusername="";publicStringpassword="";publicUser(){}publicUser(Stringusername,Stringpassword){this.username=username;this.password=password;}publicvoidvalueBound(HttpSessionBindingEvente){HttpSessionsession=e.getSession();session.getServletContext().log("用戶名:"+username+",口令:"+password+"登錄系統(tǒng).");}publicvoidvalueUnbound(HttpSessionBindingEvente){HttpSessionsession=e.getSession();session.getServletContext().log("用戶名:"+username+"口令:"+password+"退出系統(tǒng).");}}LoginServlet.java清單7.9@WebServlet("/login.do")publicclassLoginServletextendsHttpServlet{publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException,ServletException{response.setContentType("text/html;charset=UTF-8");PrintWriterout=response.getWriter();Stringusername=request.getParameter("username");Stringpassword=request.getParameter("password");DataSourcedataSource=(DataSource)getServletContext().getAttribute("dataSource");下面是一個Servlet,它接受登錄用戶的用戶名和口令,然后創(chuàng)建一個User對象并將其綁定到會話對象上。try{Connectionconn=dataSource.getConnection();Stringsql="SELECT*FROMusersWHEREusername=?ANDpassword=?";PreparedStatementpstmt=conn.prepareStatement(sql);pstmt.setString(1,username);pstmt.setString(2,password);ResultSetrst=pstmt.executeQuery();booleanvalid=rst.next();if(valid){Uservaliduser=newUser(username,password);request.getSession().setAttribute("user",validuser);out.println("歡迎您,"+username);}else{response.sendRedirect("login.jsp");}}catch(Exceptione){事件監(jiān)聽器的注冊7.2.4前面的例子中,使用@WebListener注解來注冊監(jiān)聽器。事件監(jiān)聽器也可以在web.xml文件中使用<listener>元素注冊。該元素只包含一個<listener-class>元素,用來指定實現(xiàn)了監(jiān)聽器接口的完整的類名。下面代碼給出了如何注冊MyContextListener和MySessionListener兩個監(jiān)聽器。。<listener><listener-class>com.listener.MyContextListener</listener-class></listener><listener><listener-class>com.listener.MySessionListener</listener-class></listener>在web.xml文件中并沒有指定哪個監(jiān)聽器類處理哪個事件,這是因為當(dāng)容器需要處理某種事件時,它能夠找到有關(guān)的類和方法。容器實例化指定的類并檢查類實現(xiàn)的全部接口。Servlet的多線程問題7.3在Web應(yīng)用程序中,一個Servlet在一個時刻可能被多個用戶同時訪問。這時Web容器將為每個用戶創(chuàng)建一個線程。如果Servlet不涉及共享資源的問題,不必關(guān)心多線程問題。但如果Servlet需要共享資源,需要保證Servlet是線程安全的。下面首先來看一個非線程安全的Servlet。該Servlet從客戶接受兩個整數(shù),然后計算它們的和或差。該程序?qū)⒂嬎憬Y(jié)果存放在變量result中,它根據(jù)用戶在頁面中單擊的是“相加”按鈕或“相減”按鈕決定求和還是求差。

注意,result被聲明為一個成員變量。為了演示多個用戶請求時出現(xiàn)的問題,程序中調(diào)用Thread類的sleep()在計算出result后睡眠一段時間(假設(shè)2秒種),睡眠的時間通過Servlet初始化參數(shù)sleepTime得到。getNumber()實現(xiàn)字符串到int數(shù)據(jù)的轉(zhuǎn)換。最后輸出計算的結(jié)果。CalculatorServlet.java清單7.10@WebServlet(

name="calculatorServlet",value={"/calculator.do"}, initParams={

@WebInitParam(name="sleepTime",value="2000") })publicclassCalculatorServletextendsHttpServlet{privateintresult;privateintsleepTime;publicvoidinit(){ Stringsleep_time=getInitParameter("sleepTime"); sleepTime=getNumber(sleep_time);}publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException,ServletException{reque

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論