- Java Web程序設(shè)計(jì)
- 張磊 丁香乾編著
- 825字
- 2018-12-29 18:50:44
理論篇
第1章 Servlet基礎(chǔ)
本章目標(biāo)
■ 了解動(dòng)態(tài)網(wǎng)站開發(fā)的相關(guān)技術(shù)
■ 理解Servlet的運(yùn)行原理及生命周期
■ 掌握Servlet的編寫及部署
■ 掌握Servlet對(duì)表單數(shù)據(jù)的處理
■ 掌握Servlet對(duì)HTTP請(qǐng)求報(bào)頭的處理
學(xué)習(xí)導(dǎo)航

任務(wù)描述
【描述1.D.1】
使用Servlet輸出“Hello World”頁面。
【描述1.D.2】
使用Servlet處理表單數(shù)據(jù),當(dāng)用戶提交的數(shù)據(jù)正確時(shí)(用戶名haier,密碼soft),輸出“登錄成功!”,否則提示“登錄失敗!”。
【描述1.D.3】
使用request對(duì)象讀取報(bào)頭信息,并打印在頁面中。
【描述1.D.4】
通過設(shè)置響應(yīng)報(bào)頭,實(shí)現(xiàn)動(dòng)態(tài)時(shí)鐘。
【描述1.D.5】
使用請(qǐng)求重定向和轉(zhuǎn)發(fā)兩種方式,使用戶自動(dòng)訪問重定向后的頁面,區(qū)分轉(zhuǎn)發(fā)和重定向的區(qū)別。
1.1 動(dòng)態(tài)網(wǎng)站技術(shù)概述
在《Web編程基礎(chǔ)》課程中已經(jīng)學(xué)習(xí)使用HTML、CSS、JavaScript等相關(guān)技術(shù)來建設(shè)靜態(tài)網(wǎng)站,其中,靜態(tài)網(wǎng)頁文件的擴(kuò)展名為“.htm”或“.html”,這些頁面不能與服務(wù)器進(jìn)行數(shù)據(jù)交互。隨著站點(diǎn)內(nèi)容和功能需求的不斷復(fù)雜化,單一的靜態(tài)網(wǎng)站技術(shù)往往不能滿足應(yīng)用的要求。例如,靜態(tài)網(wǎng)站無法完成將數(shù)據(jù)傳輸?shù)椒?wù)器上進(jìn)行處理并存儲(chǔ)到數(shù)據(jù)庫中,此時(shí)就需要?jiǎng)討B(tài)網(wǎng)站技術(shù)。
1.1.1 動(dòng)態(tài)網(wǎng)站技術(shù)
動(dòng)態(tài)網(wǎng)站并不是指具有動(dòng)畫功能的網(wǎng)站,而是指基于數(shù)據(jù)庫架構(gòu)的網(wǎng)站,一般由大量的動(dòng)態(tài)網(wǎng)頁(如JSP)、后臺(tái)處理程序(如Servlet)和用于存儲(chǔ)內(nèi)容的數(shù)據(jù)庫組成。所謂“動(dòng)態(tài)網(wǎng)頁”,本質(zhì)上與網(wǎng)頁上的各種動(dòng)畫、滾動(dòng)字幕等視覺上的“動(dòng)態(tài)效果”無關(guān)。動(dòng)態(tài)網(wǎng)頁可以是純文字內(nèi)容,也可以包含各種動(dòng)畫內(nèi)容,這些只是網(wǎng)頁具體內(nèi)容的表現(xiàn)形式。無論網(wǎng)頁是否具有動(dòng)態(tài)效果,采用動(dòng)態(tài)網(wǎng)站技術(shù)生成的網(wǎng)頁都稱為動(dòng)態(tài)網(wǎng)頁。
動(dòng)態(tài)網(wǎng)站一般具有以下幾個(gè)特點(diǎn)。
■ 交互性:網(wǎng)頁會(huì)根據(jù)用戶的要求和選擇而動(dòng)態(tài)改變和響應(yīng)。例如,用戶在網(wǎng)頁中填寫表單信息并提交,服務(wù)器可以對(duì)數(shù)據(jù)進(jìn)行處理并保存到數(shù)據(jù)庫中,然后跳轉(zhuǎn)到相應(yīng)頁面。因此,動(dòng)態(tài)網(wǎng)站可以實(shí)現(xiàn)用戶注冊(cè)、信息發(fā)布、訂單管理等功能。
■ 自動(dòng)更新:無須手動(dòng)更新HTML文檔,便會(huì)自動(dòng)生成新的頁面,大大減少了工作量。例如,在論壇中發(fā)布信息時(shí),后臺(tái)服務(wù)器可以產(chǎn)生新的網(wǎng)頁。
■ 隨機(jī)性:在不同的時(shí)間、不同的用戶訪問同一網(wǎng)頁時(shí)可能產(chǎn)生不同的頁面。
注意 動(dòng)態(tài)網(wǎng)站一般采用動(dòng)靜結(jié)合的原則:網(wǎng)站中內(nèi)容頻繁更新的,可采用動(dòng)態(tài)網(wǎng)頁技術(shù);網(wǎng)站中內(nèi)容不需要更新的,則可采用靜態(tài)網(wǎng)頁進(jìn)行顯示。通常一個(gè)網(wǎng)站既包含動(dòng)態(tài)網(wǎng)頁也包含靜態(tài)網(wǎng)頁。
動(dòng)態(tài)網(wǎng)站技術(shù)有早期的CGI技術(shù),全名Common Gateway Interface(公用網(wǎng)關(guān)接口)。CGI提供了一種機(jī)制,可以實(shí)現(xiàn)客戶和服務(wù)器之間真正的雙向交互。這種技術(shù)為諸如在線用戶支持和電子商務(wù)等新思想的實(shí)現(xiàn)鋪平了道路,同時(shí)CGI技術(shù)因可以使用不同的語言編寫適合的CGI程序,如Visual Basic、Delphi和C/C++等,并且功能強(qiáng)大,被早期的很多網(wǎng)站采用。但由于編程困難、效率低下、修改復(fù)雜,所以逐漸被新技術(shù)所取代。目前被廣泛應(yīng)用的動(dòng)態(tài)網(wǎng)站技術(shù)主要有以下三種。
■ PHP(Hypertext Preprocessor):是超文本預(yù)處理器,其語法大量借鑒了C、Java、Perl等語言,只需要很少的編程知識(shí)就能使用PHP建立一個(gè)真正交互的Web站點(diǎn)。由于PHP開放源代碼,并且是免費(fèi)的,所以非常流行,是當(dāng)今Internet上最為火熱的腳本語言之一。
■ ASP(Active Server Pages):是一種類似HTML、Script與CGI結(jié)合體的技術(shù),它沒有提供自己專門的編程語言,允許用戶使用許多已有的腳本語言編寫ASP應(yīng)用程序。但ASP技術(shù)局限于微軟的操作系統(tǒng)平臺(tái)之上,主要工作環(huán)境為微軟的IIS應(yīng)用程序結(jié)構(gòu),而且ASP技術(shù)不能很容易地實(shí)現(xiàn)在跨平臺(tái)Web服務(wù)器上工作,因此一般只適合一些中小型站點(diǎn)。但目前由ASP升級(jí)演變而來的ASP.NET支持大型網(wǎng)站的開發(fā)。
■ JSP(Java Server Pages):是基于Java Servlet以及整個(gè)Java體系的Web開發(fā)技術(shù)。JSP是由SUN公司于1999年6月推出的新技術(shù),它與ASP有一定的相似之處,但JSP能在大部分的服務(wù)器上運(yùn)行,而且其應(yīng)用程序易于維護(hù)和管理,安全性能方面也被認(rèn)為是這三種基本動(dòng)態(tài)網(wǎng)站技術(shù)中最好的。
1.1.2 B/S架構(gòu)
在動(dòng)態(tài)網(wǎng)站技術(shù)中,一般使用瀏覽器作為客戶端,當(dāng)客戶在瀏覽器中發(fā)出請(qǐng)求時(shí),Web服務(wù)器得到請(qǐng)求后查找資源,然后向客戶返回一個(gè)結(jié)果,這就是B/S(Browser/Server)架構(gòu),如圖1-1所示。

