《Java Web程序設計任務教程》Servlet高級 課件_第1頁
《Java Web程序設計任務教程》Servlet高級 課件_第2頁
《Java Web程序設計任務教程》Servlet高級 課件_第3頁
《Java Web程序設計任務教程》Servlet高級 課件_第4頁
《Java Web程序設計任務教程》Servlet高級 課件_第5頁
已閱讀5頁,還剩130頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

Servlet高級《Java

Web程序設計任務教程(第2版)》第9章學習目標/Target了解Filter及其相關API熟悉Filter的生命周期

掌握Filter的實現(xiàn)

掌握Filter的映射與過濾器鏈的使用學習目標/Target熟悉Listener及相關API熟悉Servlet3.0新特性

掌握文件上傳和下載章節(jié)概述/SummaryServlet規(guī)范有三個高級特性,分別是Filter、Listener和文件的上傳下載。Filter用于修改request、response對象,Listener用于監(jiān)聽context、session、request事件。善用Servlet規(guī)范中的這三個高級特性能夠輕松地解決一些特殊問題。本章將針對過濾器Filter、監(jiān)聽器Listener和文件的上傳下載進行詳細講解。目錄/Contents010203FilterListenerServlet3.0新特性04文件的上傳和下載Filter9.19.1.1什么是Filter先定一個小目標!

先定一個小目標!了解Filter的概念,能夠知道Filter用于做什么在Servlet高級特性中,F(xiàn)ilter被稱為過濾器,F(xiàn)ilter基本功能就是對Servlet容器調(diào)用Servlet的過程進行攔截,它位于客戶端和處理程序之間,能夠對請求和響應進行檢查和修改。Filter就好比現(xiàn)實中的污水凈化設備,專門用于過濾污水雜質(zhì)。Filter在Web應用中的攔截過程如下圖所示。Filter的概念9.1.1什么是Filter上圖中展示了Filter在Web應用中的攔截過程,當客戶端對服務器資源發(fā)出請求時,服務器會根據(jù)過濾規(guī)則進行檢查,如果客戶的請求滿足過濾規(guī)則,則對客戶請求進行攔截,對請求頭和請求數(shù)據(jù)進行檢查或修改,并依次通過過濾器鏈,最后把過濾之后的請求交給處理程序。請求信息在過濾器鏈中可以被修改,也可以根據(jù)客戶端的請求條件不將請求發(fā)往處理程序。Filter在Web應用中的攔截9.1.1什么是FilterFilter除了可以實現(xiàn)攔截功能,還可以提高程序的性能,在Web開發(fā)時,不同的Web資源中的過濾操作可以放在同一個Filter中完成,這樣可以不用多次編寫重復代碼,從而提高了程序的性能。Filter的作用9.1.1什么是Filter9.1.2Filter相關API先定一個小目標!

先定一個小目標!掌握Filter的3個接口:Filter接口、FilterConfig接口和FilterChain接口Filter中包含了3個接口,分別是Filter接口、FilterConfig接口和FilterChain接口,它們都位于javax.servlet包中。Filter中的3個接口9.1.2Filter相關APIFilter接口9.1.2Filter相關API方法聲明功能描述init(FilterConfigfilterConfig)init()方法是Filter的初始化方法,創(chuàng)建Filter實例后將調(diào)用init()方法。該方法的參數(shù)filterConfig用于讀取Filter的初始化參數(shù)。doFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)doFilter()方法完成實際的過濾操作,當客戶的請求滿足過濾規(guī)則時,Servlet容器將調(diào)用過濾器的doFilter()方法完成實際的過濾操作。doFilter()方法有多個參數(shù),其中,參數(shù)request和response為Web服務器或Filter鏈中的上一個Filter傳遞過來的請求和響應對象;參數(shù)chain代表當前Filter鏈的對象。destroy()該方法用于釋放被Filter對象打開的資源,例如關閉數(shù)據(jù)庫和

IO流。destroy()方法在Web服務器釋放Filter對象之前被調(diào)用。FilterConfig接口9.1.2Filter相關API方法聲明功能描述StringgetFilterName()返回Filter的名稱ServletContextgetServletContext()返回FilterConfig對象中封裝的ServletContext對象StringgetInitParameter(Stringname)返回名為name的初始化參數(shù)值EnumerationgetInitParameterNames()返回Filter所有初始化參數(shù)的枚舉FilterConfig接口用于封裝Filter的配置信息,在Filter初始化時,服務器將FilterConfig對象作為參數(shù)傳遞給Filter對象的初始化方法。FilterChain接口9.1.2Filter相關APIFilterChain接口的doFilter()方法用于調(diào)用過濾器鏈中的下一個過濾器,如果這個過濾器是鏈上的最后一個過濾器,則將請求提交給處理程序或將響應發(fā)給客戶端。9.1.3Filter的生命周期先定一個小目標!

先定一個小目標!熟悉Filter的生命周期的創(chuàng)建、執(zhí)行和銷毀三個階段Filter的生命周期Filter的生命周期指的是一個Filter對象從創(chuàng)建到執(zhí)行再到銷毀的過程。Filter接口中的三個方法就是管理Filter對象生命周期的方法。Filter的生命周期可分為創(chuàng)建、執(zhí)行、銷毀三個階段。9.1.3Filter的生命周期創(chuàng)建階段Web服務器啟動的時候會創(chuàng)建Filter實例對象,并調(diào)用init()方法,完成對象的初始化。需要注意的是,在一次完整的請求當中,F(xiàn)ilter對象只會創(chuàng)建一次,init()方法也只會執(zhí)行一次。9.1.3Filter的生命周期執(zhí)行階段當客戶端請求目標資源時,服務器會篩選出符合映射條件的Filter,并按照類名的的先后順序依次執(zhí)行doFilter()方法。例如MyFilter01優(yōu)先MyFilter02執(zhí)行。在一次完整的請求當中,doFilter()方法可以執(zhí)行多次。9.1.3Filter的生命周期銷毀階段服務器關閉時,Web服務器調(diào)用destroy()方法銷毀Filter對象。9.1.3Filter的生命周期9.1.4實現(xiàn)第一個Filter先定一個小目標!

