web bjsp19周五-課件第9章_第1頁
web bjsp19周五-課件第9章_第2頁
web bjsp19周五-課件第9章_第3頁
web bjsp19周五-課件第9章_第4頁
web bjsp19周五-課件第9章_第5頁
免費預覽已結束,剩余157頁可下載查看

下載本文檔

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

文檔簡介

9.1Servlet概述9.2Servlet的基本結構與成員方法9.3調用Servlet的多種方法9.4兩種模式的JSP技術9.5Servlet模式的留言板案例9.6Servlet的會話跟蹤習題9第9章Servlet隨著動態網頁技術的日益發展,1955年Sun公司首先將Java引入,并介紹了基于Java的小應用程序Applet,隨后又在1996年推出了Servlet。JavaServlet的編程模式和CGI類似,但它的功能和性能要比CGI強大得多。Sun公司1999年6月推出的JSP技術,是基于JavaServlet以及整個Java體系的Web開發技術。Servlet技術為Web開發者提供了一種簡便、可靠的機制來擴展Web服務器的功能和訪問現有的事務系統,Servlet是快速、高效地開發Web動態網站的工具。JSP+Servlet技術使服務器端動態頁面程序可以真正地做到跨平臺,因此,這種技術得到了越來越多的支持和使用。這一章主要講解Servlet的特點、工作原理及JSP+

Servlet的編程技術。

Servlet就是使用JavaServletAPI及相關類和軟件包的Java程序。JavaApplet是運行在客戶端(瀏覽器)的Java類,Servlet是運行在Web服務器上的Applet,主要用于處理Web請求,動態產生HTML頁面。但是,Servlet沒有運行界面,它與協議和平臺無關,不受客戶端的安全限制。Servlet為構建Web應用程序提供了一種基于組件的平臺無關的方法,它可以使用所有的JavaAPI,包括可以訪問企業級數據庫的JDBCAPI,還可以訪問特殊的HTTP庫。Servlet具有所有Java語言的方便、可復用、安全性等優點。

9.1Servlet概述9.1.1Servlet的特點

Servlet具備Java跨平臺的優點,它不受軟硬件環境的限制,其特點如下:

(1)可移植性好。Servlet用Java編寫。Servlet代碼被編譯成字節碼后,字節碼由WebServer中與平臺有關的Java虛擬機(JVM)來解釋。因此,Servlet本身由無平臺的字節碼組成,所以,Servlet無需任何實質上的改動即可移植到別的服務器上。幾乎所有的主流服務器都直接或通過插件支持Servlet。

(2)高效。在傳統的CGI中,客戶機向服務器發出的每個請求都要生成一個新的進程。在Servlet中,每個請求將生成一個新的線程,而不是一個完整的進程。Servlet被調用時,它被載入駐留在內存中,直到更改Servlet,它才會被再次加載。

(3)功能強大。Servlet可以使用JavaAPI核心的所有功能,這些功能包括Web和URL訪問、圖像處理、數據壓縮、多線程、JDBC、RMI、序列化對象等。

(4)方便。Servlet提供了大量的實用工具例程,例如自動地解析和解碼HTML表單數據、讀取和設置HTTP頭、處理Cookie、跟蹤會話狀態等。

(5)可重用性。Servlet提供重用機制,可以給應用建立組件或用面向對象的方法封裝共享功能。

(6)模塊化。JSP、Servlet、JavaBean都提供把程序模塊化的途徑——把整個應用劃分為許多離散的模塊,各模塊負責一項具體的任務,使程序便于理解。每一個Servlet可以執行一個特定的任務,Servlet之間可以相互交流。

(7)節省投資。不僅有許多廉價甚至免費的Web服務器可供個人或小規模網站使用,而且對于現有的服務器,如果它不支持Servlet的話,想要加上這部分功能也往往是免費的或只需要極少的投資。

(8)安全性。Servlet可以充分利用Java的安全機制,并且可以實現類型的安全性。9.1.2Servlet的工作原理

Servlet由支持Servlet的服務器Servlet引擎負責管理運行。引擎為每一個請求創建一個輕量級的線程并進行管理。Servlet的工作原理如圖9.1所示,其工作步驟如下:

(1)瀏覽器向Web服務器發出請求。例如,使用瀏覽器按照HTTP協議鍵入一個URL地址,向Web服務器提出請求。

(2)

Web服務器響應請求后,把發給Servlet的請求,轉交給Servlet引擎處理。

(3)

Servlet引擎檢查對應的Servlet是否已裝載,如果沒有裝載,則將其載入內存并初始化,然后由該Servlet對請求進行處理。如果Servlet中含有訪問數據庫的操作,則還要通過相關的JDBC驅動程序,與數據庫相連,對數據庫進行訪問。

(4)

Servlet通過JDBC取回結果,生成HTML頁面并將頁面送回Web服務器。

(5)

Web服務器將頁面發送回瀏覽器。最后Servlet將動態生成的標準HTML頁面送給客戶端瀏覽器。

圖9.1Servlet的工作原理9.1.3Servlet的應用范圍

Servlet的主要功能是處理Web請求,動態產生HTML頁面。它的功能涉及范圍很廣,例如:

(1)創建并返回一個包含基于客戶請求性質的、動態內容的、完整的HTML頁面。