圖1-1 B/S模型
在B/S架構(gòu)中,用戶的請(qǐng)求與Web服務(wù)器響應(yīng)需要通過Internet網(wǎng)絡(luò)從一臺(tái)計(jì)算機(jī)發(fā)送到另一臺(tái)計(jì)算機(jī),不同計(jì)算機(jī)之間是使用HTTP(HyperText Transfer Protocol)協(xié)議進(jìn)行通信的。HTTP是超文本傳輸協(xié)議,包含命令和傳輸信息,不僅用于Web訪問,也可以用于其他互聯(lián)網(wǎng)/內(nèi)聯(lián)網(wǎng)應(yīng)用系統(tǒng)之間的通信,從而實(shí)現(xiàn)各種資源信息的超媒體訪問集成。
1.2 Servlet簡介
Servlet是JavaEE架構(gòu)中的關(guān)鍵組成部分。JavaEE是基于分布式和多層結(jié)構(gòu)的企業(yè)級(jí)應(yīng)用開發(fā)規(guī)范和標(biāo)準(zhǔn)。目前,在企業(yè)應(yīng)用開發(fā)中不僅會(huì)使用傳統(tǒng)的JavaEE組件(例如JDBC、Servlet、EJB等),還會(huì)使用一些輕量級(jí)的框架結(jié)構(gòu)(例如Struts、Hibernate和Spring),以提高企業(yè)開發(fā)效率。在Java企業(yè)級(jí)開發(fā)應(yīng)用中會(huì)使用到的技術(shù)如圖1-2所示。Servlet技術(shù)是Sun公司提供的一種實(shí)現(xiàn)動(dòng)態(tài)網(wǎng)頁的解決方案,它是基于Java編程語言的Web服務(wù)器端編程技術(shù),主要用于在Web服務(wù)器端獲得客戶端的訪問請(qǐng)求信息并動(dòng)態(tài)生成對(duì)客戶端的響應(yīng)信息。此外,Servlet技術(shù)也是JSP技術(shù)的基礎(chǔ)。

圖1-2 JavaEE技術(shù)組成
Servlet是Web服務(wù)器端的Java應(yīng)用程序,它支持用戶交互式地瀏覽和修改數(shù)據(jù),生成動(dòng)態(tài)的Web頁面。比如,當(dāng)瀏覽器發(fā)送一個(gè)請(qǐng)求到服務(wù)器后,服務(wù)器會(huì)把請(qǐng)求送往一個(gè)特定的Servlet,這樣Servlet就能處理請(qǐng)求并構(gòu)造一個(gè)合適的響應(yīng)(通常以HTML網(wǎng)頁形式)返回給客戶,如圖1-3所示。

圖1-3 Servlet的作用
Servlet與普通Java程序相比,只是輸入信息的來源和輸出結(jié)果的目標(biāo)不一樣,例如,對(duì)于Java程序而言,用戶一般通過GUI窗口輸入信息,并在GUI窗口上獲得輸出結(jié)果,而對(duì)于Servlet程序而言,用戶一般通過瀏覽器輸入并獲取響應(yīng)結(jié)果。通常普通Java程序所能完成的大多數(shù)任務(wù),Servlet程序都可以完成。Servlet程序具有以下特點(diǎ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有著更多的選擇,比如緩沖以前的計(jì)算結(jié)果、保持?jǐn)?shù)據(jù)庫連接的活動(dòng)等。
■ 方便
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í)現(xiàn)數(shù)據(jù)庫連接池之類的功能。
■ 良好的可移植性
Servlet是用Java語言編寫的,所以具備Java的可移植性特點(diǎn)。此外,Servlet API具有完善的標(biāo)準(zhǔn),支持Servlet規(guī)范的容器都可以運(yùn)行Servlet程序,例如Tomcat、Resin等。
1.3 第一個(gè)Servlet
編寫Servlet需要遵循其規(guī)范:
■ 創(chuàng)建Servlet時(shí),需要繼承HttpServlet類,同時(shí)需要導(dǎo)入Servlet API的兩個(gè)包:javax.servlet和javax.servlet.http。javax.servlet包提供了控制Servlet生命周期所必需的Servlet接口,是編寫Servlet時(shí)必須要實(shí)現(xiàn)的;javax.servlet.http包提供了從Servlet接口派生出的專門用于處理HTTP請(qǐng)求的抽象類和一般的工具類。
■ 根據(jù)數(shù)據(jù)的發(fā)送方式,覆蓋doGet()、doPost()方法之一或全部。doGet()和doPost()方法都有兩個(gè)參數(shù),分別為HttpServletRequest和HttpServletResponse類型。這兩個(gè)參數(shù)分別用于表示客戶端的請(qǐng)求和服務(wù)器端的響應(yīng)。通過HttpServletRequest,可以從客戶端獲得發(fā)送過來的信息;通過HttpServletResponse,可以讓服務(wù)器端對(duì)客戶端做出響應(yīng),最常用的就是向客戶端發(fā)送信息。關(guān)于這兩個(gè)參數(shù),將在后續(xù)內(nèi)容中詳細(xì)講解。
注意 如果在瀏覽器中直接輸入地址來訪問Servlet資源,屬于使用GET方式訪問。
下述代碼用于實(shí)現(xiàn)任務(wù)描述1.D.1,使用Servlet輸出“Hello World”頁面。
【描述1.D.1】HelloServlet.java
// 創(chuàng)建一個(gè)Servlet類,繼承HttpServlet public class HelloServlet extends HttpServlet { // 重寫doGet() public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 設(shè)置響應(yīng)到客戶端的文本類型為HTML response.setContentType("text/html"); // 獲取輸出流 PrintWriter out = response.getWriter(); out.println(" Hello World"); } }
上述代碼會(huì)向客戶端瀏覽器中打印“Hello World”信息。通過response對(duì)象的getWriter()方法可以獲取向客戶端輸出信息的輸出流:
PrintWriter out = response.getWriter();
調(diào)用輸出流的println()方法可以在客戶端瀏覽器中打印消息。例如:
out.println(" Hello World");
下面在Web應(yīng)用的部署文件web.xml中注冊(cè)此Servlet信息。
【描述1.D.1】在web.xml中配置Servlet
<servlet> <display-name>Hello</display-name> <!-- Servlet的引用名 --> <servlet-name>Hello</servlet-name> <!-- 所配置的Servlet類的完整類路徑 --> <servlet-class>com.haiersoft.ch01.HelloServlet</servlet-class> </servlet> <servlet-mapping> <!-- 前面配置的Servlet引用名--> <servlet-name>Hello</servlet-name> <!-- 訪問當(dāng)前Servlet的URL --> <url-pattern>/hello</url-pattern> </servlet-mapping>
在上述配置信息中,需要注意以下幾個(gè)方面:
■ Servlet別名,即<servlet-name>和</servlet-name>之間的命名可以隨意命名,但要遵循命名規(guī)范。
■ <servlet>和<servlet-mapping>元素可以配對(duì)出現(xiàn),通過Servlet別名進(jìn)行匹配。<servlet>元素也可以單獨(dú)出現(xiàn),通常用于初始化操作。
■ URL引用,即<url-pattern>和</url-pattern>之間的命名通常以“/”開頭。
啟動(dòng)Tomcat,在IE中訪問http://localhost:8080/ch01/hello,運(yùn)行結(jié)果如圖1-4所示。