先定一個小目標!掌握Filter如何對Servlet程序的調(diào)用過程進行攔截STEP01下面分步驟實現(xiàn)一個Filter,演示Filter如何對Servlet程序的調(diào)用過程進行攔截。首先在IDEA中創(chuàng)建一個名為chapter09的Web項目,然后在該項目的src目錄下創(chuàng)建一個名為cn.itcast.chapter09.filter包,最后在該包下創(chuàng)建一個名為MyServlet的Servlet類,用于在瀏覽器中輸出“HelloMyServlet”。MyServlet類的實現(xiàn)如下所示。@WebServlet(name="MyServlet",urlPatterns="/MyServlet")publicclassMyServletextendsHttpServlet{ publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse) throwsServletException,IOException{

response.getWriter().println("HelloMyServlet"); } publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse) throwsServletException,IOException{ doGet(request,response); }}9.1.4實現(xiàn)第一個FilterSTEP02在IDEA中使用Tomcat啟動chapter09項目,在瀏覽器的地址欄中訪問“http://localhost:8080/chapter09/MyServlet”,可以看到瀏覽器成功訪問到了MyServlet程序,具體如下圖所示。9.1.4實現(xiàn)第一個FilterSTEP03在cn.itcast.chapter09.filter包中創(chuàng)建一個名為MyFilter的Filter類,用于攔截MyServlet程序。MyFilter的實現(xiàn)如下所示。@WebFilter(filterName="MyFilter",urlPatterns="/MyServlet")publicclassMyFilterimplementsFilter{ publicvoidinit(FilterConfigfConfig)throwsServletException{ //過濾器對象在初始化時調(diào)用,可以配置一些初始化參數(shù) } publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse, FilterChainchain)throwsIOException,ServletException{ //用于攔截用戶的請求,如果和當前過濾器的攔截路徑匹配,該方法會被調(diào)用 PrintWriterout=response.getWriter(); out.write("HelloMyFilter"); } publicvoiddestroy(){ //過濾器對象在銷毀時自動調(diào)用,釋放資源 }}9.1.4實現(xiàn)第一個Filter@WebFilter注解@WebFilter注解的屬性filterName用于設置Filter的名稱,urlPattern屬性用于匹配用戶請求的URL,例如“/MyServlet”,表示過濾器MyFilter會攔截發(fā)送到/MyServlet資源的請求。這個URL還可以使用通配符“*”表示,例如,“*.do”匹配所有以“.do”結尾的Servlet路徑。9.1.4實現(xiàn)第一個FilterSTEP04在IDEA中重新啟動Tomcat服務器,在瀏覽器的地址欄中訪問“http://localhost:8080/chapter09/MyServlet”,瀏覽器窗口顯示結果如下圖所示。9.1.4實現(xiàn)第一個Filter@WebFilter注解的常用屬性9.1.4實現(xiàn)第一個Filter屬性名類型描述filterNameString指定過濾器的名稱。默認是過濾器類的名稱。urlPatternsString[]指定一組過濾器的URL匹配模式。valueString[]該屬性等價于urlPatterns屬性。urlPatterns和value屬性不能同時使用。servletNamesString[]指定過濾器將應用于哪些Servlet。取值是@WebServlet中的name屬性的取值。dispatcherTypesDispatcherType指定過濾器的轉發(fā)模式。具體取值包括:ERROR、FORWARD、INCLUDE、REQUEST。initParamsWebInitParam[]指定過濾器的一組初始化參數(shù)。9.1.5Filter映射先定一個小目標!