(2)創建可嵌入到現有HTML頁面中的一部分HTML頁面(HTML片段)。

(3)處理多個客戶機的連接,接收多個客戶機的輸入,并將結果廣播到多個客戶機上。

(4)可以與其它服務器資源(包括數據庫和基于Java的應用程序)進行通信,轉交請求給其它的服務器和Servlet,按照任務類型或組織范圍,允許在幾個服務器中劃分邏輯上的服務器。

(5)

Servlet開發人員可以定義彼此之間共同工作的激活代理,每個代理都是一個Servlet,代理者之間可以傳送數據。9.1.4Servlet的生命周期

Servlet的生命周期分為裝載Servlet、處理客戶請求和結束Servlet三個階段。

1.裝載Servlet

在下列時刻服務器裝載Servlet:

●如果配置了自動裝載選項,則在啟動Web服務器時自動裝載Servlet。

●在Web服務器啟動后客戶端首次向Servlet發出請求時,自動裝載Servlet。

●重新裝載Servlet時自動裝載Servlet。

所謂裝載Servlet,實際上是用Web服務器創建一個Servlet對象,調用這個對象的init()方法完成必要的初始化工作。

2.處理客戶請求

當Servlet初始化結束后,Servlet接收由服務器傳來的用戶請求,調用service()方法處理客戶請求。

service()方法首先獲得關于請求對象的信息,處理請求,訪問其它資源,獲得需要的信息。然后,service()方法使用響應對象的方法將響應傳回Web服務器,Web服務器做相應處理后再將其傳送至客戶端。service()方法也可能激活其它方法(如doGet()、doPost()或用戶自己開發的新的方法)以處理請求。

Servlet的響應有以下類型:

●一個輸出流,瀏覽器根據它的內容類型(如TEXT/HTML)進行解釋。

●一個HTTP錯誤響應,重定向到另一個URL、Servlet、JSP。

Servlet能夠同時運行多個service()方法。對于每一個客戶請求,Servlet都在它自己的線程中調用service()方法為用戶服務。如此循環,但Servlet不再調用init()方法進行初始化,一般情況下只初始化一次。圖9.2Servlet對客戶端提供服務的過程

3.結束Servlet

當Web服務器要卸載Servlet或重新裝入Servlet時,服務器會調用servlet的destroy()方法,將Servlet從內存中刪除,否則它一直為客戶服務。

總之,Servlet的生命周期如圖9.2所示,開始于將它裝載到Web服務器,結束于終止或重新裝載Servlet。當Servlet被加載后,主要通過循環調用service()方法為用戶服務。9.1.5init()、service()和destroy()方法

1.?init()方法

Servlet第一次被請求加載時,服務器創建一個Servlet對象,這個對象調用init()方法完成必要的初始化工作。該方法在執行時,Servlet會把一個ServletConfig類型的對象傳遞給init()方法,這個對象就被保存在Servlet對象中,直到Servlet對象被銷毀。

服務器只調用一次init()方法,以后的客戶再請求Servlet服務時,Web服務器將啟動一個線程,在該線程中,Servlet調用service()方法響應客戶的請求,除非它要重載這個Servlet。在重載某個Servlet之前,服務器必須先調用destroy()方法卸載這個Servlet。缺省的init()方法設置了Servlet的初始化參數,并用它的ServletConfig對象參數來啟動配置,所以,通常不必覆蓋init()方法。但是,在個別情況下也可以用自己編寫的init()方法來覆蓋它。例如,可以編寫一個init()方法用于一次裝入GIF圖像,也可以編寫一個init()方法初始化數據庫連接。同時需要注意,所有覆蓋init()方法的Servlet應調用super.init()方法,以確保仍然執行這些任務。此外,在調用service()方法之前,應確保已完成了init()方法。

2.?service()方法

service()方法是Servlet的核心。每當客戶請求一個Servlet對象時,該對象的service()方法就被調用,而且傳遞給service()方法一個“請求”(ServletRequest)對象和一個“響應”(ServletResponse)對象作為參數。service()方法根據請求的類型調用相應的服務功能,缺省的服務功能是調用與HTTP請求的方法相應的do功能。例如,當客戶通過HTML表單發出一個HTTPGET請求時,則缺省情況下就調用doGet()方法;當客戶發出的是一個HTTPPOST請求時,就調用doPost()方法。

Servlet應該為Servlet支持的HTTP方法覆蓋do功能。因為HttpServlet.service()方法會檢查請求方法是否調用了適當的處理方法。不必要覆蓋service()方法,只需覆蓋相應的do方法就可以了。

3.?destroy()方法

destroy()方法僅執行一次,即在服務器停止且卸載Servlet時執行該方法。缺省的destroy()方法通常是符合要求的。也可以覆蓋destroy()方法。例如,如果Servlet在運行時要累計統計數據,則可以編寫一個destroy()方法,該方法用于在未裝載Servlet時將統計數字保存在文件中,也可以編寫一個destroy()方法關閉數據庫連接等。

一個Servlet程序就是一個在Web服務器端運行的特殊Java類。Sun公司提供了javax.servlet和javax.servlet.http兩個擴展包來開發Servlet。這兩個包屬于Java的標準擴展JavaServletAPI。

javax.servlet包提供了控制Servlet生命周期所必需的Servlet接口。