圖1-4 運(yùn)行結(jié)果
注意 關(guān)于Web應(yīng)用的開發(fā)過程及配置,可參考實(shí)踐1.G.2指導(dǎo)部分。
1.4 Servlet的生命周期
Servlet是運(yùn)行在服務(wù)器上的,其生命周期由Servlet容器負(fù)責(zé)。Servlet生命周期是指Servlet實(shí)例從創(chuàng)建到響應(yīng)客戶請(qǐng)求直至銷毀的過程。Servlet API中定義了關(guān)于Servlet生命周期的3個(gè)方法。
■ init():用于Servlet初始化。當(dāng)容器創(chuàng)建Servlet實(shí)例后,會(huì)自動(dòng)調(diào)用此方法。
■ service():用于服務(wù)處理。當(dāng)客戶端發(fā)出請(qǐng)求,容器會(huì)自動(dòng)調(diào)用此方法進(jìn)行處理,并將處理結(jié)果響應(yīng)到客戶端。service()方法有兩個(gè)參數(shù),分別接收ServletRequest接口和ServletResponse接口的對(duì)象來處理請(qǐng)求和響應(yīng)。
■ destroy():用于銷毀Servlet。當(dāng)容器銷毀Servlet實(shí)例時(shí)自動(dòng)調(diào)用此方法,釋放Servlet實(shí)例,清除當(dāng)前Servlet所持有的資源。
Servlet生命周期概括為以下幾個(gè)階段。
01 裝載Servlet:這項(xiàng)操作一般是動(dòng)態(tài)執(zhí)行的,有些服務(wù)器提供了相應(yīng)的管理功能,可以在啟動(dòng)的時(shí)候就裝載Servlet。
02 創(chuàng)建一個(gè)Servlet實(shí)例:容器創(chuàng)建Servlet的一個(gè)實(shí)例對(duì)象。
03 初始化:容器調(diào)用init()方法對(duì)Servlet實(shí)例進(jìn)行初始化。
04 服務(wù):當(dāng)容器接收到對(duì)此Servlet的請(qǐng)求時(shí),將調(diào)用service()方法響應(yīng)客戶的請(qǐng)求。
05 銷毀:容器調(diào)用destroy()方法銷毀Servlet實(shí)例。
在Servlet生命周期的這幾個(gè)階段中,初始化init()方法僅執(zhí)行一次,是在服務(wù)器裝載Servlet時(shí)執(zhí)行的,以后無論有多少客戶訪問此Servlet,都不會(huì)重復(fù)執(zhí)行init()。即此Servlet在Servlet容器中只有單一實(shí)例;當(dāng)多個(gè)用戶訪問此Servlet時(shí),會(huì)分為多個(gè)線程訪問此Servlet實(shí)例對(duì)象的service()方法。在service()方法內(nèi),容器會(huì)對(duì)客戶端的請(qǐng)求方式進(jìn)行判斷,如果是Get方式提交,則調(diào)用doGet()進(jìn)行處理;如果是Post方式提交,則調(diào)用doPost()進(jìn)行處理。圖1-5說明了Servlet生命周期的不同階段。
下面代碼演示了Servlet的生命周期。

