綜述:Java Servlet 是 JSP 技術(shù)的基礎(chǔ),而且大型的 Web 應(yīng)用程序的開發(fā)需要 Java Servlet 和 JSP 配合才能完成?,F(xiàn)在許多 Web 服務(wù)器都支持 Servlet,即使不直接支持 Servlet 的 Web 服務(wù)器,也可以通過附件的應(yīng)用服務(wù)器和模塊來支持 Servlet,這得益于 Java 的跨平臺(tái)特性。另外,由于 Servlet 內(nèi)部以線程方式提供提供服務(wù),不必對(duì)于每個(gè)請(qǐng)求都啟動(dòng)一個(gè)進(jìn)程,并且利用多線程機(jī)制可以同時(shí)為多個(gè)請(qǐng)求服務(wù),因此 Servlet 的效率非常高。
但它并不是沒有缺點(diǎn),和傳統(tǒng)的 CGI、ISAPI、NSAPI 方式相同,Java Servlet 也是利用輸出 HTML 語句來實(shí)現(xiàn)動(dòng)態(tài)網(wǎng)頁的,如果用它來開發(fā)整個(gè)網(wǎng)站,動(dòng)態(tài)部分和靜態(tài)頁面的整合過程將變得無法想象。這就是 SUN 還要推出 JSP 的原因。
如何正確理解 servlet?
servlet 的基本概念
一、Servlet 的結(jié)構(gòu)
在具體掌握 servlet 之前,須對(duì) Java 語言有所了解。我們假設(shè)讀者已經(jīng)具備一定的 Java 基礎(chǔ)。在 Servlet API 中最重要的是 Servlet 接口(interface),所有的 servlets 都必須實(shí)現(xiàn)該接口,途徑有很多:一是直接實(shí)現(xiàn)該接口,二是通過擴(kuò)展類(class)來實(shí)現(xiàn),如 HttpServlet。 這個(gè) Servlet 接口提供了 servlet 與客戶端聯(lián)系的方法。Servlet 編寫者可以在他們開發(fā) servlet 程序時(shí)提供更多一些或所有的這樣方法。
當(dāng)一個(gè) servlet 接收來自客戶端的調(diào)用請(qǐng)求, 它接收兩個(gè)對(duì)象:一個(gè)是 ServletRequest,另外一個(gè)是 ServletResponse。這個(gè) ServletRequest 類概括從客戶端到服務(wù)器之間的聯(lián)系,而 ServletResponse 類概括從 servlet 返回客戶端的聯(lián)系。
ServletRequest 接口可以獲取到這樣一些信息,如由客戶端傳送的闡述名稱,客戶端正在使用的協(xié)議,產(chǎn)生請(qǐng)求并且接收請(qǐng)求的服務(wù)器遠(yuǎn)端主機(jī)名。它也提供獲取數(shù)據(jù)流的 ServletInputStream, 這些數(shù)據(jù)是客戶端引用中使用 HTTP POST 和 PUT 方法遞交的。一個(gè) ServletRequest 的子類可以讓 servlet 獲取更多的協(xié)議特性數(shù)據(jù)。例如: HttpServletRequest 包含獲取 HTTP-specific 頭部信息的方法。
ServletResponse 接口給出相應(yīng)客戶端的 servlet 方法。它允許 servlet 設(shè)置內(nèi)容長(zhǎng)度和回應(yīng)的 mime 類型,并且提供輸出流 ServletOutputStream,通過編寫者可以發(fā)回相應(yīng)的數(shù)據(jù)。 ServletResponse 子類可以給出更多 protocol- specific 內(nèi)容的信息。 例如:HttpServletResponse 包含允許 servlet 操作 HTTP-specific 頭部信息的方法。
上面有關(guān)類和接口的描述,構(gòu)成了一個(gè)基本的 Servlet 框架。HTTP servlets 有一些附加的可以提供 session-tracking capabilities 的方法。servlet 編寫者可以利用這些 API,在有他人操作時(shí)維護(hù) servlet 與客戶端之間的狀態(tài)。
二、Servlet 的接口
我們編寫的 Servlet ,一般從 Javax 包的 HttpServlet 類擴(kuò)展而來,在 HttpServlet 中加入了一些附加的方法,這些方法可以被協(xié)助處理 HTTP 基本請(qǐng)求的 HttpServlet 類中的方法 service 自動(dòng)地調(diào)用。這些方法有:
· doGet 用來處理 HTTP 的 GET 請(qǐng)求。
這個(gè) GET 操作僅僅允許客戶從 HTTP server 上取得(GET)資源。重載此方法的用戶自動(dòng)允許支持方法 HEAD。這個(gè) GET 操作被認(rèn)為是安全的,沒有任何的負(fù)面影響,對(duì)用戶來說是很可靠的。比如,大多數(shù)的正規(guī)查詢都沒有副作用。打算改變存儲(chǔ)數(shù)據(jù)的請(qǐng)求必須用其他的 HTTP 方法。這些方法也必須是個(gè)安全的操作。方法 doGet 的缺省實(shí)現(xiàn)將返回一個(gè) HTTP 的 BAD_REQUEST 錯(cuò)誤。
方法 doGet 的格式:
protected void doGet(HttpServletResquest request, HttpServletResponse response)
throws ServletException,IOException;
· doPost 用來處理 HTTP 的 POST 請(qǐng)求。
這個(gè) POST 操作包含了在必須通過此 servlet 執(zhí)行的請(qǐng)求中的數(shù)據(jù)。由于它不能立即取得資源,故對(duì)于那些涉及到安全性的用戶來說,通過 POST 請(qǐng)求操作會(huì)有一些副作用。
方法 doPost 的缺省實(shí)現(xiàn)將返回一個(gè) HTTP 的 BAD_REQUEST 錯(cuò)誤。當(dāng)編寫 servlet 時(shí),為了支持 POST 操作必須在子類 HttpServlet 中實(shí)現(xiàn)(implement)此方法。
此方法的格式:
protected void doPost(HttpServletResquest request, HttpServletResponse response)
throws ServletException,IOException;
· doPut 用來處理 HTTP 的 PUT 請(qǐng)求。
此 PUT 操作模擬通過 FTP 發(fā)送一個(gè)文件。對(duì)于那些涉及到安全性的用戶來說,通過 PUT 請(qǐng)求操作也會(huì)有一些副作用。
此方法的格式:
protected void doPut(HttpServletResquest request,HttpServletResponse response)
throws ServletException,IOException;
· doDelete 用來處理 HTTP 的 DELETE 請(qǐng)求。
此操作允許客戶端請(qǐng)求一個(gè)從 server 移出的 URL。對(duì)于那些涉及到安全性的用戶來說,通過 DELETE 請(qǐng)求操作會(huì)有一些副作用。
方法 doDelete 的缺省實(shí)現(xiàn)將返回一個(gè) HTTP 的 BAD_REQUEST 錯(cuò)誤。當(dāng)編寫 servlet 時(shí),為了支持 DELETE 操作,必須在子類 HttpServlet 中實(shí)現(xiàn)(implement)此方法。
此方法的格式:
protected void doDelete (HttpServletResquest request, HttpServletResponse response)
throws ServletException,IOException;
· doHead 用來處理 HTTP 的 HEAD 請(qǐng)求。
缺省地,它會(huì)在無條件的 GET 方法執(zhí)行時(shí)運(yùn)行,但是不返回任何數(shù)據(jù)到客戶端。只返回包含內(nèi)容信息的長(zhǎng)度的 header。由于用到 GET 操作,此方法應(yīng)該是很安全的(沒有副作用)也是可重復(fù)使用的。此方法的缺省實(shí)現(xiàn)(implement)自動(dòng)地處理了 HTTPDE 的 HEAD 操作并且不需要通過一個(gè)子類實(shí)現(xiàn)(implement)。
此方法的格式:
protected void doHead (HttpServletResquest request,HttpServletResponse response)
throws ServletException,IOException;
· doOptions 用來處理 HTTP 的 OPTIONS 請(qǐng)求。
此操作自動(dòng)地決定支持什么 HTTP 方法。比如說,如果讀者創(chuàng)建 HttpServlet 的子類并重載方法 doGet,然后方法 doOptions 會(huì)返回下面的 header:
Allow:GET,HEAD,TRACE,OPTIONS
一般不需要重載方法 doOptions。
此方法的格式:
protected void doOptions (HttpServletResquest request, HttpServletResponse response)
throws ServletException,IOException;
· doTrace 用來處理 HTTP 的 TRACE 請(qǐng)求。
此方法的缺省實(shí)現(xiàn)產(chǎn)生一個(gè)包含所有在 trace 請(qǐng)求中的 header 的信息的應(yīng)答(response)。在開發(fā) servlet 時(shí),多數(shù)情況下需要重載此方法。
此方法的格式:
protected void doTrace (HttpServletResquest request, HttpServletResponse response)
throws ServletException,IOException;
在開發(fā)以 HTTP 為基礎(chǔ)的 servlet 中,Servlet 開發(fā)者關(guān)心方法 doGet 和方法 doPost 即可。
三、Servlet 的生命周期
如果讀者寫過 Java 的小應(yīng)用程序(Applet),那 Servlet 對(duì)你來說就不會(huì)太難,也許更為簡(jiǎn)單。因?yàn)?Servlet 不用考慮圖形界面的應(yīng)用。與小應(yīng)用程序一樣,Servlet 也有一個(gè)生命周期。Servlet 的生命周期是當(dāng)服務(wù)器裝載運(yùn)行 servlets:接收來自客戶端的多個(gè)請(qǐng)求并且返回?cái)?shù)據(jù)給客戶端,然后再刪除移開 servlets。下面詳細(xì)描述如下:
1.初始化時(shí)期 當(dāng)一個(gè)服務(wù)器裝載 servlet 時(shí),它運(yùn)行 servlet 的 init() 方法。
public void init(ServletConfig config) throws ServletException
{
super.init(); //一些初始化的操作,如數(shù)據(jù)庫的連接
}
需要記住的是一定要在 init()結(jié)束時(shí)調(diào)用 super.init()。init()方法不能反復(fù)調(diào)用,一旦調(diào)用就是重裝載 servlet。直到服務(wù)器調(diào)用 destroy 方法卸載 servlet 后才能再調(diào)用。
2.Servlet 的執(zhí)行時(shí)期 在服務(wù)器裝載初始化 servlet 后,servlet 就能夠處理客戶端的請(qǐng)求,我們可以用 service 方法來實(shí)現(xiàn)。每個(gè)客戶端請(qǐng)求有它自己 service 方法:這些方法接收客戶端請(qǐng)求,并且發(fā)回相應(yīng)的響應(yīng)。Servlets 能同時(shí)運(yùn)行多個(gè) service。這是很重要的,這樣,service 方法可以按一個(gè)thread-safe 樣式編寫。如:service 方法更新 servlet 對(duì)象中的一個(gè)字段 field,這個(gè)字段是可以同時(shí)存取的。假如某個(gè)服務(wù)器不能同時(shí)并發(fā)運(yùn)行 service 方法,也可以用SingleThreadModel 接口。這個(gè)接口保證不會(huì)有兩個(gè)以上的線程(threads)并發(fā)運(yùn)行。在 Servlet 執(zhí)行期間其最多的應(yīng)用是處理客戶端的請(qǐng)求并產(chǎn)生一個(gè)網(wǎng)頁。其代碼如下:
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>"# Servlet </title></head>");
out.println("<body>");
out.println("Hello World");
out.println("</body></html>");
out.close();
3.Servlet 結(jié)束時(shí)期 Servlets 一直運(yùn)行到他們被服務(wù)器卸載。在結(jié)束的時(shí)候需要收回在 init()方法中使用的資源,在 Servlet 中是通過 destory()方法來實(shí)現(xiàn)的。
public void destroy()
{
//回收在init()中啟用的資源,如關(guān)閉數(shù)據(jù)庫的連接等。
}
JSP 與 servlet 之間是怎樣的關(guān)系?
JSP 主要關(guān)注于 HTML(或者 XML)與 Java 代碼的結(jié)合,以及加入其中的 JSP 標(biāo)記。如果一個(gè)支持 JSP 的服務(wù)器遇到一個(gè) JSP 頁面,它首先查看該頁面是否被編譯成為一個(gè) servlet。由此可見,JSP 被編譯成 servlet,即被轉(zhuǎn)變?yōu)榧?Java,然后被裝載入服務(wù)器執(zhí)行。當(dāng)然,這一過程,根據(jù)不同的 JSP 引擎而略有不同。
JSP 和 servlet 在應(yīng)用上有什么區(qū)別
簡(jiǎn)單的說,SUN 首先發(fā)展出 SERVLET,其功能比較強(qiáng)勁,體系設(shè)計(jì)也很先進(jìn),只是,它輸出 HTML 語句還是采用了老的 CGI 方式,是一句一句輸出,所以,編寫和修改 HTML 非常不方便。
后來 SUN 推出了類似于 ASP 的嵌套型的 JSP,把 JSP TAG 嵌套到 HTML 語句中,這樣,就大大簡(jiǎn)化和方便了網(wǎng)頁的設(shè)計(jì)和修改。新型的網(wǎng)絡(luò)語言如 ASP,PHP 都是嵌套型的。
從網(wǎng)絡(luò)三層結(jié)構(gòu)的角度看,一個(gè)網(wǎng)絡(luò)項(xiàng)目最少分三層:data layer,business layer,,presentation layer。當(dāng)然也可以更復(fù)雜。
SERVLET 用來寫 business layer 是很強(qiáng)大的,但是對(duì)于寫 presentation layer 就很不方便。JSP 則主要是為了方便寫 presentation layer 而設(shè)計(jì)的。當(dāng)然也可以寫 business layer。寫慣了 ASP,PHP,CGI 的朋友,經(jīng)常會(huì)不自覺的把 presentation layer 和 business layer 混在一起。比如把數(shù)據(jù)庫處理信息放到 JSP 中,其實(shí),它應(yīng)該放在 business layer 中。
根據(jù) SUN 自己的推薦,JSP 中應(yīng)該僅僅存放與 presentation layer 有關(guān)的部分,也就是說,只放輸出 HTML 網(wǎng)頁的部份。而所有的數(shù)據(jù)計(jì)算、數(shù)據(jù)分析、數(shù)據(jù)庫聯(lián)結(jié)處理,統(tǒng)統(tǒng)是屬于 business layer,應(yīng)該放在 JAVA BEANS 中。通過 JSP 調(diào)用 JAVA BEANS,實(shí)現(xiàn)兩層的整合。
實(shí)際上,微軟前不久推出的 DNA 技術(shù),簡(jiǎn)單說,就是 ASP+COM/DCOM 技術(shù)。與 JSP+BEANS 完全類似,所有的 presentation layer 由 ASP 完成,所有的 business layer 由 COM/DCOM 完成。通過調(diào)用,實(shí)現(xiàn)整合。
為什么要采用這些組件技術(shù)呢?因?yàn)閱渭兊?ASP/JSP 語言是非常低效率執(zhí)行的,如果出現(xiàn)大量用戶點(diǎn)擊,純 SCRIPT 語言很快就到達(dá)了他的功能上限,而組件技術(shù)就能大幅度提高功能上限,加快執(zhí)行速度。
另外一方面,純 SCRIPT 語言將 presentation layer 和 business layer 混在一起,造成修改不方便,并且代碼不能重復(fù)利用。如果想修改一個(gè)地方,經(jīng)常會(huì)牽涉到十幾頁 CODE,采用組件技術(shù)就只改組件就可以了。
綜上所述,SERVLET 是一個(gè)不完善的產(chǎn)品,寫 business layer 很好,寫 presentation layer 就很遜色許多了,并且兩層混雜。所以,推出 JSP+BAEN,用 JSP 寫 presentation layer,用 BAEN 寫 business layer。SUN 自己的意思也是將來用 JSP 替代 SERVLET。
所以,學(xué)了 JSP,不會(huì)用 JAVA BEAN 并進(jìn)行整合,等于沒學(xué)。
如何調(diào)用 servlet?
要調(diào)用 Servlet 或 Web 應(yīng)用程序,請(qǐng)使用下列任一種方法:由 URL 調(diào)用、在