先定一個小目標!掌握Filter中使用通配符“*”攔截用戶所有請求以及攔截不同訪問方式的請求Filter映射Filter攔截的資源需要在Filter實現(xiàn)類中使用注解@WebFilter進行配置,這些配置信息就是Filter映射。Filter的映射方式可分為兩種:使用通配符“*”攔截用戶所有請求和攔截不同訪問方式的請求。9.1.5Filter映射STEP01如果想讓過濾器攔截用戶所有請求,可以使用通配符“*”實現(xiàn),下面修改MyFilter.java的代碼以實現(xiàn)攔截用戶所有請求的功能,修改后的代碼如下所示。@WebFilter(filterName="MyFilter",urlPatterns="/MyServlet")publicclassMyFilterimplementsFilter{ publicvoidinit(FilterConfigfConfig)throwsServletException{ //過濾器對象在初始化時調(diào)用,可以配置一些初始化參數(shù) } publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse, FilterChainchain)throwsIOException,ServletException{ //用于攔截用戶的請求,如果和當前過濾器的攔截路徑匹配,該方法會被調(diào)用 PrintWriterout=response.getWriter(); out.write("HelloMyFilter"); } publicvoiddestroy(){ //過濾器對象在銷毀時自動調(diào)用,釋放資源 }}9.1.5Filter映射攔截不同訪問方式的請求9.1.5Filter映射@WebFilter注解有一個特殊的屬性dispatcherTypes,它可以指定過濾器的轉發(fā)模式,dispatcherTypes屬性有4個常用值,REQUEST、INCLUDE、FORWARD和ERROR。REQUEST9.1.5Filter映射過濾器設置dispatcherTypes屬性值為REQUEST時,如果用戶通過RequestDispatcher對象的include()方法或forward()方法訪問目標資源,那么過濾器不會被調(diào)用。除此之外,該過濾器會被調(diào)用。INCLUDE9.1.5Filter映射過濾器設置dispatcherTypes屬性值為INCLUDE時,如果用戶通過RequestDispatcher對象的include()方法訪問目標資源,那么過濾器將被調(diào)用。除此之外,該過濾器不會被調(diào)用。FORWARD9.1.5Filter映射過濾器設置dispatcherTypes屬性值為FORWARD時,如果通過RequestDispatcher對象的forward()方法訪問目標資源,那么過濾器將被調(diào)用。除此之外,該過濾器不會被調(diào)用。ERROR9.1.5Filter映射過濾器設置dispatcherTypes屬性值為ERROR時,如果通過聲明式異常處理機制調(diào)用目標資源,那么過濾器將被調(diào)用。除此之外,過濾器不會被調(diào)用。STEP01下面分步驟實現(xiàn)一個Filter,演示Filter如何對Servlet程序的調(diào)用過程進行攔截。首先在IDEA接下來以FORWARD值為例,分步驟演示指定轉發(fā)模式的Filter對轉發(fā)請求的攔截效果。在chapter09項目的cn.itcast.chapter09.filter包中,創(chuàng)建一個名為ForwardServlet的Servlet類,用于將請求轉發(fā)給first.jsp頁面。ForwardServlet類的實現(xiàn)如下所示。@WebServlet(name="ForwardServlet",urlPatterns="/ForwardServlet")publicclassForwardServletextendsHttpServlet{ publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse) throwsServletException,IOException{ request.getRequestDispatcher("/first.jsp").forward(request,response); } publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse) throwsServletException,IOException{ doGet(request,response); }}9.1.5Filter映射STEP02在chapter09項目的web目錄中創(chuàng)建一個first.jsp頁面,用于輸出內(nèi)容。first.jsp頁面的實現(xiàn)如下所示。<%@pagelanguage="java"contentType="text/html;charset=utf-8" pageEncoding="utf-8"%><html><head></head><body> first.jsp</body></html>9.1.5Filter映射STEP03在cn.itcast.chapter09.filter包中,創(chuàng)建一個過濾器ForwardFilter.java,專門用于對first.jsp頁面的請求進行攔截。ForwardFilter.java的實現(xiàn)如下所示。@WebFilter(filterName="ForwardFilter",urlPatterns="/first.jsp")publicclassForwardFilterimplementsFilter{ publicvoidinit(FilterConfigfConfig)throwsServletException{ //過濾器對象在初始化時調(diào)用,可以配置一些初始化參數(shù)} publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse, FilterChainchain)throwsIOException,ServletException{ //用于攔截用戶的請求,如果和當前過濾器的攔截路徑匹配,該方法會被調(diào)用 PrintWriterout=response.getWriter(); out.write("HelloFilterTest"); } publicvoiddestroy(){ //過濾器對象在銷毀時自動調(diào)用,釋放資源 }}9.1.5Filter映射STEP04在IDEA中啟動Tomcat服務器,在瀏覽器中輸入地址“http://localhost:8080/chapter09/ForwardServlet”訪問ForwardServlet,瀏覽器顯示的結果如下所示。9.1.5Filter映射STEP05如果要攔截ForwardServlet類通過forward()方法轉發(fā)到first.jsp頁面的請求,可以在@WebFilter注解中設置dispatcherTypes屬性值為FORWARD。修改ForwardFilter.java中第5行代碼,在@WebFilter注解中設置dispatcherTypes屬性值為FORWARD,具體代碼如下。@WebFilter(filterName="ForwardFilter",urlPatterns="/first.jsp",dispatcherTypes=DispatcherType.FORWARD)9.1.5Filter映射STEP06在IDEA中重新啟動Tomcat服務器,在瀏覽器的地址欄中再次輸入地址“http://localhost:8080/chapter09/ForwardServlet”訪問ForwardServlet,瀏覽器顯示的結果如下圖所示。9.1.5Filter映射9.1.6Filter鏈先定一個小目標!

先定一個小目標!掌握Filter中的Filter鏈的攔截過程Filter鏈的攔截在一個Web應用程序中可以注冊多個Filter,每個Filter都可以針對某一個URL的請求進行攔截。如果多個Filter都對同一個URL的請求進行攔截,那么這些Filter就組成一個Filter鏈。Filter鏈使用FilterChain對象表示,F(xiàn)ilterChain對象提供了一個doFilter()方法,該方法的作用是讓Filter鏈上的當前過濾器放行,使請求進入下一個Filter。9.1.6Filter鏈Filter鏈的攔截過程圖9.1.6Filter鏈當瀏覽器訪問Web服務器中的資源時需要經(jīng)過兩個過濾器Filter1和Filter2,首先Filter1會對這個請求進行攔截,在Filter1過濾器中處理好請求后,通過調(diào)用Filter1的doFilter()方法將請求傳遞給Filter2,F(xiàn)ilter2將用戶請求處理后同樣調(diào)用doFilter()方法,最終將請求發(fā)送給目標資源。當Web服務器對這個請求做出響應時,響應結果也會被過濾器攔截,攔截順序與之前相反,最終響應結果被發(fā)送給客戶端。STEP01下面通過一個案例分步驟演示如何使用Filter鏈攔截MyServlet的同一個請求。在chapter09項目的cn.itcast.chapter09.filter包中新建一個過濾器MyFilter01,具體實現(xiàn)分別如下所示。@WebFilter(filterName="MyFilter01",urlPatterns="/MyServlet")publicclassMyFilter01implementsFilter{ publicvoidinit(FilterConfigfConfig)throwsServletException{ //過濾器對象在初始化時調(diào)用,可以配置一些初始化參數(shù) } publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse, FilterChainchain)throwsIOException,ServletException{ //用于攔截用戶的請求,如果和當前過濾器的攔截路徑匹配,該方法會被調(diào)用 PrintWriterout=response.getWriter(); out.println("HelloMyFilter01"); chain.doFilter(request,response); } publicvoiddestroy(){ //過濾器對象在銷毀時自動調(diào)用,釋放資源 }}9.1.6Filter鏈STEP02下面通過一個案例分步驟演示如何使用Filter鏈攔截MyServlet的同一個請求。在chapter09項目的cn.itcast.chapter09.filter包中新建一個過濾器MyFilter02,具體實現(xiàn)分別如下所示。@WebFilter(filterName="MyFilter02",urlPatterns="/MyServlet")publicclassMyFilter02implementsFilter{ publicvoidinit(FilterConfigfConfig)throwsServletException{ //過濾器對象在初始化時調(diào)用,可以配置一些初始化參數(shù) } publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse, FilterChainchain)throwsIOException,ServletException{ //用于攔截用戶的請求,如果和當前過濾器的攔截路徑匹配,該方法會被調(diào)用 PrintWriterout=response.getWriter(); out.println("MyFilter02Before"); chain.doFilter(request,response); out.println("MyFilter02After"); } publicvoiddestroy(){ //過濾器對象在銷毀時自動調(diào)用,釋放資源 }}9.1.6Filter鏈STEP03在IDEA中重新啟動Tomcat服務器,在瀏覽器地址欄中輸入“http://localhost:8080/chapter09/MyServlet”訪問MyServlet類,瀏覽器窗口中的顯示結果如下圖所示。9.1.6Filter鏈Filter鏈的攔截需要注意的是,Servlet3.0新增了@WebFilter注解,當使用注解配置多個Filter時,用戶無法控制它們的執(zhí)行順序,F(xiàn)ilter的執(zhí)行順序是按照Filter的類名控制的,按自然排序的規(guī)則。例如,MyFilter01會比MyFilter02優(yōu)先執(zhí)行。9.1.6Filter鏈先定一個小目標!

先定一個小目標!通過Filter和Cookie的應用,實現(xiàn)自動登錄任務:Filter在Cookie自動登錄中的使用任務:Filter在Cookie自動登錄中的使用

使用Cookie可以實現(xiàn)用戶自動登錄,但當客戶端訪問服務器的Servlet時,Servlet需要對所有用戶的Cookie信息進行校驗,這樣勢必會導致在Servlet程序中編寫大量重復的代碼。通過注冊過濾器完成對用戶Cookie信息的校驗,可以解決這樣的問題。由于Filter可以對服務器的所有請求進行攔截,因此,可以通過Filter攔截用戶的自動登錄請求,在Filter中對用戶的Cookie信息進行校驗,一旦請求通過Filter,就相當于用戶信息校驗通過,Servlet程序根據(jù)獲取到的用戶信息,就可以實現(xiàn)自動登錄。

本任務要求使用Filter對Cookie進行攔截并實現(xiàn)自動登錄,并且可以設置指定自動登錄時間為1個月、3個月、半年或一年。任務:Filter在Cookie自動登錄中的使用實現(xiàn)步驟:要實現(xiàn)Filter對Cookie進行攔截并實現(xiàn)自動登錄,需要有以下幾個文件。需要有一個User實體類,用于封裝用戶的信息。需要有一個login.jsp的登錄頁面,在該頁面中編寫一個用戶登錄表單。用戶登錄表單需要填寫用戶名和密碼,以及用戶自動登錄的時間。需要一個登錄成功后的index.jsp頁面。需要編寫兩個Servlet,一個Servlet類用于處理用戶的登錄請求,如果輸入的用戶名和密碼正確,則發(fā)送一個用戶自動登錄的Cookie,并跳轉到首頁,否則提示輸入的用戶名或密碼錯誤,并跳轉至登錄頁面(login.jsp),讓用戶重新登錄;另外一個Servlet類用于攔截用戶登錄的訪問請求,判斷請求中是否包含用戶自動登錄的Cookie,如果包含則獲取Cookie中的用戶名和密碼,并驗證用戶名和密碼是否正確,如果正確,則將用戶的登錄信息封裝到User對象存入Session域中,完成用戶自動登錄。STEP01編寫User類在chapter09項目中創(chuàng)建cn.itcast.chapter09.entity包,在該包中新建User類,用于封裝用戶的信息。User類的實現(xiàn)如下所示。

publicclassUser{ privateStringusername; privateStringpassword; publicStringgetUsername(){ returnusername; } publicvoidsetUsername(Stringusername){ this.username=username; } publicStringgetPassword(){ returnpassword; } publicvoidsetPassword(Stringpassword){ this.password=password; }}

任務:Filter在Cookie自動登錄中的使用STEP02實現(xiàn)登錄頁面和首頁(1)在chapter09項目的web根目錄中,新建login.jsp頁面,在該頁面中編寫一個用戶登錄表單。用戶登錄表單需要填寫用戶名和密碼,以及用戶自動登錄的時間。login.jsp頁面的實現(xiàn)如下所示。<!--下面只展示table標簽的內(nèi)容--><tableborder="1"width="600px"cellpadding="0"cellspacing="0"align="center"> <tr><tdheight="30"align="center">用戶名:</td><td>  

<inputtype="text"name="username"/>${errerMsg}</td></tr> <tr><tdheight="30"align="center">密

碼:</td<td>  

<inputtype="password"name="password"/></td></tr> <tr><tdheight="35"align="center">自動登錄時間</td> <td><inputtype="radio"name="autologin"value="${60*60*24*31}"/>一個月 <inputtype="radio"name="autologin"value="${60*60*24*31*3}"/>三個月 <inputtype="radio"name="autologin"value="${60*60*24*31*6}"/>半年 <inputtype="radio"name="autologin"value="${60*60*24*31*12}"/>一年 </td></tr><tr><tdheight="30"colspan="2"align="center"> <inputtype="submit"value="登錄"/>     <inputtype="reset"value="重置"/></td></tr></table>任務:Filter在Cookie自動登錄中的使用STEP02(2)用戶在chapter09項目的web根目錄中,新建index.jsp頁面,用于顯示用戶的登錄信息,如果沒有用戶登錄,在index.jsp頁面中顯示一個用戶登錄的超鏈接,如果用戶已經(jīng)登錄,在index.jsp頁面中顯示登錄的用戶名,以及一個注銷的超鏈接。index.jsp頁面的實現(xiàn)如下所示。<!--下面只展示body標簽的內(nèi)容--><body> <br/> <center><h3>歡迎光臨</h3> </center> <br/> <br/> <c:choose> <c:whentest="${sessionScope.user==null}"><ahref="${pageContext.request.contextPath}/login.jsp">用戶登錄</a> </c:when> <c:otherwise>

歡迎你,${sessionScope.user.username}!<ahref="${pageContext.request.contextPath}/LogoutServlet">注銷</a> </c:otherwise> </c:choose><hr/></body>任務:Filter在Cookie自動登錄中的使用STEP03創(chuàng)建Servlet(1)編寫LoginServlet類:在chapter09項目的cn.itcast.chapter09.filter包中,編寫LoginServlet類,用于處理用戶的登錄請求,如果輸入的用戶名和密碼正確,則發(fā)送一個用戶自動登錄的Cookie,并跳轉到首頁,否則提示輸入的用戶名或密碼錯誤,并跳轉至登錄頁面(login.jsp),讓用戶重新登錄。LoginServlet類的實現(xiàn)如下所示。publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{

//只展示doGet()方法的內(nèi)容Stringusername=request.getParameter("username");//獲得用戶名Stringpassword=request.getParameter("password");

//獲得密碼if("itcast".equals(username)&&"123456".equals(password)){//檢查用戶名和密碼 //登錄成功,將用戶狀態(tài)user對象存入session域 Useruser=newUser(); user.setUsername(username); user.setPassword(password);request.getSession().setAttribute("user",user); StringautoLogin=request.getParameter("autologin");//發(fā)送自動登錄的cookie if(autoLogin!=null){//注意cookie中的密碼要加密 Cookiecookie=newCookie("autologin",username+"-"+password); cookie.setMaxAge(Integer.parseInt(autoLogin)); cookie.setPath(request.getContextPath());response.addCookie(cookie); }response.sendRedirect(request.getContextPath()+“/index.jsp”);//

跳轉至首頁 }else{request.setAttribute("errerMsg","用戶名或密碼錯誤"); request.getRequestDispatcher("/login.jsp").forward(request,response);}}任務:Filter在Cookie自動登錄中的使用STEP03編寫LogoutServlet類(2)在chapter09項目的cn.itcast.chapter09.filter包中,編寫LogoutServlet類,用于注銷用戶登錄的信息。在LogoutServlet類中,首先將Session會話中保存的User對象刪除,然后將自動登錄的Cookie刪除,最后跳轉到index.jsp。LogoutServlet類的實現(xiàn)如下所示。@WebServlet(name="LogoutServlet",urlPatterns="/LogoutServlet")publicclassLogoutServletextendsHttpServlet{ publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse) throwsServletException,IOException{ request.getSession().removeAttribute("user");//用戶注銷 //從客戶端刪除自動登錄的cookie Cookiecookie=newCookie("autologin","msg"); cookie.setPath(request.getContextPath()); cookie.setMaxAge(0); response.addCookie(cookie); response.sendRedirect(request.getContextPath()+"/index.jsp"); } publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse) throwsServletException,IOException{ doGet(request,response); }}任務:Filter在Cookie自動登錄中的使用STEP04創(chuàng)建過濾器在chapter09項目的cn.itcast.chapter09.filter包中,編寫AutoLoginFilter類,用于攔截用戶登錄的訪問請求,判斷請求中是否包含用戶自動登錄的Cookie,如果包含則獲取Cookie中的用戶名和密碼,并驗證用戶名和密碼是否正確,如果正確,則將用戶的登錄信息封裝到User對象存入Session域中,完成用戶自動登錄。AutoLoginFilter類的實現(xiàn)如下所示。publicvoiddoFilter(ServletRequestreq,ServletResponseresponse,

FilterChainchain)throwsIOException,ServletException{

//只展示doFilter()方法的內(nèi)容

HttpServletRequestrequest=(HttpServletRequest)req;

Cookie[]cookies=request.getCookies(); Stringautologin=null;

for(inti=0;cookies!=null&&i<cookies.length;i++){ if("autologin".equals(cookies[i].getName())){//找到了指定的cookie autologin=cookies[i].getValue(); break;}} if(autologin!=null){//做自動登錄 String[]parts=autologin.split("-"); Stringusername=parts[0];Stringpassword=parts[1]; if("itcast".equals(username)&&("123456").equals(password)){ Useruser=newUser(); user.setUsername(username);user.setPassword(password); request.getSession().setAttribute("user",user);}} chain.doFilter(request,response);//放行 }任務:Filter在Cookie自動登錄中的使用STEP05運行項目,查看結果(1)訪問login.jsp頁面:重啟服務器,打開瀏覽器在地址欄中輸入“http://localhost:8080/chapter09/login.jsp”,瀏覽器窗口中會顯示一個用戶登錄的表單,如下所示。任務:Filter在Cookie自動登錄中的使用STEP05(2)訪問實現(xiàn)用戶登錄:在上圖所示的登錄表單中輸入用戶名“itcast”、密碼“123456”,并選擇用戶自動登錄的時間,單擊“登錄”按鈕,便可完成用戶自動登錄。單擊“登錄”按鈕之后,瀏覽器窗口會顯示登錄的用戶名,如下圖所示。任務:Filter在Cookie自動登錄中的使用由上圖可知,用戶已經(jīng)登錄成功了,關閉瀏覽器后重新打開瀏覽器,在地址欄中直接輸入“http://localhost:8080/chapter09/index.jsp”仍可以看到用戶的登錄信息,表明用戶已經(jīng)成功登錄。STEP05(3)注銷用戶:單擊上圖中的“注銷”超鏈接,就可以注銷當前的用戶,注銷之后,瀏覽器顯示頁面如下圖所示。

任務:Filter在Cookie自動登錄中的使用由上圖可知,用戶已經(jīng)注銷成功。此時如果再開啟一個新的瀏覽器窗口,訪問首頁網(wǎng)址,頁面仍會顯示圖3的內(nèi)容。至此,使用Filter校驗用戶Cookie信息,實現(xiàn)用戶自動登錄功能已經(jīng)完成。Listener9.29.2.1Listener概述先定一個小目標!

先定一個小目標!了解Listener的概念,能夠知道Listener用于做什么Filter鏈的攔截在Web程序開發(fā)中,經(jīng)常需要對某些事件進行監(jiān)聽,以便及時作出處理,如監(jiān)聽鼠標單擊事件、監(jiān)聽鍵盤按下事件等。為此,Servlet提供了監(jiān)聽器(Listener),專門用于監(jiān)聽Servlet事件。9.2.1Listener概述Listener的重要組成部分9.2.1Listener概述Listener在監(jiān)聽過程中會涉及幾個重要組成部分,具體如下。(1)事件:用戶的一個操作,如單擊一個按鈕、調(diào)用一個方法、創(chuàng)建一個對象等。(2)事件源:產(chǎn)生事件的對象。(3)事件監(jiān)聽器:負責監(jiān)聽發(fā)生在事件源上的事件。(4)事件處理器:監(jiān)聽器的成員方法,當事件發(fā)生的時候會觸發(fā)對應的處理器(成員方法)。注意:當用戶執(zhí)行一個操作觸發(fā)事件源上的事件時,該事件會被事件監(jiān)聽器監(jiān)聽到,當監(jiān)聽器監(jiān)聽到事件發(fā)生時,相應的事件處理器就會對發(fā)生的事件進行處理。事件監(jiān)聽器的工作過程9.2.1Listener概述事件監(jiān)聽器的工作過程可分為以下幾個步驟。

(1)將監(jiān)聽器綁定到事件源,也就是注冊監(jiān)聽器。

(2)監(jiān)聽器監(jiān)聽到事件發(fā)生時,會調(diào)用監(jiān)聽器的成員方法,將事件對象傳遞給

事件處理器,即觸發(fā)事件處理器。

(3)事件處理器通過事件對象獲得事件源,并對事件源進行處理。9.2.2Listener的API先定一個小目標!

先定一個小目標!熟悉Listener中8個不同的監(jiān)聽器接口,分別監(jiān)聽不同的對象Listener事件監(jiān)聽器Web應用中的Listener就是一個實現(xiàn)了特定接口的Java程序,專門用于監(jiān)聽Web應用程序中ServletContext、HttpSession和ServletRequest等域對象的創(chuàng)建和銷毀過程,以及這些域對象屬性的修改,并且感知綁定到HttpSession域中某個對象的狀態(tài)變化。9.2.2Listener的APIListener中8個不同的監(jiān)聽器接口9.2.2Listener的API類型描述ServletContextListener用于監(jiān)聽ServletContext對象的創(chuàng)建與銷毀過程HttpSessionListener用于監(jiān)聽HttpSession對象的創(chuàng)建和銷毀過程ServletRequestListener用于監(jiān)聽ServletRequest對象的創(chuàng)建和銷毀過程ServletContextAttributeListener用于監(jiān)聽ServletContext對象中的屬性變更HttpSessionAttributeListener用于監(jiān)聽HttpSession對象中的屬性變更ServletRequestAttributeListener用于監(jiān)聽ServletRequest對象中的屬性變更HttpSessionBindingListener用于監(jiān)聽JavaBean對象綁定到HttpSession對象和從HttpSession對象解綁的事件HttpSessionActivationListener用于監(jiān)聽HttpSession中對象活化和鈍化的過程Listener中8個不同的監(jiān)聽器接口的分類9.2.2Listener的APIListener中的8種Servlet事件監(jiān)聽器可以分為三類,具體如下。(1)用于監(jiān)聽域對象創(chuàng)建和銷毀的監(jiān)聽器:ServletContextListener接口、HttpSessionListener接口和ServletRequestListener接口。(2)用于監(jiān)聽域對象屬性增加和刪除的監(jiān)聽器:ServletContextAttributeListener接口、HttpSessionAttributeListener接口和ServletRequestAttributeListener接口。(3)用于監(jiān)聽綁定到HttpSession域中某個對象狀態(tài)的事件監(jiān)聽器:HttpSessionBindingListener接口和HttpSessionActivationListener接口。Listener中8個不同的監(jiān)聽器接口9.2.2Listener的API在Servlet規(guī)范中,這三類事件監(jiān)聽器都定義了相應的接口,在編寫監(jiān)聽器程序時只需實現(xiàn)對應的接口就可以。Web服務器會根據(jù)監(jiān)聽器所實現(xiàn)的接口,把它注冊到被監(jiān)聽的對象上,當被監(jiān)聽的對象觸發(fā)了監(jiān)聽器的事件處理器時,Web服務器將會調(diào)用監(jiān)聽器相關的方法對事件進行處理。先定一個小目標!

先定一個小目標!通過Listener監(jiān)聽ServletContext、HttpSession和ServletRequest域對象的生命周期任務:監(jiān)聽域對象的生命周期任務:監(jiān)聽域對象的生命周期

要想對Servlet域對象的生命周期進行監(jiān)聽,首先需要實現(xiàn)域對象的ServletContextListener、HttpSessionListener和ServletRequestListener接口,這些接口中的方法和執(zhí)行過程非常類似??梢詾槊恳粋€監(jiān)聽器編寫一個單獨的類,也可以用一個類實現(xiàn)這三個接口,從而讓這個類具有三個事件監(jiān)聽器的功能。

本案例要求編寫一個Listener監(jiān)聽ServletContext、HttpSession和ServletRequest域對象的生命周期。STEP01創(chuàng)建監(jiān)聽器在chapter09項目中創(chuàng)建一個cn.itcast.chapter09.listener包,在該包中新建一個MyListener類,用于實現(xiàn)ServletContextListener、HttpSessionListener和ServletRequestListener三個監(jiān)聽器接口,并實現(xiàn)這些接口中的所有方法。MyListenser類的實現(xiàn)如下所示。

@WebListenerpublicclassMyListenerimplementsServletContextListener,HttpSessionListener,ServletRequestListener{ publicvoidcontextInitialized(ServletContextEventarg0){ System.out.println("ServletContext對象被創(chuàng)建了"); } publicvoidcontextDestroyed(ServletContextEventarg0){ System.out.println("ServletContext對象被銷毀了"); } //省略requestInitialized()、requestDestroyed()、sessionCreated()和

//

sessionDestroyed()方法}任務:監(jiān)聽域對象的生命周期STEP02啟動項目,查看ServletContext對象創(chuàng)建信息在IDEA中啟動Tomcat服務器,控制臺窗口顯示結果如下圖所示。

任務:監(jiān)聽域對象的生命周期由圖中所示的控制臺窗口可知,ServletContext對象被創(chuàng)建了,這是因為Web服務器在啟動時會自動加載chapter09這個Web項目,并創(chuàng)建其對應的ServletContext對象。而服務器之所以會自動加載chapter09項目,是因為在MyListenser類上添加的@WebListener注解開啟了Listener。Web服務器創(chuàng)建ServletContext對象后就調(diào)用MyListener類中的contextInitialized()方法,輸出“ServletContext對象被創(chuàng)建了”這行信息。STEP03關閉項目,查看ServletContext對象銷毀信息為了觀察ServletContext對象的銷毀信息,可以將已經(jīng)啟動的Web服務器關閉,關閉Web服務器之后,控制臺窗口顯示的結果如圖所示。任務:監(jiān)聽域對象的生命周期由圖中可知,在Web服務器關閉之前,ServletContext對象被銷毀并調(diào)用了MyListener中的contextDestroyed()方法。STEP04創(chuàng)建測試頁面為了查看HttpSessionListener和ServletRequestListener的運行效果,在chapter09項目的web目錄中編寫一個簡單的頁面文件myjsp.jsp,myjsp.jsp的實現(xiàn)如下所示。

<%@pagelanguage="java"contentType="text/html;charset=utf-8"pageEncoding="utf-8"%><html><head><title>thisisMyJsp.jsppage</title></head><body>

這是一個測試監(jiān)聽器的頁面</body></html>任務:監(jiān)聽域對象的生命周期STEP05設置監(jiān)聽超時信息為了盡快查看到HttpSession對象創(chuàng)建與銷毀過程,可以在chapter09項目的web.xml文件中設置session的超時時間為2min,具體代碼如下。<session-config> <session-timeout>2</session-timeout></session-config>任務:監(jiān)聽域對象的生命周期在上述配置中,<session-timeout>標簽指定的超時必須為一個整數(shù),若這個整數(shù)為0或負整數(shù),則session永遠不會超時,如果這個數(shù)是正整數(shù),那么項目中的session將在指定分鐘后超時。STEP06重啟項目,查看結果重新啟動項目chapter09,再打開瀏覽器,在地址欄中輸入“http://localhost:8080/chapter09/myjsp.jsp”,訪問myjsp.jsp頁面,控制臺窗口中顯示的結果如圖所示。

任務:監(jiān)聽域對象的生命周期由圖中可知,當瀏覽器第一次訪問myjsp.jsp頁面時,Web容器除了為這次請求創(chuàng)建ServletRequest對象外,還創(chuàng)建了與這個瀏覽器對應的HttpSession對象,當這兩個對象被創(chuàng)建時,Web容器會調(diào)用監(jiān)聽器MyListener中的requestInitialized()、sessionCreated()和requestDestroyed()方法完成ServletRequest和HttpSession對象的創(chuàng)建和銷毀,當Web服務器完成這次請求后,ServletRequest對象會隨之銷毀,因此控制臺窗口輸出了“ServletRequest對象被銷毀了”。任務:監(jiān)聽域對象的生命周期需要注意的是,如果此時單擊瀏覽器窗口的中“刷新”按鈕,再次訪問myjsp.jsp頁面,控制臺窗口會再次輸出ServletRequest對象被創(chuàng)建與被銷毀的信息,但不會創(chuàng)建新的HttpSession對象,這是因為Web容器會為每次請求都創(chuàng)建一個新的ServletRequest對象,而對于同一個瀏覽器在會話期間只會創(chuàng)建一個HttpSession對象。關閉訪問myjsp.jsp頁面的瀏覽器窗口或保持瀏覽器窗口不刷新,與之對應的HttpSession對象將在2min之后被銷毀,控制臺窗口顯示結果如下圖所示。由圖中可知,HttpSession對象被銷毀了,Web服務器調(diào)用了監(jiān)聽器對象的sessionDestroyed()方法銷毀了該對象。Servlet3.0新特性9.39.3Servlet3.0新特性先定一個小目標!

先定一個小目標!熟悉Servlet3.0新特性:注解和異步處理支持Servlet3.0的新特性Servlet3.0作為JavaEE6規(guī)范體系中一員,隨著JavaEE6規(guī)范一起發(fā)布。Servlet3.0在前一版本(Servlet2.5)的基礎上提供了很多新特性以簡化Web應用的開發(fā)和部署。在前面的章節(jié)中其實已經(jīng)接觸了Servlet3.0的新特性,例如,已經(jīng)使用過的@WebServlet注解、@WebFilter注解,注解就是Servlet3.0的新特性之一,通過使用注解的方式簡化了Servlet的配置。9.3Servlet3.0新特性注解幾乎所有基于Java的web框架都建立在servlet之上,在Servlet3.0之前,web框架需要在web.xml中配置。在Servlet3.0之后,可以用注解的方式配置web框架,簡化了web框架的開發(fā)。9.3Servlet3.0新特性Servlet3.0常見的注解Servlet3.0常見的注解主要有以下幾個。@WebServlet:修飾Servlet類,用于部署Servlet類。@WebFilter:修飾Filter類,用于部署Filter類@WebListener:修飾Listener類,用于部署Listener類。@WebInitParam:與@WebServlet或@WebFilter注解連用,為@WebServlet或@WebFilter注解配置參數(shù)。@MultipartConfig:修飾Servlet類,指定Servlet類負責處理multipart/form-data類型的請求(主要用于處理上傳文件)@ServletSecurity:修飾Servlet類,與JAAS(Java驗證和授權API)有關的注解。9.3Servlet3.0新特性普通Servlet的工作流程Servlet3.0的異步處理特性可以提高Web程序的接口處理速度。在Servlet3.0之前,一個普通Servlet的工作流程大致如下。(1)Servlet接收到請求之后,對請求攜帶的數(shù)據(jù)進行一些預處理。(2)調(diào)用業(yè)務接口的某些方法,完成業(yè)務處理。(3)最后根據(jù)處理的結果提交響應,Servlet線程結束。9.3Servlet3.0新特性普通Servlet的工作流程的弊端在上述的Servlet工作流程的第(2)步是業(yè)務處理通常是最耗時的,這主要體現(xiàn)在數(shù)據(jù)庫操作,以及其他的跨網(wǎng)絡調(diào)用等。在此過程中,Servlet線程一直處于阻塞狀態(tài),直到業(yè)務方法執(zhí)行完畢。在處理業(yè)務的過程中,Servlet資源一直被占用而得不到釋放,對于并發(fā)較大的應用,可能造成性能瓶頸。對于這個問題,Servlet3.0之前,通常是采用提前結束Servlet線程的方式,及時釋放資源。9.3Servlet3.0新特性異步處理的Servlet工作流程Servlet3.0通過異步處理,將之前的Servlet工作流程進行了調(diào)整,具體如下。(1)Servlet接收到請求之后,首先對請求攜帶的數(shù)據(jù)進行一些預處理。(2)Servlet線程將請求轉交給一個異步線程執(zhí)行業(yè)務處理。(3)線程本身返回至Web容器,此時Servlet還沒有生成響應數(shù)據(jù)。(4)異步線程處理完業(yè)務以后,可以直接生成響應數(shù)據(jù)(異步線程擁有ServletRequest和ServletResponse對象的引用),或者將請求繼續(xù)轉發(fā)給其他Servlet。注意:如此一來,Servlet線程不再是一直處于阻塞狀態(tài)等待業(yè)務邏輯處理完成,而是啟動異步線程之后可以立即返回。9.3Servlet3.0新特性異步處理特性異步處理特性可以應用于Servlet和過濾器兩個組件,由于異步處理的工作模式和普通工作模式在實現(xiàn)上有著本質(zhì)的區(qū)別,因此默認情況下,Servlet和過濾器并沒有開啟異步處理特性,如果希望使用該特性,可以通過web.xml配置與注解兩種方式實現(xiàn)。9.3Servlet3.0新特性Web.xml配置開啟異步處理對于使用web.xml文件配置Servlet和過濾器的情況,Servlet3.0在Servlet標簽中增加了async-supported子標簽,該標簽的默認取值為false,要啟用異步處理支持,將其設置為true即可。以的MyServlet.java為例,如果開啟異步處理,web.xml文件的配置方式如下所示。9.3Servlet3.0新特性<servlet><servlet-name>MyServlet</servlet-name><servlet-class>cn.itcast.chapter09.filter.MyServlet</servlet-class><async-supported>true</async-supported></servlet>注解配置開啟異步處理對于使用Servlet3.0提供的@WebServlet和@WebFilter注解對Servlet或過濾器進行配置的情況,由于這兩個注解都提供了asyncSupported屬性,因此可以通過設置asyncSupported屬性值開啟異步處理。asyncSupported默認值為false,要啟用異步處理支持,只需將該屬性設置為true即可。以@WebFilter注解為例,其配置方式如下所示。9.3Servlet3.0新特性@WebFilter(filterName="MyFilter",urlPatterns="/MyServlet",

asyncSupported=true)文件的上傳和下載9.49.4.1文件上傳的原理先定一個小目標!

先定一個小目標!熟悉文件上傳的原理9.4.1文件上傳的原理要實現(xiàn)Web開發(fā)中的文件上傳功能,通常需完成兩步操作:一是在Web項目的頁面中添加上傳輸入項,二是在Servlet中讀取上傳文件的數(shù)據(jù),并保存到目標路徑中。由于大多數(shù)文件的上傳都是通過表單的形式提交給服務器的,因此,要想在程序中實現(xiàn)文件上傳功能,首先要創(chuàng)建一個用于提交上傳文件的表單頁面。在表單頁面中,需要使用<inputtype="

溫馨提示

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

最新文檔

評論

0/150

提交評論