在Servlet之前Java服務(wù)器端編程使用C或Perl編寫復(fù)雜的CGI來(lái)實(shí)現(xiàn)來(lái)完成,Java Servlet API的出現(xiàn)極大地簡(jiǎn)化了Java在服務(wù)器端編程的復(fù)雜性同時(shí)能最大限度地發(fā)揮Java的的整體優(yōu)勢(shì)。
在這個(gè)專題中我們由淺入深地向大家介紹Java Servlet的基本特征、開發(fā)環(huán)境的配置以及Servlet的一些主要API類。
Servlet是一種獨(dú)立于平臺(tái)和協(xié)議的服務(wù)器端的Java應(yīng)用程序,可以生成動(dòng)態(tài)的Web頁(yè)面
一、概述
Servlet是一種獨(dú)立于平臺(tái)和協(xié)議的服務(wù)器端的Java應(yīng)用程序,可以生成動(dòng)態(tài)的Web頁(yè)面。
Servlet是位于Web 服務(wù)器內(nèi)部的服務(wù)器端的Java應(yīng)用程序,與傳統(tǒng)的從命令行啟動(dòng)的Java應(yīng)用程序不同,Servlet由Web服務(wù)器進(jìn)行加載,該Web服務(wù)器必須包含支持Servlet的Java虛擬機(jī)。
Java Servlet 與 Applet 的比較:
相似之處:
* 它們不是獨(dú)立的應(yīng)用程序,沒有main()方法。
* 它們不是由用戶或程序員調(diào)用,而是由另外一個(gè)應(yīng)用程序(容器)調(diào)用。
* 它們都有一個(gè)生存周期,包含init()和destroy()方法。
不同之處:
* Applet具有很好的圖形界面(AWT),與瀏覽器一起,在客戶端運(yùn)行。
* Servlet 則沒有圖形界面,運(yùn)行在服務(wù)器端。
Java Servlet 與 CGI(Common Gateway Interface) 的比較:
與傳統(tǒng)的CGI和許多其他類似CGI的技術(shù)相比,Java Servlet具有更高的效率,更容易使用,功能更強(qiáng)大,具有更好的可移植性,更節(jié)省投資。在未來(lái)的技術(shù)發(fā)展過(guò)程中,Servlet有可能徹底取代CGI。
* 高效
在傳統(tǒng)的CGI中,每個(gè)請(qǐng)求都要啟動(dòng)一個(gè)新的進(jìn)程,如果CGI程序本身的執(zhí)行時(shí)間較短,啟動(dòng)進(jìn)程所需要的開銷很可能反而超過(guò)實(shí)際執(zhí)行時(shí)間。而在Servlet中,每個(gè)請(qǐng)求由一個(gè)輕量級(jí)的Java線程處理(而不是重量級(jí)的操作系統(tǒng)進(jìn)程)。
在傳統(tǒng)CGI中,如果有N個(gè)并發(fā)的對(duì)同一CGI程序的請(qǐng)求,則該CGI程序的代碼在內(nèi)存中重復(fù)裝載了N次;而對(duì)于Servlet,處理請(qǐng)求的是N個(gè)線程,只需要一份Servlet類代碼。在性能優(yōu)化方面,Servlet也比CGI有著更多的選擇。
* 方便
Servlet提供了大量的實(shí)用工具例程,例如自動(dòng)地解析和解碼HTML表單數(shù)據(jù)、讀取和設(shè)置HTTP頭、處理Cookie、跟蹤會(huì)話狀態(tài)等。
* 功能強(qiáng)大
在Servlet中,許多使用傳統(tǒng)CGI程序很難完成的任務(wù)都可以輕松地完成。例如,Servlet能夠直接和Web服務(wù)器交互,而普通的CGI程序不能。Servlet還能夠在各個(gè)程序之間共享數(shù)據(jù),使得數(shù)據(jù)庫(kù)連接池之類的功能很容易實(shí)現(xiàn)。
* 可移植性好
Servlet用Java編寫,Servlet API具有完善的標(biāo)準(zhǔn)。因此,為IPlanet Enterprise Server寫的Servlet無(wú)需任何實(shí)質(zhì)上的改動(dòng)即可移植到Apache、Microsoft IIS或者WebStar。幾乎所有的主流服務(wù)器都直接或通過(guò)插件支持Servlet。
* 節(jié)省投資
不僅有許多廉價(jià)甚至免費(fèi)的Web服務(wù)器可供個(gè)人或小規(guī)模網(wǎng)站使用,而且對(duì)于現(xiàn)有的服務(wù)器,如果它不支持Servlet的話,要加上這部分功能也往往是免費(fèi)的(或只需要極少的投資)。
Java Servlet 與 JSP(JavaServer Pages) 的比較:
JavaServer Pages(JSP)是一種實(shí)現(xiàn)普通靜態(tài)HTML和動(dòng)態(tài)HTML混合編碼的技術(shù),JSP并沒有增加任何本質(zhì)上不能用Servlet實(shí)現(xiàn)的功能。但是,在JSP中編寫靜態(tài)HTML更加方便,不必再用println語(yǔ)句來(lái)輸出每一行HTML代碼。更重要的是,借助內(nèi)容和外觀的分離,頁(yè)面制作中不同性質(zhì)的任務(wù)可以方便地分開:比如,由頁(yè)面設(shè)計(jì)者進(jìn)行HTML設(shè)計(jì),同時(shí)留出供Servlet程序員插入動(dòng)態(tài)內(nèi)容的空間。
Java Servlet API 2.2 簡(jiǎn)介
Java Servlet API 2.2 的類和接口組成兩個(gè)Java 包,即:javax.servlet 和 javax.servlet.http(還包括javax.servlet.jsp包,不在本篇文章討論范圍之內(nèi))。
javax.servlet 包提供了控制 Servlet 生命周期所必需的 Servlet 接口,是編寫 Servlet 時(shí)必須要實(shí)現(xiàn)的。
javax.servlet.http 包提供了從Servlet 接口派生出的專門用于處理 HTTP 請(qǐng)求的抽象類和一般的工具類。所有的Servlet 對(duì)象都要實(shí)現(xiàn)Servlet 接口,大多數(shù)情況下是作為已經(jīng)實(shí)現(xiàn)了Servlet 接口的javax.servlet.GenericServlet 和 javax.servlet.http.HttpServlet 這兩個(gè)抽象類的子類來(lái)間接實(shí)現(xiàn)Servlet 接口。
javax.servlet 包定義的類和接口:
interface RequestDispatcher
//定義一種對(duì)象,用于從客戶接受請(qǐng)求,并將請(qǐng)求發(fā)送到服務(wù)器上任何指定的資源,如一個(gè)Servlet 、JSP 或 HTML 文件。
interface Servlet
//定義了所有 Servlet 必須實(shí)現(xiàn)的方法。
interface ServletConfig
//定義Servlet config 對(duì)象,由Servlet 引擎用在 Servlet 初始化時(shí),向 Servlet 傳遞信息。
interface ServletContext
//定義了一系列方法,以便Servlet與其運(yùn)行的環(huán)境通信。
interface ServletRequest
//定義了用于向Servlet傳遞客戶請(qǐng)求信息的對(duì)象。
interface ServletResponse
//定義了一個(gè)對(duì)象,由Servlet用于向客戶發(fā)送響應(yīng)。
interface SingleThreadModel
//用于保證Servlet在任一時(shí)刻,只處理一個(gè)請(qǐng)求。
class GenericServlet
//繼承Servlet接口,定義了一個(gè)通用的,與協(xié)議無(wú)關(guān)的Servlet。
class ServletInputStream
//定義了一個(gè)輸入流,用于由Servlet從中讀取客戶請(qǐng)求的二進(jìn)制數(shù)據(jù)。
class ServletOutputStream
//定義了一個(gè)輸出流,用于由Servlet向客戶發(fā)送二進(jìn)制數(shù)據(jù)。
class ServletException
//定義了一個(gè)當(dāng)Servlet遇到問(wèn)題時(shí)可以拋出的異常。
class UnavailableException
//定義了一種異常,用于由Servlet指明它永遠(yuǎn)或暫時(shí)不可用。
javax.servlet.http 包定義的類和接口:
interface HttpServletRequest
//繼承了ServletRequest 接口,為HTTPServlet 提供請(qǐng)求信息。
interface HttpServletResponse
//繼承了ServletResponse 接口,為HTTPServlet 輸出響應(yīng)信息提供支持。
interface HttpSession
//為維護(hù) HTTP 用戶的會(huì)話狀態(tài)提供支持。
interface HttpSessionBindingListener
//使得某對(duì)象在加入一個(gè)會(huì)話或從會(huì)話中刪除時(shí)能夠得到通知。
interface HttpSessionContext
//由Servlet 2.1 定義,該對(duì)象在新版本已不被支持。
class Cookie
//用在Servlet 中使用Cookie 技術(shù)
class HttpServlet
//定義了一個(gè)抽象類,繼承 GenericServlet 抽象類,應(yīng)被 HTTPServlet 繼承。
class HttpSessionBindingEvent
//定義了一種對(duì)象,當(dāng)某一個(gè)實(shí)現(xiàn)了HttpSessionBindingListener接口的對(duì)象被加入會(huì)話或從會(huì)//話中刪除時(shí),會(huì)收到該類對(duì)象的一個(gè)句柄
class HttpUtils
//提供了一系列便于編寫HTTPServlet 的方法。
下面主要介紹javax.servlet.http提供的HTTP Servlet應(yīng)用編程接口。
HTTP Servlet 使用一個(gè) HTML 表格來(lái)發(fā)送和接收數(shù)據(jù)。要?jiǎng)?chuàng)建一個(gè) HTTP Servlet,請(qǐng)擴(kuò)展 HttpServlet 類, 該類是用專門的方法來(lái)處理 HTML 表格的 GenericServlet 的一個(gè)子類。 HTML 表單是由 <FORM> 和 </FORM> 標(biāo)記定義的。表單中典型地包含輸入字段(如文本輸入字段、復(fù)選框、單選按鈕和選擇列表)和用于提交數(shù)據(jù)的按鈕。當(dāng)提交信息時(shí),它們還指定服務(wù)器應(yīng)執(zhí)行哪一個(gè)Servlet(或其它的程序)。 HttpServlet 類包含 init()、destroy()、service() 等方法。其中 init() 和 destroy() 方法是繼承的。
(1) init() 方法
在 Servlet 的生命期中,僅執(zhí)行一次 init() 方法。它是在服務(wù)器裝入 Servlet 時(shí)執(zhí)行的。 可以配置服務(wù)器,以在啟動(dòng)服務(wù)器或客戶機(jī)首次訪問(wèn) Servlet 時(shí)裝入 Servlet。 無(wú)論有多少客戶機(jī)訪問(wèn) Servlet,都不會(huì)重復(fù)執(zhí)行 init() 。
缺省的 init() 方法通常是符合要求的,但也可以用定制 init() 方法來(lái)覆蓋它,典型的是管理服務(wù)器端資源。 例如,可能編寫一個(gè)定制 init() 來(lái)只用于一次裝入 GIF 圖像,改進(jìn) Servlet 返回 GIF 圖像和含有多個(gè)客戶機(jī)請(qǐng)求的性能。另一個(gè)示例是初始化數(shù)據(jù)庫(kù)連接。缺省的 init() 方法設(shè)置了 Servlet 的初始化參數(shù),并用它的 ServletConfig 對(duì)象參數(shù)來(lái)啟動(dòng)配置, 因此所有覆蓋 init() 方法的 Servlet 應(yīng)調(diào)用 super.init() 以確保仍然執(zhí)行這些任務(wù)。在調(diào)用 service() 方法之前,應(yīng)確保已完成了 init() 方法。
(2) service() 方法
service() 方法是 Servlet 的核心。每當(dāng)一個(gè)客戶請(qǐng)求一個(gè)HttpServlet 對(duì)象,該對(duì)象的service() 方法就要被調(diào)用,而且傳遞給這個(gè)方法一個(gè)"請(qǐng)求"(ServletRequest)對(duì)象和一個(gè)"響應(yīng)"(ServletResponse)對(duì)象作為參數(shù)。 在 HttpServlet 中已存在 service() 方法。缺省的服務(wù)功能是調(diào)用與 HTTP 請(qǐng)求的方法相應(yīng)的 do 功能。例如, 如果 HTTP 請(qǐng)求方法為 GET,則缺省情況下就調(diào)用 doGet() 。Servlet 應(yīng)該為 Servlet 支持的 HTTP 方法覆蓋 do 功能。因?yàn)?HttpServlet.service() 方法會(huì)檢查請(qǐng)求方法是否調(diào)用了適當(dāng)?shù)奶幚矸椒ǎ槐匾采w service() 方法。只需覆蓋相應(yīng)的 do 方法就可以了。
當(dāng)一個(gè)客戶通過(guò)HTML 表單發(fā)出一個(gè)HTTP POST請(qǐng)求時(shí),doPost()方法被調(diào)用。與POST請(qǐng)求相關(guān)的參數(shù)作為一個(gè)單獨(dú)的HTTP 請(qǐng)求從瀏覽器發(fā)送到服務(wù)器。當(dāng)需要修改服務(wù)器端的數(shù)據(jù)時(shí),應(yīng)該使用doPost()方法。
當(dāng)一個(gè)客戶通過(guò)HTML 表單發(fā)出一個(gè)HTTP GET請(qǐng)求或直接請(qǐng)求一個(gè)URL時(shí),doGet()方法被調(diào)用。與GET請(qǐng)求相關(guān)的參數(shù)添加到URL的后面,并與這個(gè)請(qǐng)求一起發(fā)送。當(dāng)不會(huì)修改服務(wù)器端的數(shù)據(jù)時(shí),應(yīng)該使用doGet()方法。
Servlet的響應(yīng)可以是下列幾種類型:
一個(gè)輸出流,瀏覽器根據(jù)它的內(nèi)容類型(如text/HTML)進(jìn)行解釋。
一個(gè)HTTP錯(cuò)誤響應(yīng), 重定向到另一個(gè)URL、servlet、JSP。
(3) destroy() 方法
destroy() 方法僅執(zhí)行一次,即在服務(wù)器停止且卸裝Servlet 時(shí)執(zhí)行該方法。典型的,將 Servlet 作為服務(wù)器進(jìn)程的一部分來(lái)關(guān)閉。缺省的 destroy() 方法通常是符合要求的,但也可以覆蓋它,典型的是管理服務(wù)器端資源。例如,如果 Servlet 在運(yùn)行時(shí)會(huì)累計(jì)統(tǒng)計(jì)數(shù)據(jù),則可以編寫一個(gè) destroy() 方法,該方法用于在未裝入 Servlet 時(shí)將統(tǒng)計(jì)數(shù)字保存在文件中。另一個(gè)示例是關(guān)閉數(shù)據(jù)庫(kù)連接。
當(dāng)服務(wù)器卸裝 Servlet 時(shí),將在所有 service() 方法調(diào)用完成后,或在指定的時(shí)間間隔過(guò)后調(diào)用 destroy() 方法。一個(gè)Servlet 在運(yùn)行service() 方法時(shí)可能會(huì)產(chǎn)生其它的線程,因此請(qǐng)確認(rèn)在調(diào)用 destroy() 方法時(shí),這些線程已終止或完成。
(4) GetServletConfig()方法
GetServletConfig()方法返回一個(gè) ServletConfig 對(duì)象,該對(duì)象用來(lái)返回初始化參數(shù)和ServletContext。ServletContext 接口提供有關(guān)servlet 的環(huán)境信息。
(5) GetServletInfo()方法
GetServletInfo()方法是一個(gè)可選的方法,它提供有關(guān)servlet 的信息,如作者、版本、版權(quán)。
當(dāng)服務(wù)器調(diào)用sevlet 的Service()、doGet()和doPost()這三個(gè)方法時(shí),均需要 "請(qǐng)求"和"響應(yīng)"對(duì)象作為參數(shù)。"請(qǐng)求"對(duì)象提供有關(guān)請(qǐng)求的信息,而"響應(yīng)"對(duì)象提供了一個(gè)將響應(yīng)信息返回給瀏覽器的一個(gè)通信途徑。
javax.servlet 軟件包中的相關(guān)類為ServletResponse和ServletRequest,而javax.servlet.http 軟件包中的相關(guān)類為HttpServletRequest 和 HttpServletResponse。
Servlet 通過(guò)這些對(duì)象與服務(wù)器通信并最終與客戶機(jī)通信。Servlet 能通過(guò)調(diào)用"請(qǐng)求"對(duì)象的方法獲知客戶機(jī)環(huán)境,服務(wù)器環(huán)境的信息和所有由客戶機(jī)提供的信息。Servlet 可以調(diào)用"響應(yīng)"對(duì)象的方法發(fā)送響應(yīng),該響應(yīng)是準(zhǔn)備發(fā)回客戶機(jī)的。
進(jìn)行Servlet開發(fā)所需要的基本環(huán)境是JSDK以及一個(gè)支持Servlet的Web服務(wù)器
編寫Servlet所需要的開發(fā)環(huán)境
進(jìn)行Servlet開發(fā)所需要的基本環(huán)境是JSDK以及一個(gè)支持Servlet的Web服務(wù)器。
1.JSDK(Java Servlet Development Kit)
JSDK包含了編譯Servlet應(yīng)用程序所需要的Java類庫(kù)以及相關(guān)的文檔。對(duì)于利用Java 1.1進(jìn)行開發(fā)的用戶,必須安裝JSDK。JSDK已經(jīng)被集成進(jìn)Java 1.2 Beta版中,如果利用Java 1.2或以上版本進(jìn)行開發(fā),則不必安裝JSDK。
JSDK可以在Javasoft公司的站點(diǎn)免費(fèi)下載,其地址是: http://www.sun.com/software/jwebserver/redirect.html
2.支持Servlet的Web服務(wù)器
Servlet需要運(yùn)行在支持Servlet的Web服務(wù)器上。目前支持Servlet的Web服務(wù)器SUN公司的JSWDK1.0.1。如果現(xiàn)有的Web服務(wù)器不支持Servlet,則可以利用一些第三方廠商的服務(wù)器增加件(add-ons)來(lái)使Web服務(wù)器支持Servlet,這其中Live Software公司(http://www.livesoftware.com)提供了一種稱為JRun的產(chǎn)品,通過(guò)安裝JRun的相應(yīng)版本,可以使Microsoft IIS和Netscape Web Server支持Servlet。
開發(fā)Servlet的過(guò)程
下面舉一個(gè)簡(jiǎn)單的Servlet 例子來(lái)說(shuō)明開發(fā)Servlet的過(guò)程。
1.編寫Servlet代碼
Java Servlet API是一個(gè)標(biāo)準(zhǔn)的Java擴(kuò)展程序包,包含兩個(gè)Package∶javax.servlet和javax.servlet.http。對(duì)于想開發(fā)基于客戶自定義協(xié)議的開發(fā)者,應(yīng)該使用javax.servlet包中的類與界面;對(duì)于僅利用HTTP協(xié)議與客戶端進(jìn)行交互的開發(fā)者,則只需要使用javax.servlet.http包中的類與界面進(jìn)行開發(fā)即可。
下面是一個(gè)servlet的程序代碼(RequestInfoExample.java)∶
import java.io.*;
import java.servlet.*;
import javax.servlet.*;
public class RequestInfoExample extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<head>");
out.println("<title>Request Information Example</title>");
out.println("</head>");
out.println("<body>");
out.println("<h3>Request Information Example</h3>");
out.println("Method: " + request.getMethod());
out.println("Request URI: " + request.getRequestURI());
out.println("Protocol: " + request.getProtocol());
out.println("PathInfo: " + request.getPathInfo());
out.println("Remote Address: " + request.getRemoteAddr());
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request, HttpServletResponse res)
throws IOException, ServletException
{
doGet(request, response);
}
}
該servlet實(shí)現(xiàn)如下功能∶當(dāng)用戶通過(guò)瀏覽器訪問(wèn)該servlet時(shí),該servlet向客戶端瀏覽器返回一個(gè)HTML頁(yè)面∶
------------------------------------------------
Request Information Example
Method: GET
Request URI: /examples/servlet/RequestInfoExample
Protocol: HTTP/1.1
Path Info: null
Remote Address: 127.0.0.1
--------------------------------------------------
有關(guān)servlet程序說(shuō)明∶
* 基于HTTP協(xié)議的servlet必須引入javax.servlet和javax.servlet.http包;
* HelloServlet從類HttpServlet派生,HttpServlet是GenericServlet的一個(gè)派生類,通過(guò) GenericServlet實(shí)現(xiàn)了Servlet界面。HttpServlet為基于HTTP協(xié)議的servlet提供了基本的支持;
* HttpServletRequest對(duì)象包含了客戶端請(qǐng)求的信息,可以通過(guò)該參數(shù)取得客戶端的一些信息(例如IP地址、瀏覽器類型等)以及HTTP請(qǐng)求類型(例如GET、HEAD、POST、PUT等);HttpServletResponse對(duì)象用于完成Servlet與客戶端的交互,通過(guò)調(diào)用HttpServletResponse.getOutputStream()客戶取得向客戶端進(jìn)行輸出的輸出流,向客戶端發(fā)送HTML頁(yè)面。
* 編寫了doGet方法,對(duì)于HTML POST 請(qǐng)求,調(diào)用Servlet 的doPost()方法。
2.編譯Servlet代碼
利用JDK 1.2.2 對(duì)Servlet代碼進(jìn)行編譯(假設(shè)Web服務(wù)器采用jswdk-1.0.1),其命令行為:
c:\> javac -d C:\jswdk-1.0.1\examples\WEB-INF\servlets HelloServlet.java
進(jìn)行編譯時(shí)必須確保HelloServlet.java 文件拷貝到目錄C:\jswdk-1.0.1\examples\WEB- INF\servlets 下面。
3.測(cè)試Servlet
現(xiàn)在可以對(duì)HelloServlet進(jìn)行測(cè)試了,打開瀏覽器,鍵入:
http://localhost:8080/examples/servlet/RequestInfoExample
其中l(wèi)ocalhost是安裝有jswdk-1.0.1的機(jī)器,8080是端口號(hào)。
希爾排序法基本思想是:取一個(gè)間隔,將長(zhǎng)序列分成若干短的子序列,對(duì)每個(gè)子序列進(jìn)行直插排序;然后逐漸縮小間隔,重復(fù)以上過(guò)程,直到間隔為1
前面我們學(xué)習(xí)了兩種插入排序法,但當(dāng)要排序的數(shù)組長(zhǎng)度越長(zhǎng)并且數(shù)值越不成順序,比較和交換的次數(shù)就越多,效率越低。因此D.L.Shell在1959年提出了縮小增量排序法(又叫希爾排序法),基本思想是:取一個(gè)間隔,將長(zhǎng)序列分成若干短的子序列,對(duì)每個(gè)子序列進(jìn)行直插排序;然后逐漸縮小間隔,重復(fù)以上過(guò)程,直到間隔為1。可以看到這種算法,較好的克服了直接插入排序法的不足。
下面是示例:
8 7 4 3 6 1 //是要排序的數(shù)值,我們以一半的長(zhǎng)度為間隔3
3 7 4 8 6 1 //第一次,取得3,小于前面的8,交換位置
3 6 4 8 7 1 //第二次,取得6,小于前面的7,交換位置
3 6 1 8 7 4 //第三次,取得1,小于前面的4,交換位置
1 6 3 4 7 8 //第四次,再縮小間隔,為2,取得1小于3,交換位置,取得7,大于前面的3,不變;取得8大于6,不變,取得4小于8,交換位置
1 3 4 6 7 8 //第五次,再縮小間隔,為1,取得6,大于1,不變;取得3小于6,交換位置;取得4,小于6,交換位置;取得7,大于前面的6,不變;取得8 ,大于7,不變
以下是代碼:
void paixu( ) //用希爾排序法,
{
int N=13;// N為前后紀(jì)錄位置的增量
for (int Z= N/2; Z; Z = Z/2)//每次縮小增量
for (int i = Z; i < N; i++)//從增兩大小開始比較
{
int temp = apai[i]; //將后一個(gè)備份
for (int j = i; j >= Z && temp < a[j - Z]; j -= Z) //與他在同一個(gè)子序列的數(shù)一個(gè)個(gè)的較
{
a[j] = a[j -Z]; //如果小于,就交換
}//end for
a[j] = temp; //找到合適的插入點(diǎn),放入其中
}//end for
}//end
我們?cè)賮?lái)看最后一種關(guān)于數(shù)組的排序方法,就是快速排序法,它是目前最快的一種排序的方法.它的基本思想是:通過(guò)一趟排序?qū)⒋判虻挠涗浄指顬楠?dú)立的兩部分,其中一部分記錄的數(shù)值均比另一部分記錄的數(shù)值小,然后繼續(xù)分別對(duì)這兩部分進(jìn)行排序,直到整個(gè)序列有序?yàn)橹?
具體做法: 任取待排序列的某個(gè)記錄(我們可以取第一個(gè)數(shù))作為基準(zhǔn),按照該數(shù)值大小,將整個(gè)序列分成兩個(gè)序列——左側(cè)的所有記錄的數(shù)值都比基準(zhǔn)小(或者相等),右側(cè)的都比基準(zhǔn)大,基準(zhǔn)則放在兩個(gè)子序列之間,顯然這時(shí)基準(zhǔn)放在了最后應(yīng)該放置的位置。分別對(duì)左右子序列重復(fù)上面的過(guò)程,直到最后所有的記錄都放在相應(yīng)的位置。
示例如下:
7 8 4 3 6 1 //是要排序的數(shù)值
1 8 4 3 6 //第一次,取得7,作為基準(zhǔn),1為right值,7>1,交換位置
1 4 3 6 8 //第二次, 8為left值,7<8,放到最后;
1 4 3 6 8 //第三次,left取得4,小于7,放到前面,
1 4 6 3 8 //第四次,right取6,小于7,放到前面
1 4 6 3 8 //第五次,left=right=3,小于7,放到前面,
1 4 6 3 7 8 //7放入合適位置,第一趟排序完成
//后面,在以1為基準(zhǔn)排序
……
//直到成功
代碼如下:
void paixu(int a[],int low,int high;)//用快速排序法
{
// low, high表示掃描的范圍
int pivot;//存放中心索引及其值的局部變量
int scanup,scandown,mid;//用于掃描的索引
if (high-low<=0) //如果數(shù)組中的元素少于兩個(gè),則返回
return;
else
if(high-low==1) //如果有兩個(gè)元素,對(duì)其進(jìn)行比較
{
if(apai[high]<apai[low]) //如果后一個(gè)比前一個(gè)小,
Swap(apai[low],apai[high]);//那么交換位置
return;
}//end if
mid=(low+high)/2;//取得中心索引
pivot=apai[mid];//將中間索引的值,賦給pivot
Swap(apai[mid],apai[low]);//交換pivot及低端元素的值
Scanup=low+1;
Scandown=high;//初始化掃描索引scanup和scandown
do{
//從低端子表向上掃描,當(dāng)scanup進(jìn)入高端子表或遇到大于pivot的元素時(shí)結(jié)束.
while(scanup<=scandown && apai[scanup]<=pivot)
scanup++;
//從高端子表向下掃描,當(dāng)scandown遇到小于或等于pivot的元素時(shí)結(jié)束
while(piovt<apai[scandown])
scandown--;
//如果兩個(gè)索引還在各自的子表中,則表示兩個(gè)元素錯(cuò)位,將兩個(gè)元素?fù)Q位
if(scanup<scandown)
Swap(apai[scanup],apai[scandown]);
}while(scanup<scandown);
//將pivot拷貝到scandown位置,分開兩個(gè)子表
apai[low]=apai[scandown];
apai[scandown]=pivot;
//如果低端子表(low至scandown-1)有2個(gè)或更多個(gè)元素,則進(jìn)行遞歸調(diào)用
if(low<scandown-1)
paixu(apai,low,scandown-1);
//如果高端子表(scandown+1至high) 有2個(gè)或更多個(gè)元素,則進(jìn)行遞歸調(diào)用
if(scandown+1<high)
paixu(apai, scandown+1, high);
}
關(guān)于排序的問(wèn)題已經(jīng)夠多了,就到這里吧,如果大家有興趣,可以看已看這方面的書.
HttpServlet 是從GenericServlet 繼承而來(lái),因此它具有GenericServlet 類似的方法和對(duì)象,是我們使用Servlet編程經(jīng)常用到的包,它支持HTTP 的post 和 get 等方法。
編程思路:下面的例子,運(yùn)行結(jié)果是輸出簡(jiǎn)單地返回客戶發(fā)送給服務(wù)器的請(qǐng)求行和頭部信息,以及一些可訪問(wèn)的HTTP 信息等。
SnoopServlet.java 的源代碼如下:
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.*;
import javax.servlet.http.*;
public class SnoopServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
PrintWriter out = response.getWriter();
response.setContentType("text/plain");
out.println("Snoop Servlet");
out.println();
out.println("Servlet init parameters:");
Enumeration e = getInitParameterNames();
while (e.hasMoreElements()) {
String key = (String)e.nextElement();
String value = getInitParameter(key);
out.println(" " + key + " = " + value);
}
out.println();
out.println("Context init parameters:");
ServletContext context = getServletContext();
Enumeration enum = context.getInitParameterNames();
while (enum.hasMoreElements()) {
String key = (String)enum.nextElement();
Object value = context.getInitParameter(key);
out.println(" " + key + " = " + value);
}
out.println();
out.println("Context attributes:");
enum = context.getAttributeNames();
while (enum.hasMoreElements()) {
String key = (String)enum.nextElement();
Object value = context.getAttribute(key);
out.println(" " + key + " = " + value);
}
out.println();
out.println("Request attributes:");
e = request.getAttributeNames();
while (e.hasMoreElements()) {
String key = (String)e.nextElement();
Object value = request.getAttribute(key);
out.println(" " + key + " = " + value);
}
out.println();
out.println("Servlet Name: " + getServletName());
out.println("Protocol: " + request.getProtocol());
out.println("Scheme: " + request.getScheme());
out.println("Server Name: " + request.getServerName());
out.println("Server Port: " + request.getServerPort());
out.println("Server Info: " + context.getServerInfo());
out.println("Remote Addr: " + request.getRemoteAddr());
out.println("Remote Host: " + request.getRemoteHost());
out.println("Character Encoding: " + request.getCharacterEncoding());
out.println("Content Length: " + request.getContentLength());
out.println("Content Type: "+ request.getContentType());
out.println("Locale: "+ request.getLocale());
out.println("Default Response Buffer: "+ response.getBufferSize());
out.println();
out.println("Parameter names in this request:");
e = request.getParameterNames();
while (e.hasMoreElements()) {
String key = (String)e.nextElement();
String[] values = request.getParameterValues(key);
out.print(" " + key + " = ");
for(int i = 0; i < values.length; i++) {
out.print(values[i] + " ");
}
out.println();
}
out.println();
out.println("Headers in this request:");
e = request.getHeaderNames();
while (e.hasMoreElements()) {
String key = (String)e.nextElement();
String value = request.getHeader(key);
out.println(" " + key + ": " + value);
}
out.println();
out.println("Cookies in this request:");
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
out.println(" " + cookie.getName() + " = "+ cookie.getValue());
}
}
out.println();
out.println("Request Is Secure: " + request.isSecure());
out.println("Auth Type: " + request.getAuthType());
out.println("HTTP Method: " + request.getMethod());
out.println("Remote User: " + request.getRemoteUser());
out.println("Request URI: " + request.getRequestURI());
out.println("Context Path: " + request.getContextPath());
out.println("Servlet Path: " + request.getServletPath());
out.println("Path Info: " + request.getPathInfo());
out.println("Path Trans: " + request.getPathTranslated());
out.println("Query String: " + request.getQueryString());
out.println();
HttpSession session = request.getSession();
out.println("Requested Session Id: " +
request.getRequestedSessionId());
out.println("Current Session Id: " + session.getId());
out.println("Session Created Time: " + session.getCreationTime());
out.println("Session Last Accessed Time: " +session.getLastAccessedTime());
out.println("Session Max Inactive Interval Seconds: " + session.getMaxInactiveInterval());
out.println();
out.println("Session values: ");
Enumeration names = session.getAttributeNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
out.println(" " + name + " = " + session.getAttribute(name));
}
}
}
編程技巧說(shuō)明:
程序輸出Init Parameters(初始化參數(shù))、Attribute names in this request、Parameter names in this request、Headers in this request、Cookies in this request 和 Session Information等信息。
方法getRequestURI返回的對(duì)象URI 是作為URL 的一部分,是去掉URL 中用于指定機(jī)器的那部分;方法getPathInfo 返回的字符串是客戶向Servlet 傳送的各種選項(xiàng),這些選項(xiàng)是跟在Servlet 的URL 之后的,方法getPathTranslated 返回的字符串是Servlet 的自己的絕對(duì)路徑名,SnoopServlet.class 文件位置是C:\jswdk-1.0.1\examples\WEB-INF\servlets\SnoopServlet.class,則方法getPathTranslated 返回的字符串值就是它。
在瀏覽器中輸入如下的地址:
http://localhost:8080/examples/servlet/SnoopServlet
則會(huì)輸出結(jié)果。
Cookie 是一小塊可以嵌入HTTP 請(qǐng)求和響應(yīng)中的數(shù)據(jù),它在服務(wù)器上產(chǎn)生,并作為響應(yīng)頭域的一部分返回用戶。瀏覽器收到包含Cookie 的響應(yīng)后,會(huì)把Cookie 的內(nèi)容用“關(guān)鍵字/值” 對(duì)的形式寫入到一個(gè)客戶端專為存放Cookie 的文本文件中。瀏覽器會(huì)把Cookie 及隨后產(chǎn)生的請(qǐng)求發(fā)給相同的服務(wù)器,服務(wù)器可以再次讀取Cookie 中存Cookie 可以進(jìn)行有效期設(shè)置,過(guò)期的Cookie 不會(huì)發(fā)送給服務(wù)器。
Servlet API 提供了一個(gè)Cookie 類,封裝了對(duì)Cookie 的一些操作。Servlet 可以創(chuàng)建一個(gè)新的Cookie,設(shè)置它的關(guān)鍵字、值及有效期等屬性,然后把Cookie 設(shè)置在HttpServletResponse 對(duì)象中發(fā)回瀏覽器,還可以從HttpServletRequest 對(duì)象中獲取Cookie。
編程思路:Cookie 在實(shí)際的Servlet 編程中是很廣泛應(yīng)用,下面是一個(gè)從Servlet 中獲取Cookie 信息的例子。
ShowCookies.java 的源代碼如下:
import javax.servlet.*;
import javax.servlet.http.*;
/**
* <p>This is a simple servlet that displays all of the
* Cookies present in the request
*/
public class ShowCookies extends HttpServlet
{
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, java.io.IOException
{
// Set the content type of the response
resp.setContentType("text/html;charset=gb2312");
// Get the PrintWriter to write the response
java.io.PrintWriter out = resp.getWriter();
// Get an array containing all of the cookies
Cookie cookies[] = req.getCookies();
// Write the page header
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet Cookie Information</title>");
out.println("</head>");
out.println("<body>");
if ((cookies == null) || (cookies.length == 0)) {
out.println("沒有 cookies ");
}
else {
out.println("<center><h1>響應(yīng)消息中的Cookies 信息 </h1>");
// Display a table with all of the info
out.println("<table border>");
out.println("<tr><th>Name</th><th>Value</th>" + "<th>Comment</th><th>Max Age</th></tr>");
for (int i = 0; i < cookies.length; i++) {
Cookie c = cookies[i];
out.println("<tr><td>" + c.getName() + "</td><td>" +
c.getValue() + "</td><td>" + c.getComment() + "</td><td>" + c.getMaxAge() + "</td></tr>");
}
out.println("</table></center>");
}
// Wrap up
out.println("</body>");
out.println("</html>");
out.flush();
}
/**
* <p>Initialize the servlet. This is called once when the
* servlet is loaded. It is guaranteed to complete before any
* requests are made to the servlet
* @param cfg Servlet configuration information
*/
public void init(ServletConfig cfg)
throws ServletException
{
super.init(cfg);
}
/**
* <p>Destroy the servlet. This is called once when the servlet
* is unloaded.
*/
public void destroy()
{
super.destroy();
}
}
注意:Cookie 進(jìn)行服務(wù)器端與客戶端的雙向交流,所以它涉及到安全性問(wèn)題。
使用Java Servlet API 進(jìn)行會(huì)話管理
javax.servlet.http.HttpSession 接口封裝了HTTP 會(huì)話的細(xì)節(jié),該會(huì)話與一段時(shí)間內(nèi)特定的Web 客戶對(duì)Web 服務(wù)器的多個(gè)請(qǐng)求相關(guān)。管理會(huì)話數(shù)據(jù)主要涉及到3個(gè)方面:會(huì)話交換、會(huì)話重定位和會(huì)話持久性,只有實(shí)現(xiàn)了java.io.Serializable 接口的數(shù)據(jù)對(duì)象才能夠被交換、重定位和保持。這個(gè)接口主要是讓對(duì)象具有序列化的能力,它可以將對(duì)象的狀態(tài)信息寫入任意的輸出流中如:文件、網(wǎng)絡(luò)連接等。
編程思路:下面是實(shí)現(xiàn)一個(gè)簡(jiǎn)單在商場(chǎng)購(gòu)物的例子,當(dāng)用戶選購(gòu)商品(糖果、收音機(jī)和練習(xí)簿)放入購(gòu)物袋中,保存選購(gòu)的商品信息。
ShowBuy.java 的源代碼如下:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class ShowBuy extends HttpServlet
{
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, java.io.IOException
{
String[] item={"糖果","收音機(jī)","練習(xí)簿"};
//獲取會(huì)話對(duì)象
HttpSession session=req.getSession(true);
//獲取選擇的商品數(shù)目
Integer itemCount=(Interger) session.getValue("itemCount");
//如果沒放入商品則數(shù)目為0
if (itemCount==null){
itemCount=new Integer(0);
}
// Set the content type of the response
res.setContentType("text/html;charset=gb2312");
PrintWriter out=res.getWriter();
//取得POST上來(lái)的表單信息
String[] itemsSelected;
String itemName;
itemsSelected=req.getParameterValues("item");
//將選中的商品放入會(huì)話對(duì)象
if(itemsSelected !=null){
for(int i=0;i<itemsSelected.length;i++){
itemName=itemsSelected[i];
itemCount=new Integer(itemCount.intValue()+1);
session.putValue("Item" + itemCount,itemName);
//將商品名稱定義為ItemX
session.putValue("itemCount",itemCount);
//將商品數(shù)量放入會(huì)話對(duì)象
}
}
// Write the page header
out.println("<html>");
out.println("<head>");
out.println("<title>購(gòu)物袋的內(nèi)容</title>");
out.println("</head>");
out.println("<body>");
out.println("<center><h1>你放在購(gòu)物袋中的商品是: </h1></center>");
//將購(gòu)物袋的內(nèi)容寫入頁(yè)面
for (int i = 1; i < itemCount.intValue(); i++) {
String item =(String) session.getValue("Item"+i);
//取出商品名稱
out.println(items[Integer.parseInt(item)]);
out.println("<BR>");
}
// Wrap up
out.println("</body>");
out.println("</html>");
out.close();
}
}
客戶端的ShowBuy.html 的源代碼如下:
<HTML>
<HEAD>
<TITLE>購(gòu)物袋的實(shí)例 </TITLE>
</HEAD>
<BODY>
<CENTER><H1>百貨商場(chǎng)</H1></CENTER>
<HR>
<FORM ACTION='servlet/ShowBuy" METHOD="POST">
選購(gòu)商品
<p><INPUT TYPE="Checkbox" NAME="item" VALUE="0">
第一種:糖果</p>
<p><INPUT TYPE="Checkbox" NAME="item" VALUE="1">
第二種:收音機(jī)</p>
<p><INPUT TYPE="Checkbox" NAME="item" VALUE="2">
第三種:練習(xí)簿</p>
<HR>
<INPUT TYPE="Submit" NAME="bt_submit" VALUE="加入購(gòu)物袋">
</FORM>
</BODY>
</HTML>
編程技巧說(shuō)明:
在Servlet 中進(jìn)行會(huì)話管理時(shí),首先要獲得會(huì)話對(duì)象。HttpServletRequest.getSession()對(duì)象返回與請(qǐng)求相關(guān)的當(dāng)前HttpSession 對(duì)象,并且當(dāng)該對(duì)象不存在時(shí)就新創(chuàng)建一個(gè)對(duì)象;HttpServletRequest.getSession(true)實(shí)現(xiàn)相同的功能。如果參數(shù)是false,當(dāng)不存在會(huì)話對(duì)象時(shí),將返回一個(gè)null 值。
//獲取會(huì)話對(duì)象
HttpSession session=req.getSession(true);
//獲取選擇的商品數(shù)目
Integer itemCount=(Interger) session.getValue("itemCount");
具體操作時(shí),當(dāng)用戶選擇商品后,單擊“加入購(gòu)物袋"按鈕,Servlet 輸出用戶選擇的商品。
posted on 2007-09-27 11:31
lk 閱讀(789)
評(píng)論(0) 編輯 收藏 所屬分類:
j2ee