javax.servlet.http包提供了從Servlet接口派生出的專門用于處理HTTP請求的抽象類和一般的工具類。9.2Servlet的基本結構與成員方法9.2.1Servlet的基本層次結構

Servlet的基本層次結構如圖9.3所示。

Servlet程序必須實現javax.servlet.Servlet接口。Servlet接口定義了Servlet容器與Servlet程序之間的通信協議。為了簡化Servlet程序的編寫,ServletAPI中也提供了一個實現Servlet接口的GenericServlet類,這個類實現了Servlet程序的基本特征和功能。ServletAPI中還提供了一個專用于HTTP協議的HttpServlet類。HttpServlet類是GenericServlet類的子類,在GenericServlet類的基礎上進行了一些針對HTTP特點的擴充。因此,開發基于Servet類的應用必須繼承GenericServlet類或HttpServlet類。為了充分利用HTTP協議的功能,一般情況下,都將自己編寫的Servlet作為HttpServlet類的子類。而HttpServlet類是一個抽象類,開發者必須在自己定義的繼承類中實現HttpServlet類的所有方法。圖9.3Servlet接口和類的繼承關系9.2.2HttpServlet類的成員方法

由于大多數Servlet是針對HTTP協議的Web服務器,所以,最通用的開發Servlet的方法是使用HttpServlet類。由于HttpServlet類是一個抽象類,可以從該類派生出一個類來實現HttpServlet,即將自己定義的類作為HttpServlet的子類。

Servlet被設計成請求驅動的。Servlet的請求可能包含多個數據項,當Web站點接收某個對Servlet的請求時(該請求來自訪問此Web站點的客戶端瀏覽器),它把這個請求封裝成一個HttpServletRequest對象,然后把此對象傳給Servlet的對應服務方法(doGet()、doPost())或高級的處理方法(doPut()、doTrace()、doDelete())進行處理。經這些方法中的某個方法處理后,將處理的響應結果返回Web站點,Web站點再將響應發送給客戶端瀏覽器。因此,在開發者自己定義的HttpServlet的子類中,必須至少重載下列方法中的一種。

HttpServlet類中常用的成員方法如下。

(1)

protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;

被這個類的service()方法調用,用來處理一個HTTPGET操作。這個操作允許客戶端簡單地從HTTP服務器“獲得”資源。對這個方法的重載將自動地支持HEAD方法。

當一個客戶通過HTML表單發出一個HTTPGET請求或直接請求一個URL時,doGet()方法被調用。與GET請求相關的參數添加到URL的后面,并與這個請求一起發送。當不需修改服務器端的數據時,應該使用doGet()方法。

(2)

protectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;

被這個類的service()方法調用,用來處理一個HTTPPOST操作。這個操作包含請求體的數據。當開發者要處理POST操作時,必須在HttpServlet的子類中重載這一方法。

當一個客戶通過HTML表單發出一個HTTPPOST請求時,doPost()方法被調用。與POST請求相關的參數作為一個單獨的HTTP請求從瀏覽器發送到服務器。當需要修改服務器端的數據時,應該使用doPost()方法。

(3)