圖1-5 Servlet的生命周期
【代碼1-1】ServletLife.java
public class ServletLife extends HttpServlet { /** * 構(gòu)造方法 */ public ServletLife() { super(); } /** * 初始化方法 */ public void init(ServletConfig config) throws ServletException { System.out.println("初始化時(shí),init()方法被調(diào)用!"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("處理請(qǐng)求時(shí),doGet()方法被調(diào)用。"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("處理請(qǐng)求時(shí),doPost()方法被調(diào)用。"); } /** * 用于釋放資源 */ public void destroy() { super.destroy(); System.out.println("釋放系統(tǒng)資源時(shí),destroy()方法被調(diào)用!"); } }
啟動(dòng)Tomcat,在IE中訪問http://localhost:8080/ch01/ServletLife,觀察控制臺(tái)輸出信息,如圖1-6所示。

圖1-6 Servlet生命周期
打開多個(gè)IE窗口,訪問此Servlet,觀察控制臺(tái)輸出,會(huì)發(fā)現(xiàn)init()方法只運(yùn)行一次,而service()方法會(huì)對(duì)每次請(qǐng)求都做出響應(yīng)。
1.5 Servlet數(shù)據(jù)處理
Servlet數(shù)據(jù)處理主要包括讀取表單數(shù)據(jù)、HTTP請(qǐng)求報(bào)頭的處理和HTTP響應(yīng)報(bào)頭的設(shè)置。
1.5.1 讀取表單數(shù)據(jù)
當(dāng)訪問Internet網(wǎng)站時(shí),在瀏覽器地址欄中會(huì)經(jīng)常看到如下所述的字符串:
http://host/path?usr=tom&dest=ok
該字符串問號(hào)后面的部分為表單數(shù)據(jù)(Form Data)或查詢數(shù)據(jù)(Query Data),這些數(shù)據(jù)以“name=value”形式通過URL傳送,多個(gè)數(shù)據(jù)使用“&”分開,這種形式也稱為“查詢字符串”。查詢字符串緊跟在URL中的“?”后面,所有“名/值”對(duì)會(huì)被傳遞到服務(wù)器,這是服務(wù)器獲取客戶端信息所采用的最常見的方式。
表單數(shù)據(jù)可以通過GET請(qǐng)求方式提交給服務(wù)器,此種方式將數(shù)據(jù)跟在問號(hào)后附加到URL的結(jié)尾(查詢字符串形式);也可以采用POST請(qǐng)求方式提交給服務(wù)器,此種方式將在地址欄看不到表單數(shù)據(jù)信息,可用于大量數(shù)據(jù)的傳輸,并且比GET方式更安全。
在學(xué)習(xí)處理Form表單數(shù)據(jù)前,先來回顧《Web編程基礎(chǔ)》中學(xué)過的關(guān)于表單的基本知識(shí)。
(1)使用Form標(biāo)簽創(chuàng)建HTML表單。
使用action屬性指定對(duì)表單進(jìn)行處理的Servlet或JSP頁面的地址,可以使用絕對(duì)或相對(duì)URL。例如:
<form action="...">...</form>
如果省略action屬性,那么數(shù)據(jù)將提交給當(dāng)前頁面對(duì)應(yīng)的URL。
(2)使用輸入元素收集用戶數(shù)據(jù)。
將這些元素放在Form標(biāo)簽內(nèi),并為每個(gè)輸入元素賦予一個(gè)name。文本字段是最常用的輸入元素,其創(chuàng)建方式如下:
<input type="text" name="...">
(3)在接近表單的尾部放置提交按鈕。
例如:
<input type="submit"/>
單擊提交按鈕時(shí),瀏覽器會(huì)將數(shù)據(jù)提交給表單action對(duì)應(yīng)的服務(wù)器端程序。
1. Form表單數(shù)據(jù)
通過HttpServletRequest對(duì)象可以讀取Form標(biāo)簽中的表單數(shù)據(jù)。HttpServletRequest接口在javax.servlet.http包中定義,它擴(kuò)展了ServletRequest,并定義了描述一個(gè)HTTP請(qǐng)求的方法。當(dāng)客戶端請(qǐng)求Servlet時(shí),一個(gè)HttpServletRequest類型的對(duì)象會(huì)被傳遞到Servlet的service()方法,進(jìn)而傳遞到doGet()或doPost()方法中去。此對(duì)象中封裝了客戶端的請(qǐng)求擴(kuò)展信息,包括HTTP方法(即GET或POST)、Cookie、身份驗(yàn)證和表單數(shù)據(jù)等信息。
表1-1列出了HttpServletRequest接口中用于讀取表單數(shù)據(jù)的方法。
表1-1 HttpServletRequest接口中讀取表單數(shù)據(jù)的方法

默認(rèn)情況下,request.getParameter()使用服務(wù)器的當(dāng)前字符集解釋輸入。要改變這種默認(rèn)行為,需要使用setCharacterEncoding(String env)方法來設(shè)置字符集,例如:
request.setCharacterEncoding("GBK");
下述內(nèi)容用于實(shí)現(xiàn)任務(wù)描述1.D.2,使用Servlet處理表單數(shù)據(jù),當(dāng)用戶提交的數(shù)據(jù)正確時(shí)(用戶名haier,密碼soft),輸出“登錄成功!”,否則提示“登錄失敗!”。
(1)首先編寫靜態(tài)頁面,用于接收用戶信息。
【描述1.D.2】index.html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gbk"> <title>登錄</title> <script language="javascript" type=""> function LoginSubmit(){ var user=document.Login.loginName.value; var pass=document.Login.password.value; if(user==null||user==""){ alert("請(qǐng)?zhí)顚懹脩裘?); } else if(pass==null||pass==""){ alert("請(qǐng)?zhí)顚懨艽a"); } else document.Login.submit(); } </script> </head> <body> <form method="POST" name="Login" action="LoginServlet"> <p align="left"> 用戶名:<input type="text" name="loginName" size="20"></p> <p align="left"> 密 碼:<input type="password" name="password" size="20"></p> <p align="left"> <input type="button" value="提交" name="B1" onclick="LoginSubmit()"> <input type="reset" value="重置" name="B2"></p> </form> </body> </html>
上述HTML代碼中,使用JavaScript對(duì)用戶表單進(jìn)行初始驗(yàn)證,驗(yàn)證成功后才提交給LoginSevlet進(jìn)行處理。
(2)編寫Servlet處理用戶提交表單數(shù)據(jù)。
【描述1.D.2】LoginServlet.java
public class LoginServlet extends HttpServlet { public LoginServlet() { super(); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 設(shè)置請(qǐng)求的編碼字符為GBK(中文編碼) request.setCharacterEncoding("GBK"); // 設(shè)置響應(yīng)的文本類型為html,編碼字符為GBK response.setContentType("text/html;charset=GBK"); // 獲取輸出流 PrintWriter out = response.getWriter(); // 獲取表單數(shù)據(jù) String pass = request.getParameter("password"); String user = request.getParameter("loginName"); if ("haier".equals(user) && "soft".equals(pass)) { out.println("登錄成功!"); } else { out.println("登錄失敗!"); } } }
上述代碼中,在doGet()方法中調(diào)用了doPost()方法,這樣不管用戶以什么方式提交,處理過程都一樣。因?yàn)轫撁嬷惺褂昧酥形模瑸榱朔乐钩霈F(xiàn)中文亂碼問題,所以需要設(shè)置請(qǐng)求和響應(yīng)的編碼字符集,使之能夠支持中文,如下所示:
request.setCharacterEncoding("GBK"); response.setContentType("text/html;charset=GBK");
獲取表單中的數(shù)據(jù)時(shí),使用getParameter()方法通過參數(shù)名獲得參數(shù)值,例如:
String pass = request.getParameter("password");
上面語句通過參數(shù)名“password”來獲取該參數(shù)的值。
注意 如果index.html中表單的提交方式為GET方式,則在瀏覽器地址欄中會(huì)出現(xiàn)查詢字符串形式的表單數(shù)據(jù)(如password=soft&user=haier),但在LoginServlet中獲取參數(shù)值的方式完全相同。
(3)在web.xml中注冊(cè)該Servlet。
【描述1.D.2】web.xml
<servlet> <display-name>LoginServlet</display-name> <servlet-name>LoginServlet</servlet-name> <servlet-class>com.haiersoft.ch01.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/LoginServlet</url-pattern> </servlet-mapping>
上述代碼中,注冊(cè)了一個(gè)名為“LoginServlet”的Servlet,當(dāng)請(qǐng)求的相對(duì)URL為“/LoginServlet”時(shí),Servlet容器會(huì)將請(qǐng)求交給該Servlet進(jìn)行處理。
啟動(dòng)Tomcat,在IE中訪問http://localhost:8080/ch01/index.html,運(yùn)行結(jié)果如圖1-7所示。

圖1-7 index.html頁面
在“用戶名”文本欄中輸入“haier”,在“密碼”文本框中輸入“soft”。然后單擊“提交”按鈕,顯示結(jié)果如圖1-8所示。
當(dāng)輸入錯(cuò)誤的用戶名或密碼時(shí),則顯示“登錄失敗!”,如圖1-9所示。

圖1-8 LoginServlet驗(yàn)證成功

圖1-9 LoginServlet驗(yàn)證失敗
Form表單數(shù)據(jù)中除了普通的表單項(xiàng)之外,在實(shí)際開發(fā)中會(huì)廣泛應(yīng)用到隱藏域。隱藏域是隱藏的HTML表單變量,可以用來存儲(chǔ)狀態(tài)信息,操作起來與一般的HTML輸入域(比如文本輸入域、復(fù)選框和單選按鈕)類似,同樣會(huì)被提交到服務(wù)器。隱藏域與普通的HTML輸入域之間的不同之處就在于客戶端不能看到或修改隱藏域的值。
隱藏域可以用來在客戶端和服務(wù)器之間透明地傳輸狀態(tài)信息,示例代碼如下。
【代 碼1-2】hidden.html
<html> <head> <title>隱藏域</title> </head> <body bgcolor="blue"> <form method="post" action="nameservlet"> <p> 請(qǐng)輸入用戶名:<br> <input type="text" name="uname"><br> <input type="hidden" name="bcolor" value="blue"><br> <input type="submit" value="submit"> </form> </body> </html>
上述代碼中使用隱藏域?qū)⒂脩羲矚g的背景色傳遞給服務(wù)器。在服務(wù)器端獲取隱藏域的數(shù)據(jù)與表單其他元素一樣,都是使用getParameter()方法通過參數(shù)名獲取其數(shù)據(jù)值。
2. 查詢字符串
查詢字符串是表單數(shù)據(jù)的另一種情況,它們實(shí)質(zhì)上是相同的。同樣,服務(wù)器端的Servlet也是通過HttpServletRequest對(duì)象的getParameter()方法或者getParameterValues()方法讀取URL中查詢字符串的信息,然后根據(jù)信息可以進(jìn)行查詢,再把查詢的結(jié)果返回。
下述代碼演示查詢字符串的應(yīng)用。
【代碼1-3】querystr.html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GBK"> <title> 查詢字符串</title> </head> <body> <a href="TestURL?id=2010">下一頁</a> </body> </html>
上述代碼中,在超鏈接的URL中使用查詢字符串,在“?”后添加了“id=2010”,該語句傳遞了一個(gè)參數(shù)id,其值為2010。
【代碼1-4】TestURL
public class TestURL extends HttpServlet { public TestURL() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=GBK"); PrintWriter out = response.getWriter(); String id = request.getParameter("id"); out.println("URL參數(shù)值是:" + id); } }
在上述代碼中,使用request對(duì)象的getParameter()方法獲取URL中的參數(shù)值,并輸出。
啟動(dòng)Tomcat,在IE中訪問http://localhost:8080/ch01/querystr.html,顯示結(jié)果如圖1-10所示。
單擊“下一頁”超鏈接,顯示結(jié)果如圖1-11所示。

圖1-10 index.html

圖1-11 TestURL結(jié)果
1.5.2 處理HTTP請(qǐng)求報(bào)頭
客戶端瀏覽器向服務(wù)器發(fā)送請(qǐng)求的時(shí)候,除了用戶輸入的表單數(shù)據(jù)或者查詢數(shù)據(jù)之外,通常還會(huì)在GET/POST請(qǐng)求行后面加上一些附加的信息;而在服務(wù)器向客戶端的請(qǐng)求做出響應(yīng)的時(shí)候,也會(huì)自動(dòng)向客戶端發(fā)送一些附加的信息。這些附加信息被稱為HTTP報(bào)頭,信息附加在請(qǐng)求信息后面稱為HTTP請(qǐng)求報(bào)頭,而附加在響應(yīng)信息后面則稱為HTTP響應(yīng)報(bào)頭。在Servlet中可以獲取或設(shè)置這些報(bào)頭的信息。
報(bào)頭信息的讀取比較簡單:只需將報(bào)頭的名稱作為參數(shù),調(diào)用HttpServletRequest的getHeader方法;如果當(dāng)前的請(qǐng)求中提供了對(duì)應(yīng)的報(bào)頭信息,則返回一個(gè)String,否則返回null。
另外,這些報(bào)頭的參數(shù)名稱不區(qū)分大小寫,也就是說,也可以通過getHeader("user-agent")來獲得User-Agent報(bào)頭。常用的HTTP請(qǐng)求報(bào)頭如表1-2所示。
表1-2 常用HTTP請(qǐng)求報(bào)頭

盡管getHeader()方法是讀取輸入報(bào)頭的通用方式,但由于幾種報(bào)頭的應(yīng)用很普遍,因此HttpServletRequest為它們提供了專門的訪問方法,如表1-3所示。
表1-3 HttpServletRequest獲取報(bào)頭信息的方法

下述代碼用于實(shí)現(xiàn)任務(wù)描述1.D.3,演示報(bào)頭信息的讀取方式。
【描述1.D.3】HttpHeadServlet.java
public class HttpHeadServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=gbk"); PrintWriter out = response.getWriter(); StringBuffer buffer = new StringBuffer(); buffer.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " + "Transitional//EN\">"); buffer.append("<html>"); buffer.append("<head><title>"); String title = "請(qǐng)求表頭信息"; buffer.append(title); buffer.append("</title></head>"); buffer.append("<body>"); buffer.append("<h1 align='center'>" + title + "</h1>"); buffer.append("<b>Request Method: </b>"); buffer.append(request.getMethod() + "<br/>"); buffer.append("<b>Request URL: </b>"); buffer.append(request.getRequestURI() + "<br/>"); buffer.append("<b>Request Protocol: </b>"); buffer.append(request.getProtocol() + "<br/>"); buffer.append("<b>Request Local: </b>"); buffer.append(request.getLocale() + "<br/><br/>"); buffer.append("<table border='1' align='center'>"); buffer.append("<tr bgcolor='#FFAD00'>"); buffer.append("<th>Header Name</th><th>Header Value</th>"); buffer.append("</tr>"); Enumeration<String> headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = (String) headerNames.nextElement(); buffer.append("<tr>"); buffer.append("<td>" + headerName + "</td>"); buffer.append("<td>" + request.getHeader(headerName) + "</td>"); buffer.append("</tr>"); } buffer.append("</body>"); buffer.append("</html>"); out.println(buffer.toString()); } }
上述代碼中,通過調(diào)用request對(duì)象中的getMethod()方法來獲取用戶請(qǐng)求方式;調(diào)用getRequestURI()方法來獲取用戶請(qǐng)求路徑;調(diào)用getHeaderNames()方法返回所有請(qǐng)求報(bào)頭名稱的集合,遍歷此集合并使用getHeader()提取報(bào)頭信息顯示。
啟動(dòng)Tomcat,在IE中訪問http://localhost:8080/ch01/HttpHeadServlet,運(yùn)行結(jié)果如圖1-12所示。

圖1-12 請(qǐng)求報(bào)頭信息
1.5.3 設(shè)置HTTP響應(yīng)報(bào)頭
在Servlet中,可以通過HttpServletResponse的setHeader()方法來設(shè)置HTTP響應(yīng)報(bào)頭,它接收兩個(gè)參數(shù),用于指定響應(yīng)報(bào)頭的名稱和對(duì)應(yīng)的值,語法格式如下:
setHeader(String headerName,String headerValue)
常用的HTTP響應(yīng)報(bào)頭如表1-4所示。
表1-4 常用的HTTP響應(yīng)報(bào)頭

注意 一些舊版本的瀏覽器只支持HTTP 1.0的報(bào)頭,所以,為了保證程序具有良好的兼容性,應(yīng)該慎重地使用這些報(bào)頭,或者使用HttpServletRequest的getRequestProtocol()方法獲得HTTP的版本后再做選擇。
除了setHeader()方法外,還有兩個(gè)方法用于設(shè)置日期或者整型數(shù)據(jù)格式報(bào)頭:
setDateHeader(String headerName, long ms)
和
setIntHeader(String headerName, int headerValue)
此外,對(duì)于一些常用的報(bào)頭,在API中也提供了更方便的方法來設(shè)置它們,如表1-5所示。
表1-5 HttpServletResponse響應(yīng)方法