protectedvoiddoHead(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;

被這個類的service()方法調用,用來處理一個HTTPHEAD操作。默認的情況是,這個操作會按照一個無條件的get方法來執行,該操作僅僅是返回包含內容長度的頭信息。

(4)

protectedvoiddoDelete(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;

被這個類的service()方法調用,用來處理一個HTTPDELETE操作。這個操作允許客戶端請求從服務器上刪除URL。當開發者要處理DELETE請求時,必須重載這一方法。

(5)

protectedvoiddoOptions(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;

被這個類的service()方法調用,用來處理一個HTTPOPTION操作。這個操作自動地決定支持哪一種HTTP方法。

(6)

protectedvoiddoPut(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;

被這個類的service()方法調用,用來處理一個HTTPPUT操作。這個操作類似于通過FTP發送文件。當要處理PUT操作時,必須在HttpServlet的子類中重載這一方法。

(7)

protectedvoiddoTrace(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;

被這個類的service()方法調用,用來處理一個HTTPTRACE操作。這個操作的默認執行結果是產生一個響應,這個響應包含一個反映TRACE請求中發送的所有頭域的信息。當開發Servlet時,在多數情況下需要重載這個方法。

(8)

protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException;

publicvoidservice(ServletRequestrequest,ServletResponseresponse)throwsServletException,IOException;

service()方法是Servlet的核心,它是一個Servlet的HTTP-specific方案,負責把請求分配給支持這個請求的其它方法。每當客戶請求一個HttpServlet對象時,該對象的service()方法就被調用,而且傳遞給該方法一個“請求”(ServletRequest)對象和一個“響應”(ServletResponse)對象作為參數。在HttpServlet中已存在service()方法。缺省的服務功能是調用與HTTP請求的方法相應的do功能。例如,如果HTTP請求的方法為get,則缺省情況下就調用doGet()。Servlet應該為Servlet支持的HTTP方法覆蓋do功能。因為HttpServlet.service()方法會檢查請求方法是否調用了適當的處理方法。

在開發Servlet時,大多數情況下不必重載service()方法,只需覆蓋相應的do方法就可以了。9.2.3在Eclipse中建立Servlet

下面我們使用Eclipse開發平臺,建立一個簡單的Servlet,以說明如何開發Servlet。

在Eclipse建立、編譯、運行Servlet程序(C9_1.java程序)的步驟與第3章所述建立JSP程序的步驟基本相同。當建立了ch9項目(文件夾)后,存放C9_1.java程序,操作過程如圖9.4所示。

在“ch9”文件夾下單擊右鍵,依次單擊“新建”/“servlet”,彈出如圖9.5所示的“創建servlet”對話框。圖9.4新建Servlet圖

圖9.5“創建servlet”對話框在圖9.5中輸入類名C9_1,然后單擊“下一步”,彈出編輯界面,在其中輸入程序。圖9.6是在編輯界面中輸入程序后的狀態。

【示例程序C9_1.java】在瀏覽器上輸出“ThefirstServlet程序”。

importjava.io.*;

importjavax.servlet.*;

importjavax.servlet.http.*;

publicclassC9_1extendsHttpServlet

{ publicvoidinit(ServletConfigcfig)throwsServletException

圖9.6在“創建servlet”對話框的編輯界面中輸入程序后的顯示

{super.init(cfig);}

//重寫service方法

publicvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException

{ response.setContentType("text/html;charset=GB2312");//設置響應的MIME類型

PrintWriterout=response.getWriter();//獲得向客戶發送數據的輸出流 out.println("<HTML><HEAD></HEAD><BODY>");

out.println("<H1ALIGN=CENTER><B>ThefirstServlet程序</H1><BR>");

out.println("</BODY></HTML>");

}

}

在圖9.6中輸入程序后,啟動運行C9_1.java,最終的結果如圖9.7所示。

圖9.7C9_1的運行結果程序說明:

(1)基于HTTP協議的Servlet必須導入javax.servlet和javax.servlet.http包。

(2)當客戶向Servlet發送一個請求時,經過init()方法初始化后,Servlet調用service()方法來對客戶端(client)發出的各個請求進行響應。它接受ServletRequest和ServletResponse兩個對象。Servlet從HttpServletRequest對象中取出輸入數據流,完成相應的操作;Servlet通過HttpServletResponse對象的getWriter()方法來獲得輸出流,將Servlet的響應數據返回給客戶。

(3)

HttpServletResponse必須知道輸出流的格式才能輸出,因此,要使用setContentType()方法來設置輸出流的格式。

生成一個Servlet后,可通過多種方法來調用它。常用的方法是下面四種之一:

●在瀏覽器的URL地址欄中直接指定。

●在HTML表單中通過<FORM>標記的ACTION屬性指定。

●使用服務器包含文件,即在HTML文件中使用<SERVLET>和</SERVLET>標記。

●在JSP頁面中調用Servlet。

下面將逐一介紹。9.3調用Servlet的多種方法9.3.1在URL中直接調用Servlet

【示例程序C9_2.java】在URL中調用Servlet,在瀏覽器上輸出客戶端的部分信息。

importjava.io.*;

importjavax.servlet.*;

importjavax.servlet.http.*;

publicclassC9_2extendsHttpServlet

{ //重寫doPost方法

publicvoiddoPost(HttpServletRequestreq,HttpServletResponseres)

throwsServletException,IOException

{ res.setContentType("text/html;charset=GB2312");//設置響應的MIME類型

PrintWriterout=res.getWriter();//獲得向客戶發送數據的輸出流

out.println("<HTML><HEAD></HEAD><BODY>");

out.println("<H3>輸出客戶端的信息</H3><BR>");

out.println("Method:"+req.getMethod()+"<BR>");//獲取請求的方法

out.println("RequestURL:"+req.getRequestURL()+"<BR>");//獲得請求URL

out.println("Protocol:"+req.getProtocol()+"<BR>");//獲得該對象的協議

out.println("RemoteAddress:"+req.getRemoteAddr()+"<BR>");//獲取客戶端IP地址

out.println("</BODY></HTML>");

}

//重寫doGet方法

publicvoiddoGet(HttpServletRequestreq,HttpServletResponseres)

throwsServletException,IOException

圖9.8C9_2的運行結果

{ doPost(req,res); }

}

該示例程序的運行結果如圖9.8所示。

程序說明:

(1)

C9_2是HttpServlet的子類,HttpServlet是GenericServlet的一個子類,通過GenericServlet實現了Servlet界面。

(2)當service()方法缺省時,則調用與HTTP請求方法相應的do功能。根據接收的HTTP請求類型,分別調用doGet()、doPost()等方法。

(3)

doGet()、doPost()方法的參數HttpServletRequest對象包含了客戶端請求的信息,可以通過該參數取得客戶端的一些信息(例如IP地址等)以及HTTP請求類型(例如GET、HEAD、POST、PUT等),生成HTTP響應;最后通過參數HttpServletResponse對象返回響應信息,完成Servlet與客戶端的交互。該程序中編寫了doPost()和doGet()兩個方法,并且在doGet()方法中調用了Servlet的doPost()方法,用于HTML請求。9.3.2在<FORM>標記中訪問Servlet

在HTML表單中通過<FORM>標記的ACTION屬性調用Servlet需要編寫兩個文件:一個是如c9_3.html所示的Web界面;另一個是如程序C9_3.java所示的Servlet。本例通過c9_3.html界面輸入信息,用戶的輸入信息提交給Servlet程序(C9_3.java)處理,并將處理結果輸出到用戶界面上。

【示例程序c9_3.html】在<FORM>標記中調用Servlet。

<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN">

<HTML><HEAD>

<metahttp-equiv="Content-Type"content="text/html;charset=GB2312">

<TITLE>在〈FORM〉標記中調用Servlet</TITLE>

</HEAD><BODY>

<CENTER>在〈FORM〉標記中調用Servlet</CENTER><HR>

<FORMMETHOD="post"ACTION="C9_3">

<P>姓名:<INPUTTYPE="name"name="myname"size=25maxlength="30"></P>

<P>愛好:<INPUTTYPE="text"name="love"size=30maxlength="30"></P>

<INPUTTYPE="submit"VALUE="確定">

<INPUTTYPE="reset"VALUE="清除">

</FORM>

</BODY></HTML>

【示例程序C9_3.java】<FORM>標記中調用的Servlet程序。

importjava.io.*;

importjavax.servlet.*;

importjavax.servlet.http.*;

publicclassC9_3extendsHttpServlet

{ //重寫doPost方法

publicvoiddoPost(HttpServletRequestreq,HttpServletResponseres)throwsServletException,IOException

{ res.setContentType("text/html;charset=GB2312");//設置響應的MIME類型

PrintWriterout=res.getWriter();//獲得向客戶發送數據的輸出流

byteb1[]=req.getParameter("myname").getBytes("ISO-8859-1");//獲得客戶端提交的參數

Strings1=newString(b1);

byteb2[]=req.getParameter("love").getBytes("ISO-8859-1");//獲得客戶端提交的參數

Strings2=newString(b2);

out.println("<HTML><HEAD></HEAD><BODY>");

out.println("<H3>輸出客戶端的信息</H3><BR>");

out.println("姓名:"+s1+"<BR>");//獲得請求URL

out.println("愛好:"+s2+"<BR>");//獲得請求URL

out.println("</BODY></HTML>");

}

//重寫doGet方法

publicvoiddoGet(HttpServletRequestreq,HttpServletResponseres) throwsServletException,IOException

{ doPost(req,res); }

}

該示例程序的運行結果如圖9.9和圖9.10所示。

圖9.9在表單界面c9_3.html上輸入數據

圖9.10Servlet的運行結果9.3.3利用超鏈接訪問Servlet

【示例程序c9_4.html】在HTML頁面中利用超鏈接訪問Servlet。

<HTML><HEAD><TITLE>超鏈接訪問Servlet</TITLE></HEAD>

<BODY>

<CENTER>

在HTML頁面中利用超鏈接訪問Servlet

</CENTER>

<HR>

<H3>

<AHREF="C9_1">加載servlet(C9_1)</A>

</H3>

</BODY>

</HTML>

c9_4.html的運行結果如圖9.11所示,單擊超鏈接后的運行結果見圖9.7所示。

圖9.11c9_4.html的運行結果9.3.4在JSP文件中調用Servlet

JSP和Servlet是兩種極具特色的動態Web技術,如果撇開底層運行機制上的共同之處(JSP被翻譯成Servlet再執行),單從開發人員的角度來看,完全可以單獨采用其中一種技術實現一個動態Web應用。由于Servlet輸出HTML時采用CGI的方式,是一句一句輸出的,所以,編寫和修改HTML文件非常不方便。而JSP把Java代碼嵌套到HTML語句中,大大簡化和方便了網頁的設計和維護。因此,在開發Web應用實踐中,主要是整合這兩種技術,實現兩種技術的優勢互補。在整合技術中,表示層的工作由JSP技術承擔,注重頁面的表現,編寫輸出HTML網頁的程序;業務邏輯層的工作由Servlet承擔,注重業務邏輯的實現,編寫完成諸如數據計算、數據分析、數據庫連接等操作處理的程序。在JSP文件中訪問Servlet所采用的格式與HTML頁面中調用Servlet的方法完全一樣,而且原理也完全相同。只不過這時訪問Servlet的是動態的JSP文件,而不是靜態的HTML頁面。顯然,在JSP文件中訪問Servlet也需要編寫兩個程序,即一個JSP程序和一個Servlet程序。本例中的c9_5.jsp程序是一個Web登錄頁面,在文本框中輸入用戶名和密碼,單擊“登錄”按鈕后,則把輸入的信息提交給<FORM>標記中調用的Servlet。程序C9_5.java是<FORM>標記中調用的Servlet,它接收用戶輸入的信息并將處理結果輸出到用戶界面上。

在Eclipse中建立JSP+Servlet程序(c9_5.jsp,C9_5.java)的存儲位置如圖9.12所示。

圖9.12JSP+Servlet的存儲位置

【示例程序c9_5.jsp】編寫一個調用Servlet的登錄頁面程序。

<%@pagecontentType="text/html;charset=GBK"%>

<HTML><HEAD><TITLE>在JSP中調用Servlet</TITLE></HEAD>

<BODY>

<CENTER>用戶登錄Servlet</CENTER><HR>

<FORMMETHOD="post"ACTION="C9_5">

<P>用戶名:<INPUTTYPE="name"name="myname"size=25></P>

<P>密碼:<INPUTTYPE="password"name="pass"></P>

<INPUTTYPE="submit"VALUE="確定">

<INPUTTYPE="reset"VALUE="清除">

</FORM>

</BODY></HTML>

【示例程序C9_5.java】測試登錄密碼,將處理結果輸出到頁面上。

importjava.io.*;

importjavax.servlet.*;

importjavax.servlet.http.*;

publicclassC9_5extendsHttpServlet

{ //重寫doPost方法

publicvoiddoPost(HttpServletRequestreq,HttpServletResponseres)throwsServletException,IOException

{ res.setContentType("text/html;charset=GB2312");//設置響應的MIME類型

PrintWriterout=res.getWriter(); //獲得向客戶發送數據的輸出流

byteb1[]=req.getParameter("myname").getBytes("ISO-8859-1");

//獲得客戶端提交的用戶名

//參數

Strings1=newString(b1);

Strings2=req.getParameter("pass"); //獲得客戶端提交的密碼參數

out.println("<HTML><HEAD></HEAD><BODY>");

out.println("<H3>輸出客戶端的信息</H3><BR>");

if(s2.equals("abc"))//密碼為“abc”

{out.println("用戶名:"+s1+"<BR>");

out.println("登錄成功!<BR>");

}

else

{

out.print("<PALIGN="+"CENTER"+">");

out.println("<AHREF="+"c9_5.jsp"+">密碼寫錯重新輸入</A></P>");

}

out.println("</BODY></HTML>");

}

//重寫doGet方法

publicvoiddoGet(HttpServletRequestreq,HttpServletResponseres) throwsServletException,IOException

{

doPost(req,res);

}

}

該示例程序的運行結果如圖9.13和圖9.14所示。

圖9.13c9_5.jsp的運行結果

圖9.14Servlet的運行結果

運用JSP/Servlet技術實現Web動態交互,主要采用模型Ⅰ(JSP+JavaBean)和模型Ⅱ(JSP+Servlet+JavaBean)。本節分別介紹這兩種模型,并比較兩種模型的優缺點。

9.4兩種模式的JSP技術9.4.1JSP+JavaBean

模型Ⅰ的體系結構如圖9.15所示,稱之為JSP+JavaBean模型。其工作原理是:當瀏覽器發出請求時,JSP接收請求訪問JavaBean。若需要訪問數據庫或后端服務器時,則通過JavaBean連接數據庫或后端服務器,進行相應的處理。JavaBean將處理的結果數據提交給JSP。JSP提取結果并重新組織后,動態產生HTML頁面,返回給瀏覽器。用戶從顯示的頁面中得到交互的結果。

圖9.15JSP+JavaBean模型模型Ⅰ充分利用了JSP技術易于開發動態網頁的特點,頁面顯示層的任務由JSP承擔(但它也含有事務邏輯層的內容),JavaBean主要負責事務邏輯層和數據層的工作。JSP+JavaBean模型依靠一個或幾個JavaBean組件實現具體的應用功能,生成動態內容,其最大的特點是簡單。9.4.2JSP+Servlet+JavaBean

模型Ⅱ的體系結構如圖9.16所示,稱之為JSP+Servlet+JavaBean模型。它是一種采用基于模型視圖控制器(Model-View-Controller)的設計模型,即MVC模型。該模型將JSP程序的功能分為三個層次:Model(模型)層、View(視圖)層和Controller(控制層)。Model層用來實現業務邏輯,包含了Web應用程序功能的核心,負責存儲與應用程序相關的數據;View層用于用戶界面的顯示,它可以訪問模型的數據,但不能改變這些數據;Controller層主要負責View層和Model層之間的控制關系。具體實現時,JavaBean作為模型層,Servlet作為控制層,JSP作為視圖層。每層的作用如下:

(1)

JavaBean作為Model層,實現各個具體的應用邏輯和功能。

(2)

Servlet作為Controller層負責處理HTTP請求,包括:

①對輸入數據的檢查和轉換。

②通過JavaBean訪問數據庫。

③初始化JSP中要用到的JavaBean或對象。

④根據處理中不同分支和執行的結果(如成功或失敗),決定轉向哪個JSP等。

(3)

JSP作為用戶界面程序(View),負責生成交互后返回的頁面。它主要通過信息共享,獲取Servlet生成的對象或JavaBean,從中取出相關數據,插入到HTML頁面中。

該模型的工作原理是:所有的請求都被發送給作為控制器的Servlet。Servlet接受請求,并根據請求信息將它們分發給適當的JSP來響應;同時Servlet還根據JSP的需求生成JavaBean的對象并輸出給JSP環境。JSP可以通過直接調用方法或使用UseBean的自定義標簽得到JavaBean中的數據。

這種設計模型通過JSP和Servlet的合作來實現交互處理,很好地實現了表示層、事務邏輯層和數據層的分離。

圖9.16JSP+Servlet+JavaBean模型9.4.3兩種模式的比較

從以上對兩種模型的陳述可以看出,模型Ⅰ和模型Ⅱ的整體結構都比較清晰,易于實現。它們的基本思想都是實現表示層、事務邏輯層和數據層的分離。這樣的分層設計便于系統的維護和修改。兩種模型的主要區別在于:

(1)處理流程的主控部分不同。模型Ⅰ利用JSP作為主控部分,將用戶的請求、JavaBean和響應有效地銜接起來。模型Ⅱ利用Servlet作為主控部分,將用戶的請求、JavaBean、JSP和響應有效地銜接起來。

(2)實現表示層、事務邏輯層和數據層的分離的程度不同。模型Ⅱ比模型Ⅰ有更徹底的分離效果。當事務邏輯比較復雜、分支較多或者需要涉及多個JavaBean組件時,模型Ⅰ常常會導致JSP文件中嵌入大量的腳本或者Java代碼。特別是在大型項目開發中,由于頁面設計與邏輯處理分別由不同的專業人員承擔,如果JSP有相當一部分處理邏輯和頁面描述被混在一起,這就有可能引起分工不清,不利于兩個部分的獨立開發和維護,影響項目的施工和管理。在模型Ⅱ中,由Servlet處理HTTP請求,JavaBean承擔事務邏輯處理,JSP僅負責生成網頁的工作,所以,出現層的混合問題比較輕,適合于不同專長的專業人員獨立開發Web項目中的各層功能。

(3)適用于動態交互處理的需求不同。當事務邏輯比較復雜、分支較多或者需要涉及多個JavaBean組件時,由于模型Ⅱ比模型Ⅰ具有更清晰的頁面表現,更明確的開發模塊的劃分,所以使用模型Ⅱ比較適合。然而,模型Ⅱ需要編寫Servlet程序,Servlet程序需要的工具是Java集成開發環境,編程工作量比較大。而對于簡單的交互處理,利用模型Ⅰ,JSP主要是使用HTML工具開發,然后再插入少量的編程代碼就可以實現動態交互。在這種情況下,使用模型Ⅰ更為方便快捷。模型Ⅰ與模型Ⅱ這兩種用于開發Web應用的方法都有很好的實用性。當然,實現動態交互的Web應用,不限于這兩種模型。在實際開發Web應用的過程中,要根據系統的特點、客戶需求及處理邏輯的特性,選擇合適的模型,力求使整個應用的體系結構更趨合理,從而實現不同的交互處理。

在第8章我們已經提供了一個用JSP+JavaBean開發的留言板案例,這一節我們仍然利用第8章的案例,開發一個JSP+Servlet+JavaBean的留言板,其目的是通過使用兩種不同的模型來比較它們之間的區別。9.5Servlet模式的留言板案例

JSP+Servlet+JavaBean的留言板的界面如圖9.17所示,它與圖8.16完全相同。用戶需要輸入留言的標題、留言人的姓名、留言人的E-mail和留言內容。點擊“提交留言”按鈕后,要將留言人輸入的信息保存到數據庫。因此,我們建立一個Message數據庫,并建立一個MessageTable表來存放留言人輸入的信息。MessageTable表的結構與表8.2也完全相同。系統設計如下。

圖9.17Messgages.html用戶界面在Eclipse開發環境中,JSP+Servlet+JavaBean模型留言板的所有程序(Messgages.html、AddMessageServlet.java、ViewMessages_servlet.java、MessageDataBean.java和viewMessages.jsp)的存儲位置如圖9.18所示。

圖9.18留言板程序的所有存儲位置9.5.1填寫留言的界面

填寫留言界面的示例程序為Messgages.html,它的執行效果如圖9.17所示。該程序與第8章提供的留言界面的示例程序Messgages.html基本相同,只需要修改form中的action的內容與“查看留言”的超鏈接。點擊留言界面的“提交留言”按鈕,使用Servlet(AddMessageServlet)接收HTTP請求。

【示例程序Messgages.html】填寫留言的界面程序。

<!--Messgages.html-->

<HTML><HEAD>

<TITLE>留言板</TITLE></HEAD>

<BODY><CENTER>留言板</CENTER>

<FORMACTION="AddMessageServlet">

<TABLEborder=1ALIGN="CENTER">

<TR>

<TD>姓名:</TD>

<TD><INPUTTYPE="text"name="name"size=25></TD>

</TR>

<TR><TD>E-mail:</TD><TD><INPUTTYPE="text"name="email"size=25></TD></TR>

<TR><TD>主題:</TD><TD><INPUTTYPE="text"name="title"size=25></TD></TR>

<TR><TD>留言:</TD><TD><textareaname="content"rows=7cols=25></textarea></TD></TR>

<TR>

<TDcolspan=3>

<TABLEALIGN="CENTER"width="100%"cellspacing="0"cellpadding="0"></TD>

<TR>

<TDALIGN="CENTER"><INPUTTYPE="submit"VALUE="提交留言"></TD>

<TDALIGN="CENTER"><AHREF="ViewMessages_servlet">

<FORTsize=2>查看留言</FORT></A></TD>

<TDALIGN="CENTER"><INPUTTYPE="reset"VALUE="重新填寫"></TD>

</TR>

</TABLE></TD>

</TR></TABLE>

</FORM>

</BODY></HTML>9.5.2接受請求保存留言的Servlet

該Servlet(AddMessageServlet)作為控制器,完成如下工作:

(1)接受瀏覽器發送的所有請求。

(2)建立與數據庫的連接。

(3)將留言板中需要存入數據庫的信息存入數據庫。

(4)對于留言板中“查看留言”的請求,它通過訪問另一個Servlet(ViewMessages_servlet)響應用戶的請求。

【示例程序AddMessageServlet.java】保存留言的Servlet程序。

packagemessage;

importjavax.servlet.*;

importjavax.servlet.http.*;

importjava.sql.*;

importjava.io.*;

publicclassAddMessageServletextendsjavax.servlet.http.HttpServletimplementsjavax.servlet.Servlet

{//建立數據庫的連接

publicAddMessageServlet(){

StringJDriver="sun.jdbc.odbc.JdbcOdbcDriver"; //聲明JDBC驅動程序對象

StringconURL="jdbc:odbc:message"; //定義JDBC的URL對象

try{

Class.forName(JDriver); //加載JDBC-ODBC橋驅動程序

con=DriverManager.getConnection(conURL); //連接數據庫URL

}

catch(Exceptione)

{System.err.println(e.getMessage());}

}

privateConnectioncon;

/*接收GET請求*/

protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)

throwsServletException,IOException

{

byteb1[]=request.getParameter("name").getBytes("ISO-8859-1");

Stringna=newString(b1);

byteb2[]=request.getParameter("email").getBytes("ISO-8859-1");

Stringem=newString(b2);

byteb3[]=request.getParameter("title").getBytes("ISO-8859-1");

Stringti=newString(b3);

byteb4[]=request.getParameter("content").getBytes("ISO-8859-1");

Stringco=newString(b4);

if(na==null)na="";

if(ti==null)ti="";

if(co==null)co="";

if(em==null)em="";

try

{//將獲得的留言信息裝入數據庫

PreparedStatementstm=con.prepareStatement("insertintoMessageTablevalues(?,?,?,?)");

stm.setString(1,ti);

stm.setString(2,na);

if(em.length()==0)stm.setString(3,null);

elsestm.setString(3,em);

stm.setString(4,co);

try{ stm.executeQuery(); }

catch(Exceptione){ }

//對留言板中“查看留言”的請求,服務器端重定向給另一個Servlet來控制

RequestDispatcherrequestDispatcher=request.getRequestDispatcher("ViewMessages_servlet");

requestDispatcher.forward(request,response);

}

catch(Exceptione){e.printStackTrace();}

}

/*接收POST請求*/

protectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)

throwsServletException,IOException

{doGet(request,response);}

}程序說明:

requestDispatcher=request.getRequestDispatcher

("ViewMessages_servlet")語句表示生成一個RequestDispatcher類的對象,并將第一個Servlet的控制權轉交給第二個Servlet(ViewMessages_servlet)。requestDispatcher.forward(request,response)語句表示服務器端的重定向方式。

RequestDispatcher是一個Web資源的包裝器,可以用來把當前的request傳遞到該資源,或者把新的資源包括到當前響應中。RequestDispatcher的forward()方法將當前的request和response重定向到該RequestDispacher指定的資源,它只在服務器端起作用。使用forward()方法時,Servletengine傳遞HTTP請求從當前的Servlet或JSP到另外一個Servlet、JSP或普通的HTML文件。因為完成一個邏輯操作往往需要跨越多個步驟,每一步驟完成相應的處理后轉向到下一個步驟,所以,這種方式在實際項目中大量使用。使用時應該注意,只有在尚未向客戶端輸出響應時才可以調用forward()方法;調用forward()方法時,如果頁面緩存不為空,則在轉向前將自動清除緩存,否則將拋出一個IllegalStateException異常。9.5.3查看留言的Servlet

該Servlet作為控制器,完成如下工作:

(1)接受AddMessageServlet請求。

(2)建立與數據庫的連接。

(3)從數據庫中讀取存入留言板的信息。這些信息正是留言板界面中“查看留言”按鈕所提供的信息。

(4)將留言信息提交給JavaBean(MessageDataBean),再由JavaBean對象保留到Collection對象中。具體內容見下面“表示留言板數據的JavaBean”。

(5)把Collection對象保存到request中,然后訪問顯示留言的JSP(viewMessages.jsp)頁面。

【示例程序ViewMessages_servlet.java】實現“查看留言”請求的Servlet。

packagemessage;

importjavax.servlet.*;

importjavax.servlet.http.*;

importjava.sql.*;

importjava.util.ArrayList;

importjava.util.Collection;

importjava.io.*;

publicclassViewMessages_servletextendsjavax.servlet.http.HttpServletimplementsjavax.servlet.Servlet

{ //連接數據庫

publicViewMessages_servlet()

{

StringJDriver="sun.jdbc.odbc.JdbcOdbcDriver"; //聲明JDBC驅動程序對象

StringconURL="jdbc:odbc:message"; //定義JDBC的URL對象

try{

Class.forName(JDriver); //加載JDBC-ODBC橋驅動程序

con=DriverManager.getConnection(conURL); //連接數據庫URL

}

catch(Exceptione)

{System.err.println(e.getMessage());}

}

privateConnectioncon;

//得到GET請求,從數據庫中讀出留言信息

publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)

throwsIOException,ServletException

{

Collectionret=newArrayList();

try

{

Statementstm=con.createStatement();

ResultSetresult=stm.executeQuery("selectcount(*)fromMessageTable"); intmessage_count=0;

if(result.next())

{

message_count=result.getInt(1);

result.close();

}

if(message_count>0)

{

result=stm.executeQuery("select*fromMessageTable");

while(result.next())

{

Stringtitle=result.getString("title");

Stringname=result.getString("name");

Stringemail=result.getString("email");

Stringcontent=result.getString("co

溫馨提示

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

評論

0/150

提交評論