下述代碼用于實(shí)現(xiàn)任務(wù)描述1.D.4,通過設(shè)置響應(yīng)報(bào)頭,實(shí)現(xiàn)動(dòng)態(tài)時(shí)鐘。
【描述1.D.4】DateServlet.java
public class DateServlet extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 獲得一個(gè)向客戶發(fā)送數(shù)據(jù)的輸出流 response.setContentType("text/html; charset=GBK");// 設(shè)置響應(yīng)的MIME類型 PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<body>"); response.setHeader("Refresh", "1"); // 設(shè)置Refresh的值 out.println("現(xiàn)在時(shí)間是:"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); out.println("<br/>" + sdf.format(new Date())); out.println("</body>"); out.println("</html>"); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
上述代碼中,通過設(shè)置響應(yīng)報(bào)頭,使得客戶端每隔一秒訪問一次當(dāng)前Servlet,從而在客戶端能夠動(dòng)態(tài)地觀察時(shí)鐘的變化。實(shí)現(xiàn)每隔一秒動(dòng)態(tài)刷新的功能代碼如下:
response.setHeader("Refresh", "1");
其中,Refresh為響應(yīng)頭部信息;1是時(shí)間間隔值,以秒為單位。
啟動(dòng)Tomcat,在IE中訪問http://localhost:8080/ch01/DateServlet,運(yùn)行結(jié)果如圖1-13所示。

圖1-13 動(dòng)態(tài)時(shí)鐘
注意 在任務(wù)描述1.D.4中,通過不斷地刷新當(dāng)前頁面來訪問DateServlet,從而實(shí)現(xiàn)了動(dòng)態(tài)時(shí)鐘,在本書第8章通過AJAX技術(shù)可以實(shí)現(xiàn)無刷新時(shí)鐘,讀者可以通過觀察顯示效果對(duì)這兩種方式進(jìn)行比較。
1.6 重定向和請(qǐng)求轉(zhuǎn)發(fā)
重定向和請(qǐng)求轉(zhuǎn)發(fā)是Servlet處理完數(shù)據(jù)后進(jìn)行頁面跳轉(zhuǎn)的兩種主要方式。
1.6.1 重定向
重定向是指頁面重新定位到某個(gè)新地址,之前的Request失效,進(jìn)入一個(gè)新的Request,且跳轉(zhuǎn)后瀏覽器地址欄內(nèi)容將變?yōu)樾碌闹付ǖ刂贰V囟ㄏ蚴峭ㄟ^HttpServletResponse對(duì)象的sendRedirect()方法來實(shí)現(xiàn)的,該方法用于生成302響應(yīng)碼和Location響應(yīng)頭,從而通知客戶端去重新訪問Location響應(yīng)頭中指定的URL,其語法格式如下:
pubilc void sendRedirect(java.lang.String location)throws java.io.IOException
其中:
■ location參數(shù)指定了重定向的URL,它可以是相對(duì)路徑也可以是絕對(duì)路徑。
使用sendRedirect()方法不僅可以重定向到當(dāng)前應(yīng)用程序中的其他資源,還可以重定向到其他應(yīng)用程序中的資源,例如:
response.sendRedirect("/ch01/index.html");
上面語句重定向到當(dāng)前站點(diǎn)(ch01)的根目錄下的index.html界面。
下述代碼用于實(shí)現(xiàn)任務(wù)描述1.D.5,使用請(qǐng)求重定向方式使用戶自動(dòng)訪問重定向后的頁面。
【描述1.D.5】RedirectServlet.java
public class RedirectServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html; charset="GBK"); PrintWriter out = response.getWriter(); out.println("重定向前"); response.sendRedirect(request.getContextPath() + "/myservlet"); out.println("重定向后"); } }
在web.xml配置文件中配置RedirectServlet的<url-pattern>為“/redirect”。
其中,myservlet對(duì)應(yīng)的Servlet代碼如下所示。
【描述1.D.5】MyServlet.java
public class MyServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 設(shè)置響應(yīng)到客戶端的文本類型為HTML response.setContentType("text/html; charset=GBK"); // 獲取輸出流 PrintWriter out = response.getWriter(); out.println("重定向和請(qǐng)求轉(zhuǎn)發(fā)"); } }
在web.xml配置文件中配置MyServlet的<url-pattern>為“/myservlet”。
啟動(dòng)Tomcat,在IE中訪問http://localhost:8080/ch01/redirect,顯示出了MyServlet輸出網(wǎng)頁中的內(nèi)容,這時(shí)瀏覽器地址欄中的地址變成了MyServlet的URL“http://localhost:8080/ch01/myservlet”,結(jié)果如圖1-14所示。

圖1-14 重定向地址欄變化
1.6.2 請(qǐng)求轉(zhuǎn)發(fā)
請(qǐng)求轉(zhuǎn)發(fā)是指將請(qǐng)求再轉(zhuǎn)發(fā)到另一頁面,此過程依然在Request范圍內(nèi),轉(zhuǎn)發(fā)后瀏覽器地址欄內(nèi)容不變。請(qǐng)求轉(zhuǎn)發(fā)使用RequestDispatcher接口中的forward()方法來實(shí)現(xiàn),該方法可以把請(qǐng)求轉(zhuǎn)發(fā)到另外一個(gè)資源,并讓該資源對(duì)瀏覽器的請(qǐng)求進(jìn)行響應(yīng)。
RequestDispatcher接口有以下兩個(gè)方法。
■ forward()方法:請(qǐng)求轉(zhuǎn)發(fā),可以從當(dāng)前Servlet跳轉(zhuǎn)到其他Servlet。
■ include()方法:引入其他Servlet。
RequestDispatcher是一個(gè)接口,通過使用HttpRequest對(duì)象的getRequestDispalcher()方法可以獲得該接口的實(shí)例對(duì)象,例如:
RequestDispatcher rd = request.getRequestDispatcher(path); rd.forward(request,response);
下述代碼用于實(shí)現(xiàn)任務(wù)描述1.D.5,使用請(qǐng)求轉(zhuǎn)發(fā)方式使用戶自動(dòng)訪問請(qǐng)求轉(zhuǎn)發(fā)后的頁面。
【描述1.D.5】ForwardServlet.java
//請(qǐng)求轉(zhuǎn)發(fā) public class ForwardServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html; charset=GBK"); PrintWriter out = response.getWriter(); out.println("請(qǐng)求轉(zhuǎn)發(fā)前"); RequestDispatcher rd = request.getRequestDispatcher("/myservlet"); rd.forward(request, response); out.println("請(qǐng)求轉(zhuǎn)發(fā)后"); } }
在IE中訪問http://localhost:8080/ch01/forward,瀏覽器中顯示出了MyServlet輸出網(wǎng)頁中的內(nèi)容,這時(shí)瀏覽器地址欄中的地址不會(huì)發(fā)生改變,結(jié)果如圖1-15所示。

圖1-15 請(qǐng)求轉(zhuǎn)發(fā)地址欄變化
通過上述ForwardServlet和RedirectServlet的運(yùn)行結(jié)果可以看出,轉(zhuǎn)發(fā)和重定向兩種方式在調(diào)用后地址欄中的URL是不同的,前者的地址欄不變,后者地址欄中的URL變成目標(biāo)URL。
此外,轉(zhuǎn)發(fā)和重定向最主要的區(qū)別是:轉(zhuǎn)發(fā)前后共享同一個(gè)request對(duì)象,而重定向前后不在一個(gè)請(qǐng)求中。
為了驗(yàn)證請(qǐng)求轉(zhuǎn)發(fā)和重定向的區(qū)別,在示例中會(huì)用到HttpServletRequest的存取和讀取屬性值的兩個(gè)方法。
■ getAttribute(String name):取得name的屬性值,如果屬性不存在則返回null。
■ setAttribute(String name,Object value):將value對(duì)象以name名稱綁定到request對(duì)象中。
注意 除HttpServletRequest接口外,HttpSession和ServletContext接口也擁有g(shù)etAttribute()和setAttribute()方法,分別用來讀取和設(shè)置這兩類對(duì)象中的屬性值。
下述內(nèi)容用于實(shí)現(xiàn)任務(wù)描述1.D.5,通過請(qǐng)求參數(shù)的傳遞來驗(yàn)證forward()方法和sendRedirect()方法在request對(duì)象共享上的區(qū)別。
(1)改寫RedirectServlet,在sendRedirect()方法中加上查詢字符串。
【描述1.D.5】RedirectServlet.java
public class RedirectServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html; charset=GBK"); PrintWriter out = response.getWriter(); request.setAttribute("test","helloworld"); out.println("重定向前"); response.sendRedirect(request.getContextPath() + "/myservlet "); out.println("重定向后"); } }
上述代碼中,調(diào)用了setAttribute()方法把test屬性值helloworld存儲(chǔ)到request對(duì)象中。
(2)改寫MyServlet,獲取request對(duì)象中的test屬性值。
【描述1.D.5】MyServlet.java
public class MyServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 設(shè)置響應(yīng)到客戶端的文本類型為HTML response.setContentType("text/html; charset=GBK"); String test =(String)request.getAttribute("test"); // 獲取輸出流 PrintWriter out = response.getWriter(); out.println("重定向和請(qǐng)求轉(zhuǎn)發(fā)"); out.println(test); } }
上述代碼中,從request對(duì)象中獲取test屬性值。
啟動(dòng)Tomcat,在IE中訪問http://localhost:8080/ch01/redirect,運(yùn)行結(jié)果如下:
重定向和請(qǐng)求轉(zhuǎn)發(fā)null
由此可知,在MyServlet中的request對(duì)象中并沒有獲得RedirectServlet中request對(duì)象設(shè)置的值。
(3)改寫ForwardServlet,獲取request對(duì)象中的test屬性值。
【描述1.D.5】ForwardServlet.java
// 請(qǐng)求轉(zhuǎn)發(fā) public class ForwardServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html; charset=GBK"); request.setAttribute("test","helloworld"); PrintWriter out = response.getWriter(); out.println("請(qǐng)求轉(zhuǎn)發(fā)前"); RequestDispatcher rd = request.getRequestDispatcher("/myservlet"); rd.forward(request, response); out.println("請(qǐng)求轉(zhuǎn)發(fā)后"); } }
上述代碼中,從request對(duì)象中獲取test屬性值。
啟動(dòng)Tomcat,在IE中訪問http://localhost:8080/ch01/forward,運(yùn)行結(jié)果如下:
重定向和請(qǐng)求轉(zhuǎn)發(fā)helloworld
由此可知,在MyServlet中的request對(duì)象中獲得了ForwardServlet的request對(duì)象設(shè)置的值。
通過對(duì)上述示例的運(yùn)行結(jié)果進(jìn)行比較,forward()和sendRedirect()兩者的區(qū)別總結(jié)如下:
■ forward()只能將請(qǐng)求轉(zhuǎn)發(fā)給同一個(gè)Web應(yīng)用中的組件,而sendRedirect()方法不僅可以重定向到當(dāng)前應(yīng)用程序中的其他資源,還可以重定向到其他站點(diǎn)中的資源。如果傳給sendRedirect()方法的相對(duì)URL以“/”開頭,它是相對(duì)于整個(gè)Web站點(diǎn)的根目錄;如果創(chuàng)建RequestDispatcher對(duì)象時(shí)指定的相對(duì)URL以“/”開頭,它是相對(duì)于當(dāng)前Web應(yīng)用程序的根目錄。
■ sendRedirect()方法重定向的訪問過程結(jié)束后,瀏覽器地址欄中顯示的URL會(huì)發(fā)生改變,由初始的URL地址變成重定向的目標(biāo)URL;而調(diào)用forward()方法的請(qǐng)求轉(zhuǎn)發(fā)過程結(jié)束后,瀏覽器地址欄保持初始的URL地址不變。
■ forward()方法的調(diào)用者與被調(diào)用者之間共享相同的request對(duì)象和response對(duì)象,它們屬于同一個(gè)請(qǐng)求和響應(yīng)過程;而sendRedirect()方法調(diào)用者和被調(diào)用者使用各自的request對(duì)象和response對(duì)象,它們屬于兩個(gè)獨(dú)立的請(qǐng)求和響應(yīng)過程。
1.7 小結(jié)
通過本章的學(xué)習(xí),學(xué)生應(yīng)該能夠?qū)W會(huì):
■ 動(dòng)態(tài)網(wǎng)站開發(fā)技術(shù)有Servlet、JSP、PHP、ASP、ASP.NET和CGI等。
■ Servlet是運(yùn)行在服務(wù)器端的Java程序,內(nèi)嵌HTML。
■ Servlet生命周期的三個(gè)方法分別是init()、service()和destroy()。
■ Servlet處理GET和POST請(qǐng)求時(shí)分別使用doGet()和doPost()方法進(jìn)行處理。
■ HttpServletRequest的getParameter(“參數(shù)名稱”)獲取表單、URL參數(shù)值。
■ HttpServletResponse的getWriter()獲取向客戶端發(fā)送信息的輸出流。
■ HttpServletRequest的getHeader(“報(bào)頭名稱”)獲取相關(guān)報(bào)頭信息。
■ 請(qǐng)求轉(zhuǎn)發(fā)和重定向都可以使瀏覽器獲得另外一個(gè)URL所指向的資源。
■ 請(qǐng)求轉(zhuǎn)發(fā)通常由RequestDispatcher接口的forward()方法實(shí)現(xiàn),轉(zhuǎn)發(fā)前后共享同一個(gè)請(qǐng)求對(duì)象。
■ 重定向由HttpServletResponse接口的sendRedirect()方法實(shí)現(xiàn),重定向不共享同一個(gè)請(qǐng)求對(duì)象。
練習(xí)
1. 下列選項(xiàng)中屬于動(dòng)態(tài)網(wǎng)站技術(shù)的是______。(多選)
A. PHP
B. ASP
C. JavaScript
D. JSP
2. 下列關(guān)于Servlet的說法正確的是______。(多選)
A. Servlet是一種動(dòng)態(tài)網(wǎng)站技術(shù)
B. Servlet運(yùn)行在服務(wù)器端
C. Servlet針對(duì)每個(gè)請(qǐng)求使用1個(gè)進(jìn)程來處理
D. Servlet與普通的Java類一樣,可以直接運(yùn)行,不需要環(huán)境支持
3. 下列關(guān)于Servlet的編寫方式正確的是______。(多選)
A. 必須是HttpServlet的子類
B. 通常需要覆蓋doGet()和doPost()方法或其中之一
C. 通常需要覆蓋service()方法
D. 通常需要在web.xml文件中聲明<servlet>和<servlet-mapping>兩個(gè)元素
4. 下列關(guān)于Servlet生命周期的說法正確的是______。(多選)
A. 構(gòu)造方法只會(huì)調(diào)用一次,在容器啟動(dòng)時(shí)調(diào)用
B. init()方法只會(huì)調(diào)用一次,在第一次請(qǐng)求此Servlet時(shí)調(diào)用
C. service()方法在每次請(qǐng)求此Servlet時(shí)都會(huì)被調(diào)用
D. destroy()方法在每次請(qǐng)求完畢時(shí)會(huì)被調(diào)用
5. 下列方式中可以執(zhí)行TestServlet(路徑為 /test)的doPost()方法的是______。(多選)
A. 在IE中直接訪問http://localhost:8080/網(wǎng)站名/test
B. <form action="/網(wǎng)站名/test"> 提交此表單
C. <form action="/網(wǎng)站名/test" method="post"> 提交此表單
D. <form id="form1">,在JavaScript中執(zhí)行下述代碼:
document.getElementById("form1").action="/網(wǎng)站名/test"; document.getElementById("form1").method="post"; document.getElementById("form1").submit();
6. 針對(duì)下述JSP頁面,在Servlet中需要得到用戶選擇的愛好的數(shù)量,最合適的代碼是______。
<input type="checkbox" name="aihao" value="1"/>游戲<br/> <input type="checkbox" name="aihao" value="2"/>運(yùn)動(dòng)<br/> <input type="checkbox" name="aihao" value="3"/>棋牌<br/> <input type="checkbox" name="aihao" value="4"/>美食<br/>
A. request.getParameter("aihao").length
B. request.getParameter("aihao").size()
C. request.getParameterValues("aihao").length
D. request.getParameterValues("aihao").size()
7. 用戶使用POST方式提交的數(shù)據(jù)中存在漢字(使用GBK字符集),在Servlet中需要使用下述______語句處理。
A. request.setCharacterEncoding("GBK");
B. request.setContentType("text/html;charset=GBK");
C. response.setCharacterEncoding("GBK");
D. response.setContentType("text/html;charset=GBK");
8. 簡述Servlet的生命周期。Servlet在第一次和第二次被訪問時(shí),其生命周期方法的執(zhí)行有何區(qū)別?
9. 簡述轉(zhuǎn)發(fā)和重定向兩種頁面跳轉(zhuǎn)方式的區(qū)別,在Servlet中分別使用什么方法實(shí)現(xiàn)?
- UI圖標(biāo)創(chuàng)意設(shè)計(jì)
- Mastering ServiceStack
- 樂學(xué)Web編程:網(wǎng)站制作不神秘
- 微信小程序項(xiàng)目開發(fā)實(shí)戰(zhàn)
- RabbitMQ Essentials
- R用戶Python學(xué)習(xí)指南:數(shù)據(jù)科學(xué)方法
- HoloLens與混合現(xiàn)實(shí)開發(fā)
- Test-Driven JavaScript Development
- Qt5 C++ GUI Programming Cookbook
- Distributed Computing in Java 9
- Java程序設(shè)計(jì)教程
- 百萬在線:大型游戲服務(wù)端開發(fā)
- C語言程序設(shè)計(jì)
- 打造流暢的Android App
- Bioinformatics with Python Cookbook