金年会 金字招牌诚信至上,金年会 金字招牌诚信至上,金年会 金字招牌诚信至上,金年会 金字招牌诚信至上

91手機維修論壇

標題: jsp教程 [打印本頁(yè)]

作者: firstcosmos    時(shí)間: 2005-12-15 18:37
標題: jsp教程
<>一、Servlet和JSP概述 <BR> <BR> <BR>1.1 Java Servlet及其特點(diǎn) </P>
<>   Servlet是Java技術(shù)對CGI編程的回答。Servlet程序在服務(wù)器端運行,動(dòng)態(tài)地生成Web頁(yè)面。與傳統的CGI和許多其他類(lèi)似CGI的技術(shù)相比,Java Servlet具有更高的效率,更容易使用,功能更強大,具有更好的可移植性,更節省投資(更重要的是, Servlet程序員收入要比Perl程序員高:-): </P>
<>高效。</P>
<P>在傳統的CGI中,每個(gè)請求都要啟動(dòng)一個(gè)新的進(jìn)程,如果CGI程序本身的執行時(shí)間較短,啟動(dòng)進(jìn)程所需要的開(kāi)銷(xiāo)很可能反而超過(guò)實(shí)際執行時(shí)間。而在Servlet中,每個(gè)請求由一個(gè)輕量級的Java線(xiàn)程處理(而不是重量級的操作系統進(jìn)程)。<BR>在傳統CGI中,如果有N個(gè)并發(fā)的對同一CGI程序的請求,則該CGI程序的代碼在內存中重復裝載了N次;而對于Servlet,處理請求的是N個(gè)線(xiàn)程,只需要一份Servlet類(lèi)代碼。在性能優(yōu)化方面,Servlet也比CGI有著(zhù)更多的選擇,比如緩沖以前的計算結果,保持數據庫連接的活動(dòng),等等。</P>
<P><BR>方便。</P>
<P>Servlet提供了大量的實(shí)用工具例程,例如自動(dòng)地解析和解碼HTML表單數據、讀取和設置HTTP頭、處理Cookie、跟蹤會(huì )話(huà)狀態(tài)等。</P>
<P><BR>功能強大。</P>
<P>在Servlet中,許多使用傳統CGI程序很難完成的任務(wù)都可以輕松地完成。例如,Servlet能夠直接和Web服務(wù)器交互,而普通的CGI程序不能。Servlet還能夠在各個(gè)程序之間共享數據,使得數據庫連接池之類(lèi)的功能很容易實(shí)現。</P>
<P><BR>可移植性好。</P>
<P>Servlet用Java編寫(xiě),Servlet API具有完善的標準。因此,為I-Planet Enterprise Server寫(xiě)的Servlet無(wú)需任何實(shí)質(zhì)上的改動(dòng)即可移植到Apache、Microsoft IIS或者WebStar。幾乎所有的主流服務(wù)器都直接或通過(guò)插件支持Servlet。</P>
<P><BR>節省投資。</P>
<P>不僅有許多廉價(jià)甚至免費的Web服務(wù)器可供個(gè)人或小規模網(wǎng)站使用,而且對于現有的服務(wù)器,如果它不支持Servlet的話(huà),要加上這部分功能也往往是免費的(或只需要極少的投資)。 <BR>   1.2 JSP及其特點(diǎn) </P>
<P>   JavaServer Pages(JSP)是一種實(shí)現普通靜態(tài)HTML和動(dòng)態(tài)HTML混合編碼的技術(shù),有關(guān)JSP基礎概念的說(shuō)明請參見(jiàn)《JSP技術(shù)簡(jiǎn)介 》。 </P>
<P>   許多由CGI程序生成的頁(yè)面大部分仍舊是靜態(tài)HTML,動(dòng)態(tài)內容只在頁(yè)面中有限的幾個(gè)部分出現。但是包括Servlet在內的大多數CGI技術(shù)及其變種,總是通過(guò)程序生成整個(gè)頁(yè)面。JSP使得我們可以分別創(chuàng )建這兩個(gè)部分。例如,下面就是一個(gè)簡(jiǎn)單的JSP頁(yè)面: <BR><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><BR><HTML><BR><HEAD><TITLE>歡迎訪(fǎng)問(wèn)網(wǎng)上商店</TITLE></HEAD><BR><BODY><BR><H1>歡迎</H1><BR><SMALL>歡迎,<BR><!-- 首次訪(fǎng)問(wèn)的用戶(hù)名字為"New User" --> <BR><% out.println(Utils.getUserNameFromCookie(request)); %><BR>要設置帳號信息,請點(diǎn)擊<BR><A HREF="Account-Settings.html">這里</A></SMALL><BR><P><BR>頁(yè)面的其余內容。.<BR></BODY></HTML></P>

<P>   下面是JSP和其他類(lèi)似或相關(guān)技術(shù)的一個(gè)簡(jiǎn)單比較: </P>
<P>JSP和Active Server Pages(ASP)相比</P>
<P>Microsoft的ASP是一種和JSP類(lèi)似的技術(shù)。JSP和ASP相比具有兩方面的優(yōu)點(diǎn)。首先,動(dòng)態(tài)部分用Java編寫(xiě),而不是VB Script或其他Microsoft語(yǔ)言,不僅功能更強大而且更易于使用。第二,JSP應用可以移植到其他操作系統和非Microsoft的Web服務(wù)器上。</P>
<P><BR>JSP和純Servlet相比</P>
<P>JSP并沒(méi)有增加任何本質(zhì)上不能用Servlet實(shí)現的功能。但是,在JSP中編寫(xiě)靜態(tài)HTML更加方便,不必再用 println語(yǔ)句來(lái)輸出每一行HTML代碼。更重要的是,借助內容和外觀(guān)的分離,頁(yè)面制作中不同性質(zhì)的任務(wù)可以方便地分開(kāi):比如,由頁(yè)面設計專(zhuān)家進(jìn)行HTML設計,同時(shí)留出供Servlet程序員插入動(dòng)態(tài)內容的空間。</P>
<P><BR>JSP和服務(wù)器端包含(Server-Side Include,SSI)相比</P>
<P>SSI是一種受到廣泛支持的在靜態(tài)HTML中引入外部代碼的技術(shù)。JSP在這方面的支持更為完善,因為它可以用Servlet而不是獨立的程序來(lái)生成動(dòng)態(tài)內容。另外,SSI實(shí)際上只用于簡(jiǎn)單的包含,而不是面向那些能夠處理表單數據、訪(fǎng)問(wèn)數據庫的“真正的”程序。</P>
<P><BR>JSP和JavaScript相比</P>
<P>JavaScript能夠在客戶(hù)端動(dòng)態(tài)地生成HTML。雖然JavaScript很有用,但它只能處理以客戶(hù)端環(huán)境為基礎的動(dòng)態(tài)信息。除了Cookie之外,HTTP狀態(tài)和表單提交數據對JavaScript來(lái)說(shuō)都是不可用的。另外,由于是在客戶(hù)端運行,JavaScript不能訪(fǎng)問(wèn)服務(wù)器端資源,比如數據庫、目錄信息等等。  <BR></P>
作者: firstcosmos    時(shí)間: 2005-12-15 18:37
<>二、設置開(kāi)發(fā)、運行環(huán)境 <BR> <BR>2.1 安裝Servlet和JSP開(kāi)發(fā)工具 </P>
<>   要學(xué)習Servlet和JSP開(kāi)發(fā),首先你必須準備一個(gè)符合Java Servlet 2.1/2.2和JavaServer Pages1.0/1.1規范的開(kāi)發(fā)環(huán)境。Sun提供免費的JavaServer Web Development Kit(JSWDK),可以從<a href="http://java.sun.com/products/servlet/" target="_blank" >http://java.sun.com/products/servlet/</A>下載。 </P>
<>   安裝好JSWDK之后,你還要告訴javac,在編譯文件的時(shí)候到哪里去尋找Servlet和JSP類(lèi)。JSWDK安裝指南對此有詳細說(shuō)明,但主要就是把servlet.jar和jsp.jar加入CLASSPATH。CLASSPATH是一個(gè)指示Java如何尋找類(lèi)文件的環(huán)境變量,如果不設置CLASSPATH,Java在當前目錄和標準系統庫中尋找類(lèi);如果你自己設置了CLASSPATH,不要忘記包含當前目錄(即在CLASSPATH中包含“.”)。 </P>
<P>   另外,為了避免和其他開(kāi)發(fā)者安裝到同一Web服務(wù)器上的Servlet產(chǎn)生命名沖突,最好把自己的Servlet放入包里面。此時(shí),把包層次結構中的頂級目錄也加入CLASSPATH會(huì )帶來(lái)不少方便。請參見(jiàn)下文具體說(shuō)明。 </P>
<P>   2.2 安裝支持Servlet的Web服務(wù)器 </P>
<P>   除了開(kāi)發(fā)工具之外,你還要安裝一個(gè)支持Java Servlet的Web服務(wù)器,或者在現有的Web服務(wù)器上安裝Servlet軟件包。如果你使用的是最新的Web服務(wù)器或應用服務(wù)器,很可能它已經(jīng)有了所有必需的軟件。請查看Web服務(wù)器的文檔,或訪(fǎng)問(wèn)<a href="http://java.sun.com/products/servlet/industry.html" target="_blank" >http://java.sun.com/products/servlet/industry.html</A>查看支持Servlet的服務(wù)器軟件清單。 </P>
<P>   雖然最終運行Servlet的往往是商業(yè)級的服務(wù)器,但是開(kāi)始學(xué)習的時(shí)候,用一個(gè)能夠在臺式機上運行的免費系統進(jìn)行開(kāi)發(fā)和測試也足夠了。下面是幾種當前最受歡迎的產(chǎn)品。 </P>
<P>Apache Tomcat. </P>
<P>Tomcat是Servlet 2.2和JSP 1.1規范的官方參考實(shí)現。Tomcat既可以單獨作為小型Servlet、JSP測試服務(wù)器,也可以集成到Apache Web服務(wù)器。直到2000年早期,Tomcat還是唯一的支持Servlet 2.2和JSP 1.1規范的服務(wù)器,但已經(jīng)有許多其它服務(wù)器宣布提供這方面的支持。</P>
<P>Tomcat和Apache一樣是免費的。不過(guò),快速、穩定的Apache服務(wù)器安裝和配置起來(lái)有點(diǎn)麻煩,Tomcat也有同樣的缺點(diǎn)。和其他商業(yè)級Servlet引擎相比,配置Tomcat的工作量顯然要多一點(diǎn)。具體請參見(jiàn)<a href="http://jakarta.apache.org/" target="_blank" >http://jakarta.apache.org/</A>。</P>
<P><BR>JavaServer Web Development Kit (JSWDK). </P>
<P>JSWDK是Servlet 2.1和JSP 1.0的官方參考實(shí)現。把Servlet和JSP應用部署到正式運行它們的服務(wù)器之前,JSWDK可以單獨作為小型的Servlet、JSP測試服務(wù)器。JSWDK也是免費的,而且具有很好的穩定性,但它的安裝和配置也較為復雜。具體請參見(jiàn)<a href="http://java.sun.com/products/servlet/download.html" target="_blank" >http://java.sun.com/products/servlet/download.html</A>。</P>
<P><BR>Allaire JRun. </P>
<P>JRun是一個(gè)Servlet和JSP引擎,它可以集成到Netscape Enterprise或FastTrack Server、IIS、Microsoft Personal Web Server、版本較低的Apache、O'eilly的WebSite或者StarNine Web STAR。最多支持5個(gè)并發(fā)連接的限制版本是免費的,商業(yè)版本中不存在這個(gè)限制,而且增加了遠程管理控制臺之類(lèi)的功能。具體請參見(jiàn)<a href="http://www.allaire.com/products/jrun/" target="_blank" >http://www.allaire.com/products/jrun/</A>。</P>
<P><BR>New Atlanta 的ServletExec </P>
<P>ServletExec是一個(gè)快速的Servlet和JSP引擎,它可以集成到大多數流行的Web服務(wù)器,支持平臺包括Solaris、Windows、MacOS、HP-UX和Linux。ServletExec可以免費下載和使用,但許多高級功能和管理工具只有在購買(mǎi)了許可之后才可以使用。New Atlanta還提供一個(gè)免費的Servlet調試器,該調試器可以在許多流行的Java IDE下工作。具體請參見(jiàn)<a href="http://newatlanta.com/" target="_blank" >http://newatlanta.com/</A>。</P>
<P><BR>Gefion的LiteWebServer (LWS) </P>
<P>LWS是一個(gè)支持Servlet 2.2和JSP 1.1的免費小型Web服務(wù)器。 Gefion還有一個(gè)免費的WAICoolRunner插件,利用該插件可以為Netscape FastTrack和Enterprise Server增加Servlet 2.2和JSP 1.1支持。具體請參見(jiàn)<a href="http://www.gefionsoftware.com/" target="_blank" >http://www.gefionsoftware.com/</A>。</P>
<P><BR>Sun的Java Web Server. </P>
<P>該服務(wù)器全部用Java寫(xiě)成,而且是首先提供Servlet 2.1和JSP 1.0規范完整支持的Web服務(wù)器之一。雖然Sun現在已轉向Netscape/I-Planet Server,不再發(fā)展Java Web Server,但它仍舊是一個(gè)廣受歡迎的Servlet、JSP學(xué)習平臺。要得到免費試用版本,請訪(fǎng)問(wèn)<a href="http://www.sun.com/software/jwebserver/try/" target="_blank" >http://www.sun.com/software/jwebserver/try/</A>.  <BR></P>
作者: firstcosmos    時(shí)間: 2005-12-15 18:37
<>三、第一個(gè)Servlet <BR> <BR> <BR>3.1 Servlet基本結構 </P>
<>   下面的代碼顯示了一個(gè)簡(jiǎn)單Servlet的基本結構。該Servlet處理的是GET請求,所謂的GET請求,如果你不熟悉HTTP,可以把它看成是當用戶(hù)在瀏覽器地址欄輸入URL、點(diǎn)擊Web頁(yè)面中的鏈接、提交沒(méi)有指定METHOD的表單時(shí)瀏覽器所發(fā)出的請求。Servlet也可以很方便地處理POST請求。POST請求是提交那些指定了METHOD=“POST”的表單時(shí)所發(fā)出的請求,具體請參見(jiàn)稍后幾節的討論。 <BR>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;</P>
<>public class SomeServlet extends HttpServlet {<BR>  public void doGet(HttpServletRequest request,<BR>                    HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>      <BR>  // 使用“request”讀取和請求有關(guān)的信息(比如Cookies)<BR>  // 和表單數據<BR>    <BR>    // 使用“response”指定HTTP應答狀態(tài)代碼和應答頭<BR>    // (比如指定內容類(lèi)型,設置Cookie)<BR>    <BR>    PrintWriter out = response.getWriter();<BR>    // 使用 "out"把應答內容發(fā)送到瀏覽器<BR>  }<BR>}</P>

<P><BR>   如果某個(gè)類(lèi)要成為Servlet,則它應該從HttpServlet 繼承,根據數據是通過(guò)GET還是POST發(fā)送,覆蓋doGet、doPost方法之一或全部。doGet和doPost方法都有兩個(gè)參數,分別為HttpServletRequest 類(lèi)型和HttpServletResponse 類(lèi)型。HttpServletRequest提供訪(fǎng)問(wèn)有關(guān)請求的信息的方法,例如表單數據、HTTP請求頭等等。HttpServletResponse除了提供用于指定HTTP應答狀態(tài)(200,404等)、應答頭(Content-Type,Set-Cookie等)的方法之外,最重要的是它提供了一個(gè)用于向客戶(hù)端發(fā)送數據的PrintWriter 。對于簡(jiǎn)單的Servlet來(lái)說(shuō),它的大部分工作是通過(guò)println語(yǔ)句生成向客戶(hù)端發(fā)送的頁(yè)面。 </P>
<P>   注意doGet和doPost拋出兩個(gè)異常,因此你必須在聲明中包含它們。另外,你還必須導入java.io包(要用到PrintWriter等類(lèi))、javax.servlet包(要用到HttpServlet等類(lèi))以及javax.servlet.http包(要用到HttpServletRequest類(lèi)和HttpServletResponse類(lèi))。 </P>
<P>   最后,doGet和doPost這兩個(gè)方法是由service方法調用的,有時(shí)你可能需要直接覆蓋service方法,比如Servlet要處理GET和POST兩種請求時(shí)。 </P>
<P>   3.2 輸出純文本的簡(jiǎn)單Servlet </P>
<P>   下面是一個(gè)輸出純文本的簡(jiǎn)單Servlet。 </P>
<P>   3.2.1 HelloWorld.java <BR>package hall;</P>
<P>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;</P>
<P>public class HelloWorld extends HttpServlet {<BR>  public void doGet(HttpServletRequest request,<BR>                  HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    PrintWriter out = response.getWriter();<BR>    out.println("Hello World");<BR>  }<BR>}</P>

<P><BR>   3.2.2 Servlet的編譯和安裝 </P>
<P>   不同的Web服務(wù)器上安裝Servlet的具體細節可能不同,請參考Web服務(wù)器文檔了解更權威的說(shuō)明。假定使用Java Web Server(JWS)2.0,則Servlet應該安裝到JWS安裝目錄的servlets子目錄下。在本文中,為了避免同一服務(wù)器上不同用戶(hù)的Servlet命名沖突,我們把所有Servlet都放入一個(gè)獨立的包hall中;如果你和其他人共用一個(gè)服務(wù)器,而且該服務(wù)器沒(méi)有“虛擬服務(wù)器”機制來(lái)避免這種命名沖突,那么最好也使用包。把Servlet放入了包hall之后,HelloWorld.java實(shí)際上是放在servlets目錄的hall子目錄下。 </P>
<P>   大多數其他服務(wù)器的配置方法也相似,除了JWS之外,本文的Servlet和JSP示例已經(jīng)在BEA WebLogic和IBM WebSphere 3.0下經(jīng)過(guò)測試。WebSphere具有優(yōu)秀的虛擬服務(wù)器機制,因此,如果只是為了避免命名沖突的話(huà)并非一定要用包。 </P>
<P>   對于沒(méi)有使用過(guò)包的初學(xué)者,下面我們介紹編譯包里面的類(lèi)的兩種方法。 </P>
<P>   一種方法是設置CLASSPATH,使其指向實(shí)際存放Servlet的目錄的上一級目錄(Servlet主目錄),然后在該目錄中按正常的方式編譯。例如,如果Servlet的主目錄是C:\JavaWebServer\servlets,包的名字(即主目錄下的子目錄名字)是hall,在Windows下,編譯過(guò)程如下: <BR>  DOS> set CLASSPATH=C:\JavaWebServer\servlets;%CLASSPATH%<BR>  DOS> cd C:\JavaWebServer\servlets\hall<BR>  DOS> javac YourServlet.java</P>

<P>   第二種編譯包里面的Servlet的方法是進(jìn)入Servlet主目錄,執行“javac directory\YourServlet.java”(Windows)或者“javac directory/YourServlet.java”(Unix)。例如,再次假定Servlet主目錄是C:\JavaWebServer\servlets,包的名字是hall,在Windows中編譯過(guò)程如下: <BR>  DOS> cd C:\JavaWebServer\servlets<BR>  DOS> javac hall\YourServlet.java</P>

<P>   注意在Windows下,大多數JDK 1.1版本的javac要求目錄名字后面加反斜杠(\)。JDK1.2已經(jīng)改正這個(gè)問(wèn)題,然而由于許多Web服務(wù)器仍舊使用JDK 1.1,因此大量的Servlet開(kāi)發(fā)者仍舊在使用JDK 1.1。 </P>
<P>   最后,Javac還有一個(gè)高級選項用于支持源代碼和.class文件的分開(kāi)放置,即你可以用javac的“-d”選項把.class文件安裝到Web服務(wù)器所要求的目錄。 </P>
<P>   3.2.3 運行Servlet </P>
<P>   在Java Web Server下,Servlet應該放到JWS安裝目錄的servlets子目錄下,而調用Servlet的URL是<a href="http://host/servlet/ServletName" target="_blank" >http://host/servlet/ServletName</A>。注意子目錄的名字是servlets(帶“s”),而URL使用的是“servlet”。由于HelloWorld Servlet放入包hall,因此調用它的URL應該是<a href="http://host/servlet/hall.HelloWorld" target="_blank" >http://host/servlet/hall.HelloWorld</A>。在其他的服務(wù)器上,安裝和調用Servlet的方法可能略有不同。 </P>
<P>   大多數Web服務(wù)器還允許定義Servlet的別名,因此Servlet也可能用<a href="http://host/any-path/any-file.html" target="_blank" >http://host/any-path/any-file.html</A>形式的URL調用。具體如何進(jìn)行配置完全依賴(lài)于服務(wù)器類(lèi)型,請參考服務(wù)器文檔了解細節。 </P>
<P>   3.3 輸出HTML的Servlet </P>
<P>   大多數Servlet都輸出HTML,而不象上例一樣輸出純文本。要輸出HTML還有兩個(gè)額外的步驟要做:告訴瀏覽器接下來(lái)發(fā)送的是HTML;修改println語(yǔ)句構造出合法的HTML頁(yè)面。 </P>
<P>   第一步通過(guò)設置Content-Type(內容類(lèi)型)應答頭完成。一般地,應答頭可以通過(guò)HttpServletResponse的setHeader方法設置,但由于設置內容類(lèi)型是一個(gè)很頻繁的操作,因此Servlet API提供了一個(gè)專(zhuān)用的方法setContentType。注意設置應答頭應該在通過(guò)PrintWriter發(fā)送內容之前進(jìn)行。下面是一個(gè)實(shí)例: </P>
<P>   HelloWWW.java <BR>package hall;</P>
<P>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;</P>
<P>public class HelloWWW extends HttpServlet {<BR>  public void doGet(HttpServletRequest request,<BR>                    HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    response.setContentType("text/html");<BR>    PrintWriter out = response.getWriter();<BR>    out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " +<BR>      "Transitional//EN\">\n" +<BR>                "<HTML>\n" +<BR>                "<HEAD><TITLE>Hello WWW</TITLE></HEAD>\n" +<BR>                "<BODY>\n" +<BR>                "<H1>Hello WWW</H1>\n" +<BR>                "</BODY></HTML>");<BR>  }<BR>}</P>

<P><BR>   3.4 幾個(gè)HTML工具函數 </P>
<P>   通過(guò)println語(yǔ)句輸出HTML并不方便,根本的解決方法是使用JavaServer Pages(JSP)。然而,對于標準的Servlet來(lái)說(shuō),由于Web頁(yè)面中有兩個(gè)部分(DOCTYPE和HEAD)一般不會(huì )改變,因此可以用工具函數來(lái)封裝生成這些內容的代碼。 </P>
<P>   雖然大多數主流瀏覽器都會(huì )忽略DOCTYPE行,但嚴格地說(shuō)HTML規范是要求有DOCTYPE行的,它有助于HTML語(yǔ)法檢查器根據所聲明的HTML版本檢查HTML文檔合法性。在許多Web頁(yè)面中,HEAD部分只包含<TITLE>。雖然許多有經(jīng)驗的編寫(xiě)者都會(huì )在HEAD中包含許多META標記和樣式聲明,但這里只考慮最簡(jiǎn)單的情況。 </P>
<P>   下面的Java方法只接受頁(yè)面標題為參數,然后輸出頁(yè)面的DOCTYPE、HEAD、TITLE部分。清單如下: </P>
<P>   ServletUtilities.java <BR>package hall;</P>
<P>public class ServletUtilities {<BR>  public static final String DOCTYPE =<BR>    "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">";</P>
<P>  public static String headWithTitle(String title) {<BR>    return(DOCTYPE + "\n" +<BR>           "<HTML>\n" +<BR>           "<HEAD><TITLE>" + title + "</TITLE></HEAD>\n");<BR>  }</P>
<P>  // 其他工具函數的代碼在本文后面介紹<BR>}</P>

<P><BR>   HelloWWW2.java </P>
<P>   下面是應用了ServletUtilities之后重寫(xiě)HelloWWW類(lèi)得到的HelloWWW2: <BR>package hall;</P>
<P>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;</P>
<P>public class HelloWWW2 extends HttpServlet {<BR>  public void doGet(HttpServletRequest request,<BR>                    HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    response.setContentType("text/html");<BR>    PrintWriter out = response.getWriter();<BR>    out.println(ServletUtilities.headWithTitle("Hello WWW") +<BR>                "<BODY>\n" +<BR>                "<H1>Hello WWW</H1>\n" +<BR>                "</BODY></HTML>");<BR>  }<BR>}<BR> <BR></P>
作者: firstcosmos    時(shí)間: 2005-12-15 18:38
<>四、處理表單數據 <BR> <BR> <BR>4.1 表單數據概述 </P>
<>   如果你曾經(jīng)使用過(guò)Web搜索引擎,或者瀏覽過(guò)在線(xiàn)書(shū)店、股票價(jià)格、機票信息,或許會(huì )留意到一些古怪的URL,比如“http://host/path?user=Marty+Hall&amp;;origin=bwi&amp;dest=lax”。這個(gè)URL中位于問(wèn)號后面的部分,即“user=Marty+Hall&amp;origin=bwi&amp;dest=lax”,就是表單數據,這是將Web頁(yè)面數據發(fā)送給服務(wù)器程序的最常用方法。對于GET請求,表單數據附加到URL的問(wèn)號后面(如上例所示);對于POST請求,表單數據用一個(gè)單獨的行發(fā)送給服務(wù)器。 </P>
<>   以前,從這種形式的數據提取出所需要的表單變量是CGI編程中最麻煩的事情之一。首先,GET請求和POST請求的數據提取方法不同:對于GET請求,通常要通過(guò)QUERY_STRING環(huán)境變量提取數據;對于POST請求,則一般通過(guò)標準輸入提取數據。第二,程序員必須負責在“&amp;”符號處截斷變量名字-變量值對,再分離出變量名字(等號左邊)和變量值(等號右邊)。第三,必須對變量值進(jìn)行URL反編碼操作。因為發(fā)送數據的時(shí)候,字母和數字以原來(lái)的形式發(fā)送,但空格被轉換成加號,其他字符被轉換成“%XX”形式,其中XX是十六進(jìn)制表示的字符ASCII(或者ISO Latin-1)編碼值。例如,如果HTML表單中名為“users”的域值為“~hall, ~gates, and ~mcnealy”,則實(shí)際向服務(wù)器發(fā)送的數據為“users=%7Ehall%2C+%7Egates%2C+and+%7Emcnealy”。最后,即第四個(gè)導致解析表單數據非常困難的原因在于,變量值既可能被省略(如“param1=val1&param2=&param3=val3”),也有可能一個(gè)變量擁有一個(gè)以上的值,即同一個(gè)變量可能出現一次以上(如“param1=val1&param2=val2&param1=val3”)。 </P>
<P>   Java Servlet的好處之一就在于所有上述解析操作都能夠自動(dòng)完成。只需要簡(jiǎn)單地調用一下HttpServletRequest的getParameter方法、在調用參數中提供表單變量的名字(大小寫(xiě)敏感)即可,而且GET請求和POST請求的處理方法完全相同。 </P>
<P>   getParameter方法的返回值是一個(gè)字符串,它是參數中指定的變量名字第一次出現所對應的值經(jīng)反編碼得到得字符串(可以直接使用)。如果指定的表單變量存在,但沒(méi)有值,getParameter返回空字符串;如果指定的表單變量不存在,則返回null。如果表單變量可能對應多個(gè)值,可以用getParameterValues來(lái)取代getParameter。getParameterValues能夠返回一個(gè)字符串數組。 </P>
<P>   最后,雖然在實(shí)際應用中Servlet很可能只會(huì )用到那些已知名字的表單變量,但在調試環(huán)境中,獲得完整的表單變量名字列表往往是很有用的,利用getParamerterNames方法可以方便地實(shí)現這一點(diǎn)。getParamerterNames返回的是一個(gè)Enumeration,其中的每一項都可以轉換為調用getParameter的字符串。 </P>
<P>   4.2 實(shí)例:讀取三個(gè)表單變量 </P>
<P>   下面是一個(gè)簡(jiǎn)單的例子,它讀取三個(gè)表單變量param1、param2和param3,并以HTML列表的形式列出它們的值。請注意,雖然在發(fā)送應答內容之前必須指定應答類(lèi)型(包括內容類(lèi)型、狀態(tài)以及其他HTTP頭信息),但Servlet對何時(shí)讀取請求內容卻沒(méi)有什么要求。 </P>
<P>   另外,我們也可以很容易地把Servlet做成既能處理GET請求,也能夠處理POST請求,這只需要在doPost方法中調用doGet方法,或者覆蓋service方法(service方法調用doGet、doPost、doHead等方法)。在實(shí)際編程中這是一種標準的方法,因為它只需要很少的額外工作,卻能夠增加客戶(hù)端編碼的靈活性。 </P>
<P>   如果你習慣用傳統的CGI方法,通過(guò)標準輸入讀取POST數據,那么在Servlet中也有類(lèi)似的方法,即在HttpServletRequest上調用getReader或者getInputStream,但這種方法對普通的表單變量來(lái)說(shuō)太麻煩。然而,如果是要上載文件,或者POST數據是通過(guò)專(zhuān)門(mén)的客戶(hù)程序而不是HTML表單發(fā)送,那么就要用到這種方法。 </P>
<P>   注意用第二種方法讀取POST數據時(shí),不能再用getParameter來(lái)讀取這些數據。 </P>
<P>   ThreeParams.java <BR>package hall;</P>
<P>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;<BR>import java.util.*;</P>
<P>public class ThreeParams extends HttpServlet {<BR>  public void doGet(HttpServletRequest request,<BR>               HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    response.setContentType("text/html");<BR>    PrintWriter out = response.getWriter();<BR>    String title = "讀取三個(gè)請求參數";<BR>    out.println(ServletUtilities.headWithTitle(title) +<BR>                "<BODY>\n" +<BR>                "<H1 ALIGN=CENTER>" + title + "</H1>\n" +<BR>                "<UL>\n" +<BR>                "  <LI>param1: "<BR>                + request.getParameter("param1") + "\n" +<BR>                "  <LI>param2: "<BR>                + request.getParameter("param2") + "\n" +<BR>                "  <LI>param3: "<BR>                + request.getParameter("param3") + "\n" +<BR>                "</UL>\n" +<BR>                "</BODY></HTML>");<BR>  }</P>
<P>  public void doPost(HttpServletRequest request,<BR>                     HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    doGet(request, response);<BR>  }<BR>}</P>

<P><BR>   4.3 實(shí)例:輸出所有的表單數據 </P>
<P>   下面這個(gè)例子尋找表單所發(fā)送的所有變量名字,并把它們放入表格中,沒(méi)有值或者有多個(gè)值的變量都突出顯示。 </P>
<P>   首先,程序通過(guò)HttpServletRequest的getParameterNames方法得到所有的變量名字,getParameterNames返回的是一個(gè)Enumeration。接下來(lái),程序用循環(huán)遍歷這個(gè)Enumeration,通過(guò)hasMoreElements確定何時(shí)結束循環(huán),利用nextElement得到Enumeration中的各個(gè)項。由于nextElement返回的是一個(gè)Object,程序把它轉換成字符串后再用這個(gè)字符串來(lái)調用getParameterValues。 </P>
<P>   getParameterValues返回一個(gè)字符串數組,如果這個(gè)數組只有一個(gè)元素且等于空字符串,說(shuō)明這個(gè)表單變量沒(méi)有值,Servlet以斜體形式輸出“No Value”;如果數組元素個(gè)數大于1,說(shuō)明這個(gè)表單變量有多個(gè)值,Servlet以HTML列表形式輸出這些值;其他情況下Servlet直接把變量值放入表格。 </P>
<P>   ShowParameters.java </P>
<P>   注意,ShowParameters.java用到了前面介紹過(guò)的ServletUtilities.java。 <BR>package hall;</P>
<P>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;<BR>import java.util.*;</P>
<P>public class ShowParameters extends HttpServlet {<BR>  public void doGet(HttpServletRequest request,<BR>                    HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    response.setContentType("text/html");<BR>    PrintWriter out = response.getWriter();<BR>    String title = "讀取所有請求參數";<BR>    out.println(ServletUtilities.headWithTitle(title) +<BR>                "<BODY BGCOLOR=\"#FDF5E6\">\n" +<BR>                "<H1 ALIGN=CENTER>" + title + "</H1>\n" +<BR>                "<TABLE BORDER=1 ALIGN=CENTER>\n" +<BR>                "<TR BGCOLOR=\"#FFAD00\">\n" +<BR>                "<TH>參數名字<TH>參數值");<BR>    Enumeration paramNames = request.getParameterNames();<BR>    while(paramNames.hasMoreElements()) {<BR>      String paramName = (String)paramNames.nextElement();<BR>      out.println("<TR><TD>" + paramName + "\n<TD>");<BR>      String[] paramValues = request.getParameterValues(paramName);<BR>      if (paramValues.length == 1) {<BR>        String paramValue = paramValues[0];<BR>        if (paramValue.length() == 0)<BR>          out.print("<I>No Value</I>");<BR>        else<BR>          out.print(paramValue);<BR>      } else {<BR>        out.println("<UL>");<BR>        for(int i=0; i<paramValues.length; i++) {<BR>          out.println("<LI>" + paramValues);<BR>        }<BR>        out.println("</UL>");<BR>      }<BR>    }<BR>    out.println("</TABLE>\n</BODY></HTML>");<BR>  }</P>
<P>  public void doPost(HttpServletRequest request,<BR>                     HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    doGet(request, response);<BR>  }<BR>}</P>

<P><BR>   測試表單 </P>
<P>   下面是向上述Servlet發(fā)送數據的表單PostForm.html。就像所有包含密碼輸入域的表單一樣,該表單用POST方法發(fā)送數據。我們可以看到,在Servlet中同時(shí)實(shí)現doGet和doPost這兩種方法為表單制作帶來(lái)了方便。 <BR><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><BR><HTML><BR><HEAD><BR>  <TITLE>示例表單</TITLE><BR></HEAD></P>
<P><BODY BGCOLOR="#FDF5E6"><BR><H1 ALIGN="CENTER">用POST方法發(fā)送數據的表單</H1></P>
<P><FORM ACTION="/servlet/hall.ShowParameters"<BR>      METHOD="POST"><BR>  Item Number:<BR>  <INPUT TYPE="TEXT" NAME="itemNum"><BR><BR>  Quantity:<BR>  <INPUT TYPE="TEXT" NAME="quantity"><BR><BR>  Price Each:<BR>  <INPUT TYPE="TEXT" NAME="price" VALUE="$"><BR><BR>  <HR><BR>  First Name:<BR>  <INPUT TYPE="TEXT" NAME="firstName"><BR><BR>  Last Name:<BR>  <INPUT TYPE="TEXT" NAME="lastName"><BR><BR>  Middle Initial:<BR>  <INPUT TYPE="TEXT" NAME="initial"><BR><BR>  Shipping Address:<BR>  <TEXTAREA NAME="address" ROWS=3 COLS=40></TEXTAREA><BR><BR>  Credit Card:<BR><BR>    <INPUT TYPE="RADIO" NAME="cardType"<BR>                     VALUE="Visa">Visa<BR><BR>    <INPUT TYPE="RADIO" NAME="cardType"<BR>                     VALUE="Master Card">Master Card<BR><BR>    <INPUT TYPE="RADIO" NAME="cardType"<BR>                     VALUE="Amex">American Express<BR><BR>    <INPUT TYPE="RADIO" NAME="cardType"<BR>                     VALUE="Discover">Discover<BR><BR>    <INPUT TYPE="RADIO" NAME="cardType"<BR>                     VALUE="Java SmartCard">Java SmartCard<BR><BR>  Credit Card Number:<BR>  <INPUT TYPE="PASSWORD" NAME="cardNum"><BR><BR>  Repeat Credit Card Number:<BR>  <INPUT TYPE="PASSWORD" NAME="cardNum"><BR><BR><BR>  <CENTER><BR>    <INPUT TYPE="SUBMIT" VALUE="Submit Order"><BR>  </CENTER><BR></FORM></P>
<P></BODY><BR></HTML>  <BR></P>
作者: firstcosmos    時(shí)間: 2005-12-15 18:38
<>五、讀取HTTP請求頭 <BR> <BR> <BR>5.1 HTTP請求頭概述 </P>
<>   HTTP客戶(hù)程序(例如瀏覽器),向服務(wù)器發(fā)送請求的時(shí)候必須指明請求類(lèi)型(一般是GET或者POST)。如有必要,客戶(hù)程序還可以選擇發(fā)送其他的請求頭。大多數請求頭并不是必需的,但Content-Length除外。對于POST請求來(lái)說(shuō)Content-Length必須出現。 </P>
<>   下面是一些最常見(jiàn)的請求頭: </P>
<P>Accept:瀏覽器可接受的MIME類(lèi)型。 <BR>Accept-Charset:瀏覽器可接受的字符集。 <BR>Accept-Encoding:瀏覽器能夠進(jìn)行解碼的數據編碼方式,比如gzip。Servlet能夠向支持gzip的瀏覽器返回經(jīng)gzip編碼的HTML頁(yè)面。許多情形下這可以減少5到10倍的下載時(shí)間。 <BR>Accept-Language:瀏覽器所希望的語(yǔ)言種類(lèi),當服務(wù)器能夠提供一種以上的語(yǔ)言版本時(shí)要用到。 <BR>Authorization:授權信息,通常出現在對服務(wù)器發(fā)送的WWW-Authenticate頭的應答中。 <BR>Connection:表示是否需要持久連接。如果Servlet看到這里的值為“Keep-Alive”,或者看到請求使用的是HTTP 1.1(HTTP 1.1默認進(jìn)行持久連接),它就可以利用持久連接的優(yōu)點(diǎn),當頁(yè)面包含多個(gè)元素時(shí)(例如Applet,圖片),顯著(zhù)地減少下載所需要的時(shí)間。要實(shí)現這一點(diǎn),Servlet需要在應答中發(fā)送一個(gè)Content-Length頭,最簡(jiǎn)單的實(shí)現方法是:先把內容寫(xiě)入ByteArrayOutputStream,然后在正式寫(xiě)出內容之前計算它的大小。 <BR>Content-Length:表示請求消息正文的長(cháng)度。 <BR>Cookie:這是最重要的請求頭信息之一,參見(jiàn)后面《Cookie處理》一章中的討論。 <BR>From:請求發(fā)送者的email地址,由一些特殊的Web客戶(hù)程序使用,瀏覽器不會(huì )用到它。 <BR>Host:初始URL中的主機和端口。 <BR>If-Modified-Since:只有當所請求的內容在指定的日期之后又經(jīng)過(guò)修改才返回它,否則返回304“Not Modified”應答。 <BR>Pragma:指定“no-cache”值表示服務(wù)器必須返回一個(gè)刷新后的文檔,即使它是代理服務(wù)器而且已經(jīng)有了頁(yè)面的本地拷貝。 <BR>Referer:包含一個(gè)URL,用戶(hù)從該URL代表的頁(yè)面出發(fā)訪(fǎng)問(wèn)當前請求的頁(yè)面。 <BR>User-Agent:瀏覽器類(lèi)型,如果Servlet返回的內容與瀏覽器類(lèi)型有關(guān)則該值非常有用。 <BR>UA-Pixels,UA-Color,UA-OS,UA-CPU:由某些版本的IE瀏覽器所發(fā)送的非標準的請求頭,表示屏幕大小、顏色深度、操作系統和CPU類(lèi)型。 <BR>   有關(guān)HTTP頭完整、詳細的說(shuō)明,請參見(jiàn)<a href="http://www.w3.org/Protocols/" target="_blank" >http://www.w3.org/Protocols/</A>的HTTP規范。 </P>
<P>   5.2 在Servlet中讀取請求頭 </P>
<P>   在Servlet中讀取HTTP頭是非常方便的,只需要調用一下HttpServletRequest的getHeader方法即可。如果客戶(hù)請求中提供了指定的頭信息,getHeader返回對應的字符串;否則,返回null。部分頭信息經(jīng)常要用到,它們有專(zhuān)用的訪(fǎng)問(wèn)方法:getCookies方法返回Cookie頭的內容,經(jīng)解析后存放在Cookie對象的數組中,請參見(jiàn)后面有關(guān)Cookie章節的討論;getAuthType和getRemoteUser方法分別讀取Authorization頭中的一部分內容;getDateHeader和getIntHeader方法讀取指定的頭,然后返回日期值或整數值。 </P>
<P>   除了讀取指定的頭之外,利用getHeaderNames還可以得到請求中所有頭名字的一個(gè)Enumeration對象。 </P>
<P>   最后,除了查看請求頭信息之外,我們還可以從請求主命令行獲得一些信息。getMethod方法返回請求方法,請求方法通常是GET或者POST,但也有可能是HEAD、PUT或者DELETE。getRequestURI方法返回URI(URI是URL的從主機和端口之后到表單數據之前的那一部分)。getRequestProtocol返回請求命令的第三部分,一般是“HTTP/1.0”或者“HTTP/1.1”。 </P>
<P>   5.3 實(shí)例:輸出所有的請求頭 </P>
<P>   下面的Servlet實(shí)例把所有接收到的請求頭和它的值以表格的形式輸出。另外,該Servlet還會(huì )輸出主請求命令的三個(gè)部分:請求方法,URI,協(xié)議/版本。 </P>
<P>   ShowRequestHeaders.java <BR>package hall;</P>
<P>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;<BR>import java.util.*;</P>
<P>public class ShowRequestHeaders extends HttpServlet {<BR>  public void doGet(HttpServletRequest request,<BR>                    HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    response.setContentType("text/html");<BR>    PrintWriter out = response.getWriter();<BR>    String title = "顯示所有請求頭";<BR>    out.println(ServletUtilities.headWithTitle(title) +<BR>                "<BODY BGCOLOR=\"#FDF5E6\">\n" +<BR>                "<H1 ALIGN=CENTER>" + title + "</H1>\n" +<BR>                "<B>Request Method: </B>" +<BR>                request.getMethod() + "<BR>\n" +<BR>                "<B>Request URI: </B>" +<BR>                request.getRequestURI() + "<BR>\n" +<BR>                "<B>Request Protocol: </B>" +<BR>                request.getProtocol() + "<BR><BR>\n" +<BR>                "<TABLE BORDER=1 ALIGN=CENTER>\n" +<BR>                "<TR BGCOLOR=\"#FFAD00\">\n" +<BR>                "<TH>Header Name<TH>Header Value");<BR>    Enumeration headerNames = request.getHeaderNames();<BR>    while(headerNames.hasMoreElements()) {<BR>      String headerName = (String)headerNames.nextElement();<BR>      out.println("<TR><TD>" + headerName);<BR>      out.println("    <TD>" + request.getHeader(headerName));<BR>    }<BR>    out.println("</TABLE>\n</BODY></HTML>");<BR>  }</P>
<P>  public void doPost(HttpServletRequest request,<BR>                     HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    doGet(request, response);<BR>  }<BR>}  <BR></P>
作者: firstcosmos    時(shí)間: 2005-12-15 18:38
<>六、訪(fǎng)問(wèn)CGI變量  <BR> <BR> <BR>6.1 CGI變量概述 </P>
<>   如果你是從傳統的CGI編程轉而學(xué)習Java Servlet,或許已經(jīng)習慣了“CGI變量”這一概念。CGI變量匯集了各種有關(guān)請求的信息: </P>
<>部分來(lái)自HTTP請求命令和請求頭,例如Content-Length頭; <BR>部分來(lái)自Socket本身,例如主機的名字和IP地址; <BR>也有部分與服務(wù)器安裝配置有關(guān),例如URL到實(shí)際路徑的映射。 <BR>   6.2 標準CGI變量的Servlet等價(jià)表示 </P>
<P>   下表假定request對象是提供給doGet和doPost方法的HttpServletRequest類(lèi)型對象。 CGI變量  含義  從doGet或doPost訪(fǎng)問(wèn)  <BR>AUTH_TYPE  如果提供了Authorization頭,這里指定了具體的模式(basic或者digest)。  request.getAuthType()  <BR>CONTENT_LENGTH  只用于POST請求,表示所發(fā)送數據的字節數。  嚴格地講,等價(jià)的表達方式應該是String.valueOf(request.getContentLength())(返回一個(gè)字符串)。但更常見(jiàn)的是用request.getContentLength()返回含義相同的整數。  <BR>CONTENT_TYPE  如果指定的話(huà),表示后面所跟數據的類(lèi)型。  request.getContentType()  <BR>DOCUMENT_ROOT  與<a href="http://host/" target="_blank" >http://host/</A>對應的路徑。  getServletContext().getRealPath("/") <BR>注意低版本Servlet規范中的等價(jià)表達方式是request.getRealPath("/")。 </P>
<P>HTTP_XXX_YYY  訪(fǎng)問(wèn)任意HTTP頭。  request.getHeader("Xxx-Yyy")  <BR>PATH_INFO  URL中的附加路徑信息,即URL中Servlet路徑之后、查詢(xún)字符串之前的那部分。  request.getPathInfo()  <BR>PATH_TRANSLATED  映射到服務(wù)器實(shí)際路徑之后的路徑信息。  request.getPathTranslated()  <BR>QUERY_STRING  這是字符串形式的附加到URL后面的查詢(xún)字符串,數據仍舊是URL編碼的。在Servlet中很少需要用到未經(jīng)解碼的數據,一般使用getParameter訪(fǎng)問(wèn)各個(gè)參數。  request.getQueryString()  <BR>REMOTE_ADDR  發(fā)出請求的客戶(hù)機的IP地址。  request.getRemoteAddr()  <BR>REMOTE_HOST  發(fā)出請求的客戶(hù)機的完整的域名,如java.sun.com。如果不能確定該域名,則返回IP地址。  request.getRemoteHost()  <BR>REMOTE_USER  如果提供了Authorization頭,則代表其用戶(hù)部分。它代表發(fā)出請求的用戶(hù)的名字。  request.getRemoteUser()  <BR>REQUEST_METHOD  請求類(lèi)型。通常是GET或者POST。但偶爾也會(huì )出現HEAD,PUT, DELETE,OPTIONS,或者 TRACE.  request.getMethod()  <BR>SCRIPT_NAME  URL中調用Servlet的那一部分,不包含附加路徑信息和查詢(xún)字符串。  request.getServletPath()  <BR>SERVER_NAME  Web服務(wù)器名字。  request.getServerName()  <BR>SERVER_PORT  服務(wù)器監聽(tīng)的端口。  嚴格地說(shuō),等價(jià)表達應該是返回字符串的String.valueOf(request.getServerPort())。但經(jīng)常使用返回整數值的request.getServerPort()。  <BR>SERVER_PROTOCOL  請求命令中的協(xié)議名字和版本(即HTTP/1.0或HTTP/1.1)。  request.getProtocol()  <BR>SERVER_SOFTWARE  Servlet引擎的名字和版本。  getServletContext().getServerInfo()  </P>
<P><BR>   6.3 實(shí)例:讀取CGI變量 </P>
<P>   下面這個(gè)Servlet創(chuàng )建一個(gè)表格,顯示除了HTTP_XXX_YYY之外的所有CGI變量。HTTP_XXX_YYY是HTTP請求頭信息,請參見(jiàn)上一節介紹。 </P>
<P>   ShowCGIVariables.java <BR>package hall;</P>
<P>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;<BR>import java.util.*;</P>
<P>public class ShowCGIVariables extends HttpServlet {<BR>  public void doGet(HttpServletRequest request,<BR>                    HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    response.setContentType("text/html");<BR>    PrintWriter out = response.getWriter();<BR>    String[][] variables =<BR>      { { "AUTH_TYPE", request.getAuthType() },<BR>        { "CONTENT_LENGTH", String.valueOf(request.getContentLength()) },<BR>        { "CONTENT_TYPE", request.getContentType() },<BR>        { "DOCUMENT_ROOT", getServletContext().getRealPath("/") },<BR>        { "PATH_INFO", request.getPathInfo() },<BR>        { "PATH_TRANSLATED", request.getPathTranslated() },<BR>        { "QUERY_STRING", request.getQueryString() },<BR>        { "REMOTE_ADDR", request.getRemoteAddr() },<BR>        { "REMOTE_HOST", request.getRemoteHost() },<BR>        { "REMOTE_USER", request.getRemoteUser() },<BR>        { "REQUEST_METHOD", request.getMethod() },<BR>        { "SCRIPT_NAME", request.getServletPath() },<BR>        { "SERVER_NAME", request.getServerName() },<BR>        { "SERVER_PORT", String.valueOf(request.getServerPort()) },<BR>        { "SERVER_PROTOCOL", request.getProtocol() },<BR>        { "SERVER_SOFTWARE", getServletContext().getServerInfo() }<BR>      };<BR>    String title = "顯示CGI變量";<BR>    out.println(ServletUtilities.headWithTitle(title) +<BR>                "<BODY BGCOLOR=\"#FDF5E6\">\n" +<BR>                "<H1 ALIGN=CENTER>" + title + "</H1>\n" +<BR>                "<TABLE BORDER=1 ALIGN=CENTER>\n" +<BR>                "<TR BGCOLOR=\"#FFAD00\">\n" +<BR>                "<TH>CGI Variable Name<TH>Value");<BR>    for(int i=0; i<variables.length; i++) {<BR>      String varName = variables[0];<BR>      String varValue = variables[1];<BR>      if (varValue == null)<BR>        varValue = "<I>Not specified</I>";<BR>      out.println("<TR><TD>" + varName + "<TD>" + varValue);<BR>    }<BR>    out.println("</TABLE></BODY></HTML>");<BR>  }</P>
<P>  public void doPost(HttpServletRequest request,<BR>                     HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    doGet(request, response);<BR>  }<BR>}  <BR></P>
作者: firstcosmos    時(shí)間: 2005-12-15 18:39
<>七、HTTP應答狀態(tài) <BR> <BR> <BR>7.1 狀態(tài)代碼概述 </P>
<>   Web服務(wù)器響應瀏覽器或其他客戶(hù)程序的請求時(shí),其應答一般由以下幾個(gè)部分組成:一個(gè)狀態(tài)行,幾個(gè)應答頭,一個(gè)空行,內容文檔。下面是一個(gè)最簡(jiǎn)單的應答: <BR>HTTP/1.1 200 OK<BR>Content-Type: text/plain</P>
<>Hello World</P>
<P><BR>   狀態(tài)行包含HTTP版本、狀態(tài)代碼、與狀態(tài)代碼對應的簡(jiǎn)短說(shuō)明信息。在大多數情況下,除了Content-Type之外的所有應答頭都是可選的。但Content-Type是必需的,它描述的是后面文檔的MIME類(lèi)型。雖然大多數應答都包含一個(gè)文檔,但也有一些不包含,例如對HEAD請求的應答永遠不會(huì )附帶文檔。有許多狀態(tài)代碼實(shí)際上用來(lái)標識一次失敗的請求,這些應答也不包含文檔(或只包含一個(gè)簡(jiǎn)短的錯誤信息說(shuō)明)。 </P>
<P>   Servlet可以利用狀態(tài)代碼來(lái)實(shí)現許多功能。例如,可以把用戶(hù)重定向到另一個(gè)網(wǎng)站;可以指示出后面的文檔是圖片、PDF文件或HTML文件;可以告訴用戶(hù)必須提供密碼才能訪(fǎng)問(wèn)文檔;等等。這一部分我們將具體討論各種狀態(tài)代碼的含義以及利用這些代碼可以做些什么。 </P>
<P>   7.2 設置狀態(tài)代碼 </P>
<P>   如前所述,HTTP應答狀態(tài)行包含HTTP版本、狀態(tài)代碼和對應的狀態(tài)信息。由于狀態(tài)信息直接和狀態(tài)代碼相關(guān),而HTTP版本又由服務(wù)器確定,因此需要Servlet設置的只有一個(gè)狀態(tài)代碼。 </P>
<P>   Servlet設置狀態(tài)代碼一般使用HttpServletResponse的setStatus方法。setStatus方法的參數是一個(gè)整數(即狀態(tài)代碼),不過(guò)為了使得代碼具有更好的可讀性,可以用HttpServletResponse中定義的常量來(lái)避免直接使用整數。這些常量根據HTTP 1.1中的標準狀態(tài)信息命名,所有的名字都加上了SC前綴(Status Code的縮寫(xiě))并大寫(xiě),同時(shí)把空格轉換成了下劃線(xiàn)。也就是說(shuō),與狀態(tài)代碼404對應的狀態(tài)信息是“Not Found”,則HttpServletResponse中的對應常量名字為SC_NOT_FOUND。但有兩個(gè)例外:和狀態(tài)代碼302對應的常量根據HTTP 1.0命名,而307沒(méi)有對應的常量。 </P>
<P>   設置狀態(tài)代碼并非總是意味著(zhù)不要再返回文檔。例如,雖然大多數服務(wù)器返回404應答時(shí)會(huì )輸出簡(jiǎn)單的“File Not Found”信息,但Servlet也可以定制這個(gè)應答。不過(guò),定制應答時(shí)應當在通過(guò)PrintWriter發(fā)送任何內容之前先調用response.setStatus。 </P>
<P>   雖然設置狀態(tài)代碼一般使用的是response.setStauts(int)方法,但為了簡(jiǎn)單起見(jiàn),HttpServletResponse為兩種常見(jiàn)的情形提供了專(zhuān)用方法:sendError方法生成一個(gè)404應答,同時(shí)生成一個(gè)簡(jiǎn)短的HTML錯誤信息文檔;sendRedirect方法生成一個(gè)302應答,同時(shí)在Location頭中指示新文檔的URL。 </P>
<P>   7.3 HTTP 1.1狀態(tài)代碼及其含義 </P>
<P>   下表顯示了常見(jiàn)的HTTP 1.1狀態(tài)代碼以及它們對應的狀態(tài)信息和含義。 </P>
<P>   應當謹慎地使用那些只有HTTP 1.1支持的狀態(tài)代碼,因為許多瀏覽器還只能夠支持HTTP 1.0。如果你使用了HTTP 1.1特有的狀態(tài)代碼,最好能夠檢查一下請求的HTTP版本號(通過(guò)HttpServletRequest的getProtocol方法)。 狀態(tài)代碼  狀態(tài)信息  含義  <BR>100  Continue  初始的請求已經(jīng)接受,客戶(hù)應當繼續發(fā)送請求的其余部分。(HTTP 1.1新)  <BR>101  Switching Protocols  服務(wù)器將遵從客戶(hù)的請求轉換到另外一種協(xié)議(HTTP 1.1新)  <BR>200  OK  一切正常,對GET和POST請求的應答文檔跟在后面。如果不用setStatus設置狀態(tài)代碼,Servlet默認使用202狀態(tài)代碼。  <BR>201  Created  服務(wù)器已經(jīng)創(chuàng )建了文檔,Location頭給出了它的URL。  <BR>202  Accepted  已經(jīng)接受請求,但處理尚未完成。  <BR>203  Non-Authoritative Information  文檔已經(jīng)正常地返回,但一些應答頭可能不正確,因為使用的是文檔的拷貝(HTTP 1.1新)。  <BR>204  No Content  沒(méi)有新文檔,瀏覽器應該繼續顯示原來(lái)的文檔。如果用戶(hù)定期地刷新頁(yè)面,而Servlet可以確定用戶(hù)文檔足夠新,這個(gè)狀態(tài)代碼是很有用的。  <BR>205  Reset Content  沒(méi)有新的內容,但瀏覽器應該重置它所顯示的內容。用來(lái)強制瀏覽器清除表單輸入內容(HTTP 1.1新)。  <BR>206  Partial Content  客戶(hù)發(fā)送了一個(gè)帶有Range頭的GET請求,服務(wù)器完成了它(HTTP 1.1新)。  <BR>300  Multiple Choices  客戶(hù)請求的文檔可以在多個(gè)位置找到,這些位置已經(jīng)在返回的文檔內列出。如果服務(wù)器要提出優(yōu)先選擇,則應該在Location應答頭指明。  <BR>301  Moved Permanently  客戶(hù)請求的文檔在其他地方,新的URL在Location頭中給出,瀏覽器應該自動(dòng)地訪(fǎng)問(wèn)新的URL。  <BR>302  Found  類(lèi)似于301,但新的URL應該被視為臨時(shí)性的替代,而不是永久性的。注意,在HTTP1.0中對應的狀態(tài)信息是“Moved Temporatily”,而HttpServletResponse中相應的常量是SC_MOVED_TEMPORARILY,而不是SC_FOUND。 <BR>出現該狀態(tài)代碼時(shí),瀏覽器能夠自動(dòng)訪(fǎng)問(wèn)新的URL,因此它是一個(gè)很有用的狀態(tài)代碼。為此,Servlet提供了一個(gè)專(zhuān)用的方法,即sendRedirect。使用response.sendRedirect(url)比使用response.setStatus(response.SC_MOVED_TEMPORARILY)和response.setHeader("Location",url)更好。這是因為: </P>
<P>首先,代碼更加簡(jiǎn)潔。 <BR>第二,使用sendRedirect,Servlet會(huì )自動(dòng)構造一個(gè)包含新鏈接的頁(yè)面(用于那些不能自動(dòng)重定向的老式瀏覽器)。 <BR>最后,sendRedirect能夠處理相對URL,自動(dòng)把它們轉換成絕對URL。 <BR>注意這個(gè)狀態(tài)代碼有時(shí)候可以和301替換使用。例如,如果瀏覽器錯誤地請求<a href="http://host/~user" target="_blank" >http://host/~user</A>(缺少了后面的斜杠),有的服務(wù)器返回301,有的則返回302。 </P>
<P>嚴格地說(shuō),我們只能假定只有當原來(lái)的請求是GET時(shí)瀏覽器才會(huì )自動(dòng)重定向。請參見(jiàn)307。 </P>
<P>303  See Other  類(lèi)似于301/302,不同之處在于,如果原來(lái)的請求是POST,Location頭指定的重定向目標文檔應該通過(guò)GET提。℉TTP 1.1新)。  <BR>304  Not Modified  客戶(hù)端有緩沖的文檔并發(fā)出了一個(gè)條件性的請求(一般是提供If-Modified-Since頭表示客戶(hù)只想比指定日期更新的文檔)。服務(wù)器告訴客戶(hù),原來(lái)緩沖的文檔還可以繼續使用。  <BR>305  Use Proxy  客戶(hù)請求的文檔應該通過(guò)Location頭所指明的代理服務(wù)器提。℉TTP 1.1新)。  <BR>307  Temporary Redirect  和302(Found)相同。許多瀏覽器會(huì )錯誤地響應302應答進(jìn)行重定向,即使原來(lái)的請求是POST,即使它實(shí)際上只能在POST請求的應答是303時(shí)才能重定向。由于這個(gè)原因,HTTP 1.1新增了307,以便更加清除地區分幾個(gè)狀態(tài)代碼:當出現303應答時(shí),瀏覽器可以跟隨重定向的GET和POST請求;如果是307應答,則瀏覽器只能跟隨對GET請求的重定向。 <BR>注意,HttpServletResponse中沒(méi)有為該狀態(tài)代碼提供相應的常量。(HTTP 1.1新) </P>
<P>400  Bad Request  請求出現語(yǔ)法錯誤。  <BR>401  Unauthorized  客戶(hù)試圖未經(jīng)授權訪(fǎng)問(wèn)受密碼保護的頁(yè)面。應答中會(huì )包含一個(gè)WWW-Authenticate頭,瀏覽器據此顯示用戶(hù)名字/密碼對話(huà)框,然后在填寫(xiě)合適的Authorization頭后再次發(fā)出請求。  <BR>403  Forbidden  資源不可用。服務(wù)器理解客戶(hù)的請求,但拒絕處理它。通常由于服務(wù)器上文件或目錄的權限設置導致。  <BR>404  Not Found  無(wú)法找到指定位置的資源。這也是一個(gè)常用的應答,HttpServletResponse專(zhuān)門(mén)提供了相應的方法:sendError(message)。  <BR>405  Method Not Allowed  請求方法(GET、POST、HEAD、DELETE、PUT、TRACE等)對指定的資源不適用。(HTTP 1.1新)  <BR>406  Not Acceptable  指定的資源已經(jīng)找到,但它的MIME類(lèi)型和客戶(hù)在A(yíng)ccpet頭中所指定的不兼容(HTTP 1.1新)。  <BR>407  Proxy Authentication Required  類(lèi)似于401,表示客戶(hù)必須先經(jīng)過(guò)代理服務(wù)器的授權。(HTTP 1.1新)  <BR>408  Request Timeout  在服務(wù)器許可的等待時(shí)間內,客戶(hù)一直沒(méi)有發(fā)出任何請求?蛻(hù)可以在以后重復同一請求。(HTTP 1.1新)  <BR>409  Conflict  通常和PUT請求有關(guān)。由于請求和資源的當前狀態(tài)相沖突,因此請求不能成功。(HTTP 1.1新)  <BR>410  Gone  所請求的文檔已經(jīng)不再可用,而且服務(wù)器不知道應該重定向到哪一個(gè)地址。它和404的不同在于,返回407表示文檔永久地離開(kāi)了指定的位置,而404表示由于未知的原因文檔不可用。(HTTP 1.1新)  <BR>411  Length Required  服務(wù)器不能處理請求,除非客戶(hù)發(fā)送一個(gè)Content-Length頭。(HTTP 1.1新)  <BR>412  Precondition Failed  請求頭中指定的一些前提條件失。℉TTP 1.1新)。  <BR>413  Request Entity Too Large  目標文檔的大小超過(guò)服務(wù)器當前愿意處理的大小。如果服務(wù)器認為自己能夠稍后再處理該請求,則應該提供一個(gè)Retry-After頭(HTTP 1.1新)。  <BR>414  Request URI Too Long  URI太長(cháng)(HTTP 1.1新)。  <BR>416  Requested Range Not Satisfiable  服務(wù)器不能滿(mǎn)足客戶(hù)在請求中指定的Range頭。(HTTP 1.1新)  <BR>500  Internal Server Error  服務(wù)器遇到了意料不到的情況,不能完成客戶(hù)的請求。  <BR>501  Not Implemented  服務(wù)器不支持實(shí)現請求所需要的功能。例如,客戶(hù)發(fā)出了一個(gè)服務(wù)器不支持的PUT請求。  <BR>502  Bad Gateway  服務(wù)器作為網(wǎng)關(guān)或者代理時(shí),為了完成請求訪(fǎng)問(wèn)下一個(gè)服務(wù)器,但該服務(wù)器返回了非法的應答。  <BR>503  Service Unavailable  服務(wù)器由于維護或者負載過(guò)重未能應答。例如,Servlet可能在數據庫連接池已滿(mǎn)的情況下返回503。服務(wù)器返回503時(shí)可以提供一個(gè)Retry-After頭。  <BR>504  Gateway Timeout  由作為代理或網(wǎng)關(guān)的服務(wù)器使用,表示不能及時(shí)地從遠程服務(wù)器獲得應答。(HTTP 1.1新)  <BR>505  HTTP Version Not Supported  服務(wù)器不支持請求中所指明的HTTP版本。(HTTP 1.1新)  </P>
<P><BR>   7.4 實(shí)例:訪(fǎng)問(wèn)多個(gè)搜索引擎 </P>
<P>   下面這個(gè)例子用到了除200之外的另外兩個(gè)常見(jiàn)狀態(tài)代碼:302和404。302通過(guò)sendRedirect方法設置,404通過(guò)sendError方法設置。 </P>
<P>   在這個(gè)例子中,首先出現的HTML表單用來(lái)選擇搜索引擎、搜索字符串、每頁(yè)顯示的搜索結果數量。表單提交后,Servlet提取這三個(gè)變量,按照所選擇的搜索引擎的要求構造出包含這些變量的URL,然后把用戶(hù)重定向到這個(gè)URL。如果用戶(hù)不能正確地選擇搜索引擎,或者利用其他表單發(fā)送了一個(gè)不認識的搜索引擎名字,則返回一個(gè)提示搜索引擎找不到的404頁(yè)面。 </P>
<P>   SearchEngines.java </P>
<P>   注意:這個(gè)Servlet要用到后面給出的SearchSpec類(lèi),SearchSpec的功能是構造適合不同搜索引擎的URL。 <BR>package hall;</P>
<P>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;<BR>import java.net.*;</P>
<P>public class SearchEngines extends HttpServlet {<BR>  public void doGet(HttpServletRequest request,<BR>                    HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    // getParameter自動(dòng)解碼URL編碼的查詢(xún)字符串。由于我們<BR>    // 要把查詢(xún)字符串發(fā)送給另一個(gè)服務(wù)器,因此再次使用<BR>    // URLEncoder進(jìn)行URL編碼<BR>    String searchString =<BR>      URLEncoder.encode(request.getParameter("searchString"));<BR>    String numResults =<BR>      request.getParameter("numResults");<BR>    String searchEngine =<BR>      request.getParameter("searchEngine");<BR>    SearchSpec[] commonSpecs = SearchSpec.getCommonSpecs();<BR>    for(int i=0; i<commonSpecs.length; i++) {<BR>      SearchSpec searchSpec = commonSpecs;<BR>      if (searchSpec.getName().equals(searchEngine)) {<BR>        String url =<BR>          response.encodeURL(searchSpec.makeURL(searchString,<BR>                            numResults));<BR>        response.sendRedirect(url);<BR>        return;<BR>      }<BR>    }<BR>    response.sendError(response.SC_NOT_FOUND,<BR>                       "No recognized search engine specified.");<BR>  }</P>
<P>  public void doPost(HttpServletRequest request,<BR>                     HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    doGet(request, response);<BR>  }<BR>}</P>

<P><BR>   SearchSpec.java <BR>package hall;</P>
<P>class SearchSpec {<BR>  private String name, baseURL, numResultsSuffix;</P>
<P>  private static SearchSpec[] commonSpecs =<BR>    { new SearchSpec("google",<BR>                     "<a href="http://www.google.com/search?q" target="_blank" >http://www.google.com/search?q</A>=",<BR>                     "&amp;num="),<BR>      new SearchSpec("infoseek",<BR>                     "<a href="http://infoseek.go.com/Titles?qt" target="_blank" >http://infoseek.go.com/Titles?qt</A>=",<BR>                     "&amp;nh="),<BR>      new SearchSpec("lycos",<BR>                     "<a href="http://lycospro.lycos.com/cgi-bin/pursuit?query" target="_blank" >http://lycospro.lycos.com/cgi-bin/pursuit?query</A>=",<BR>                     "&amp;maxhits="),<BR>      new SearchSpec("hotbot",<BR>                     "<a href="http://www.hotbot.com/?MT" target="_blank" >http://www.hotbot.com/?MT</A>=",<BR>                     "&amp;DC=")<BR>    };</P>
<P>  public SearchSpec(String name,<BR>                    String baseURL,<BR>                    String numResultsSuffix) {<BR>    this.name = name;<BR>    this.baseURL = baseURL;<BR>    this.numResultsSuffix = numResultsSuffix;<BR>  }</P>
<P>  public String makeURL(String searchString, String numResults) {<BR>    return(baseURL + searchString + numResultsSuffix + numResults);<BR>  }</P>
<P>  public String getName() {<BR>    return(name);<BR>  }</P>
<P>  public static SearchSpec[] getCommonSpecs() {<BR>    return(commonSpecs);<BR>  }<BR>}</P>

<P><BR>   SearchEngines.html </P>
<P>   下面是調用上述Servlet的HTML表單。 <BR><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><BR><HTML><BR><HEAD><BR>  <TITLE>訪(fǎng)問(wèn)多個(gè)搜索引擎</TITLE><BR></HEAD></P>
<P><BODY BGCOLOR="#FDF5E6"></P>
<P><FORM ACTION="/servlet/hall.SearchEngines"><BR>  <CENTER><BR>    搜索關(guān)鍵字: <BR>    <INPUT TYPE="TEXT" NAME="searchString"><BR><BR>    每頁(yè)顯示幾個(gè)查詢(xún)結果:<BR>    <INPUT TYPE="TEXT" NAME="numResults" <BR>                       VALUE=10 SIZE=3><BR><BR>    <INPUT TYPE="RADIO" NAME="searchEngine"<BR>                        VALUE="google"><BR>    Google |<BR>    <INPUT TYPE="RADIO" NAME="searchEngine"<BR>                        VALUE="infoseek"><BR>    Infoseek |<BR>    <INPUT TYPE="RADIO" NAME="searchEngine"<BR>                        VALUE="lycos"><BR>    Lycos |<BR>    <INPUT TYPE="RADIO" NAME="searchEngine"<BR>                        VALUE="hotbot"><BR>    HotBot<BR>    <BR><BR>    <INPUT TYPE="SUBMIT" VALUE="Search"><BR>  </CENTER><BR></FORM></P>
<P></BODY><BR></HTML>  <BR></P>
作者: firstcosmos    時(shí)間: 2005-12-15 18:39
<>八、設置HTTP應答頭 <BR> <BR> <BR>8.1 HTTP應答頭概述 </P>
<>   Web服務(wù)器的HTTP應答一般由以下幾項構成:一個(gè)狀態(tài)行,一個(gè)或多個(gè)應答頭,一個(gè)空行,內容文檔。設置HTTP應答頭往往和設置狀態(tài)行中的狀態(tài)代碼結合起來(lái)。例如,有好幾個(gè)表示“文檔位置已經(jīng)改變”的狀態(tài)代碼都伴隨著(zhù)一個(gè)Location頭,而401(Unauthorized)狀態(tài)代碼則必須伴隨一個(gè)WWW-Authenticate頭。 </P>
<>   然而,即使在沒(méi)有設置特殊含義的狀態(tài)代碼時(shí),指定應答頭也是很有用的。應答頭可以用來(lái)完成:設置Cookie,指定修改日期,指示瀏覽器按照指定的間隔刷新頁(yè)面,聲明文檔的長(cháng)度以便利用持久HTTP連接,……等等許多其他任務(wù)。 </P>
<P>   設置應答頭最常用的方法是HttpServletResponse的setHeader,該方法有兩個(gè)參數,分別表示應答頭的名字和值。和設置狀態(tài)代碼相似,設置應答頭應該在發(fā)送任何文檔內容之前進(jìn)行。 </P>
<P>   setDateHeader方法和setIntHeadr方法專(zhuān)門(mén)用來(lái)設置包含日期和整數值的應答頭,前者避免了把Java時(shí)間轉換為GMT時(shí)間字符串的麻煩,后者則避免了把整數轉換為字符串的麻煩。 </P>
<P>   HttpServletResponse還提供了許多設置常見(jiàn)應答頭的簡(jiǎn)便方法,如下所示: </P>
<P>setContentType:設置Content-Type頭。大多數Servlet都要用到這個(gè)方法。 <BR>setContentLength:設置Content-Length頭。對于支持持久HTTP連接的瀏覽器來(lái)說(shuō),這個(gè)函數是很有用的。 <BR>addCookie:設置一個(gè)Cookie(Servlet API中沒(méi)有setCookie方法,因為應答往往包含多個(gè)Set-Cookie頭)。 <BR>另外,如上節介紹,sendRedirect方法設置狀態(tài)代碼302時(shí)也會(huì )設置Location頭。 <BR>   8.2 常見(jiàn)應答頭及其含義 </P>
<P>   有關(guān)HTTP頭詳細和完整的說(shuō)明,請參見(jiàn)<a href="http://www.w3.org/Protocols/" target="_blank" >http://www.w3.org/Protocols/</A>規范。 </P>
<P>應答頭  說(shuō)明  <BR>Allow  服務(wù)器支持哪些請求方法(如GET、POST等)。  <BR>Content-Encoding  文檔的編碼(Encode)方法。只有在解碼之后才可以得到Content-Type頭指定的內容類(lèi)型。利用gzip壓縮文檔能夠顯著(zhù)地減少HTML文檔的下載時(shí)間。Java的GZIPOutputStream可以很方便地進(jìn)行g(shù)zip壓縮,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet應該通過(guò)查看Accept-Encoding頭(即request.getHeader("Accept-Encoding"))檢查瀏覽器是否支持gzip,為支持gzip的瀏覽器返回經(jīng)gzip壓縮的HTML頁(yè)面,為其他瀏覽器返回普通頁(yè)面。  <BR>Content-Length  表示內容長(cháng)度。只有當瀏覽器使用持久HTTP連接時(shí)才需要這個(gè)數據。如果你想要利用持久連接的優(yōu)勢,可以把輸出文檔寫(xiě)入ByteArrayOutputStram,完成后查看其大小,然后把該值放入Content-Length頭,最后通過(guò)byteArrayStream.writeTo(response.getOutputStream()發(fā)送內容。  <BR>Content-Type  表示后面的文檔屬于什么MIME類(lèi)型。Servlet默認為text/plain,但通常需要顯式地指定為text/html。由于經(jīng)常要設置Content-Type,因此HttpServletResponse提供了一個(gè)專(zhuān)用的方法setContentTyep。  <BR>Date  當前的GMT時(shí)間。你可以用setDateHeader來(lái)設置這個(gè)頭以避免轉換時(shí)間格式的麻煩。  <BR>Expires  應該在什么時(shí)候認為文檔已經(jīng)過(guò)期,從而不再緩存它?  <BR>Last-Modified  文檔的最后改動(dòng)時(shí)間?蛻(hù)可以通過(guò)If-Modified-Since請求頭提供一個(gè)日期,該請求將被視為一個(gè)條件GET,只有改動(dòng)時(shí)間遲于指定時(shí)間的文檔才會(huì )返回,否則返回一個(gè)304(Not Modified)狀態(tài)。Last-Modified也可用setDateHeader方法來(lái)設置。  <BR>Location  表示客戶(hù)應當到哪里去提取文檔。Location通常不是直接設置的,而是通過(guò)HttpServletResponse的sendRedirect方法,該方法同時(shí)設置狀態(tài)代碼為302。  <BR>Refresh  表示瀏覽器應該在多少時(shí)間之后刷新文檔,以秒計。除了刷新當前文檔之外,你還可以通過(guò)setHeader("Refresh", "5; URL=http://host/path")讓瀏覽器讀取指定的頁(yè)面。 <BR>注意這種功能通常是通過(guò)設置HTML頁(yè)面HEAD區的<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path">實(shí)現,這是因為,自動(dòng)刷新或重定向對于那些不能使用CGI或Servlet的HTML編寫(xiě)者十分重要。但是,對于Servlet來(lái)說(shuō),直接設置Refresh頭更加方便。 </P>
<P>注意Refresh的意義是“N秒之后刷新本頁(yè)面或訪(fǎng)問(wèn)指定頁(yè)面”,而不是“每隔N秒刷新本頁(yè)面或訪(fǎng)問(wèn)指定頁(yè)面”。因此,連續刷新要求每次都發(fā)送一個(gè)Refresh頭,而發(fā)送204狀態(tài)代碼則可以阻止瀏覽器繼續刷新,不管是使用Refresh頭還是<META HTTP-EQUIV="Refresh" ...>。 </P>
<P>注意Refresh頭不屬于HTTP 1.1正式規范的一部分,而是一個(gè)擴展,但Netscape和IE都支持它。 </P>
<P>Server  服務(wù)器名字。Servlet一般不設置這個(gè)值,而是由Web服務(wù)器自己設置。  <BR>Set-Cookie  設置和頁(yè)面關(guān)聯(lián)的Cookie。Servlet不應使用response.setHeader("Set-Cookie", ...),而是應使用HttpServletResponse提供的專(zhuān)用方法addCookie。參見(jiàn)下文有關(guān)Cookie設置的討論。  <BR>WWW-Authenticate  客戶(hù)應該在A(yíng)uthorization頭中提供什么類(lèi)型的授權信息?在包含401(Unauthorized)狀態(tài)行的應答中這個(gè)頭是必需的。例如,response.setHeader("WWW-Authenticate", "BASIC realm=\"executives\"")。 <BR>注意Servlet一般不進(jìn)行這方面的處理,而是讓W(xué)eb服務(wù)器的專(zhuān)門(mén)機制來(lái)控制受密碼保護頁(yè)面的訪(fǎng)問(wèn)(例如.htaccess)。 </P>

<P>   8.3 實(shí)例:內容改變時(shí)自動(dòng)刷新頁(yè)面 </P>
<P>   下面這個(gè)Servlet用來(lái)計算大素數。因為計算非常大的數字(例如500位)可能要花不少時(shí)間,所以Servlet將立即返回已經(jīng)找到的結果,同時(shí)在后臺繼續計算。后臺計算使用一個(gè)優(yōu)先級較低的線(xiàn)程以避免過(guò)多地影響Web服務(wù)器的性能。如果計算還沒(méi)有完成,Servlet通過(guò)發(fā)送Refresh頭指示瀏覽器在幾秒之后繼續請求新的內容。 </P>
<P>   注意,本例除了說(shuō)明HTTP應答頭的用處之外,還顯示了Servlet的另外兩個(gè)很有價(jià)值的功能。首先,它表明Servlet能夠處理多個(gè)并發(fā)的連接,每個(gè)都有自己的線(xiàn)程。Servlet維護了一份已有素數計算請求的Vector表,通過(guò)查找素數個(gè)數(素數列表的長(cháng)度)和數字個(gè)數(每個(gè)素數的長(cháng)度)將當前請求和已有請求相匹配,把所有這些請求同步到這個(gè)列表上。第二,本例證明,在Servlet中維持請求之間的狀態(tài)信息是非常容易的。維持狀態(tài)信息在傳統的CGI編程中是一件很麻煩的事情。由于維持了狀態(tài)信息,瀏覽器能夠在刷新頁(yè)面時(shí)訪(fǎng)問(wèn)到正在進(jìn)行的計算過(guò)程,同時(shí)也使得Servlet能夠保存一個(gè)有關(guān)最近請求結果的列表,當一個(gè)新的請求指定了和最近請求相同的參數時(shí)可以立即返回結果。 </P>
<P>   PrimeNumbers.java </P>
<P>   注意,該Servlet要用到前面給出的ServletUtilities.java。另外還要用到:PrimeList.java,用于在后臺線(xiàn)程中創(chuàng )建一個(gè)素數的Vector;Primes.java,用于隨機生成BigInteger類(lèi)型的大數字,檢查它們是否是素數。(此處略去PrimeList.java和Primes.java的代碼。) <BR>package hall;</P>
<P>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;<BR>import java.util.*;</P>
<P>public class PrimeNumbers extends HttpServlet {<BR>  private static Vector primeListVector = new Vector();<BR>  private static int maxPrimeLists = 30;<BR>  <BR>  public void doGet(HttpServletRequest request,<BR>                    HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    int numPrimes = ServletUtilities.getIntParameter(request, "numPrimes", 50);<BR>    int numDigits = ServletUtilities.getIntParameter(request, "numDigits", 120);<BR>    PrimeList primeList = findPrimeList(primeListVector, numPrimes, numDigits);<BR>    if (primeList == null) {<BR>      primeList = new PrimeList(numPrimes, numDigits, true);<BR>      synchronized(primeListVector) {<BR>        if (primeListVector.size() >= maxPrimeLists)<BR>          primeListVector.removeElementAt(0);<BR>        primeListVector.addElement(primeList);<BR>      }<BR>    }<BR>    Vector currentPrimes = primeList.getPrimes();<BR>    int numCurrentPrimes = currentPrimes.size();<BR>    int numPrimesRemaining = (numPrimes - numCurrentPrimes);<BR>    boolean isLastResult = (numPrimesRemaining == 0);<BR>    if (!isLastResult) {<BR>      response.setHeader("Refresh", "5");<BR>    }<BR>    response.setContentType("text/html");<BR>    PrintWriter out = response.getWriter();<BR>    String title = "Some " + numDigits + "-Digit Prime Numbers";<BR>    out.println(ServletUtilities.headWithTitle(title) +<BR>                "<BODY BGCOLOR=\"#FDF5E6\">\n" +<BR>                "<H2 ALIGN=CENTER>" + title + "</H2>\n" +<BR>                "<H3>Primes found with " + numDigits +<BR>                " or more digits: " + numCurrentPrimes + ".</H3>");<BR>    if (isLastResult)<BR>      out.println("<B>Done searching.</B>");<BR>    else<BR>      out.println("<B>Still looking for " + numPrimesRemaining +<BR>                  " more<BLINK>...</BLINK></B>");<BR>    out.println("<OL>");<BR>    for(int i=0; i<numCurrentPrimes; i++) {<BR>      out.println("  <LI>" + currentPrimes.elementAt(i));<BR>    }<BR>    out.println("</OL>");<BR>    out.println("</BODY></HTML>");<BR>  }</P>
<P>  public void doPost(HttpServletRequest request,<BR>                     HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    doGet(request, response);<BR>  }</P>
<P>  // 檢查是否存在同類(lèi)型請求(已經(jīng)完成,或者正在計算)。<BR>  // 如存在,則返回現有結果而不是啟動(dòng)新的后臺線(xiàn)程。<BR>  private PrimeList findPrimeList(Vector primeListVector,<BR>                             int numPrimes,<BR>                             int numDigits) {<BR>    synchronized(primeListVector) {<BR>      for(int i=0; i<primeListVector.size(); i++) {<BR>        PrimeList primes = (PrimeList)primeListVector.elementAt(i);<BR>        if ((numPrimes == primes.numPrimes()) &amp;&amp;<BR>            (numDigits == primes.numDigits()))<BR>          return(primes);<BR>      }<BR>      return(null);<BR>    }<BR>  }<BR>}</P>
<P>   PrimeNumbers.html <BR><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><BR><HTML><BR><HEAD><BR>  <TITLE>大素數計算</TITLE><BR></HEAD><BR><CENTER><BR><BODY BGCOLOR="#FDF5E6"><BR><FORM ACTION="/servlet/hall.PrimeNumbers"><BR>  <B>要計算幾個(gè)素數:</B><BR>  <INPUT TYPE="TEXT" NAME="numPrimes" VALUE=25 SIZE=4><BR><BR>  <B>每個(gè)素數的位數:</B><BR>  <INPUT TYPE="TEXT" NAME="numDigits" VALUE=150 SIZE=3><BR><BR>  <INPUT TYPE="SUBMIT" VALUE="開(kāi)始計算"><BR></FORM><BR></CENTER><BR></BODY><BR></HTML>  <BR></P>
作者: firstcosmos    時(shí)間: 2005-12-15 18:39
<>九、處理Cookie  <BR> <BR> <BR>9.1 Cookie概述 </P>
<>   Cookie是服務(wù)器發(fā)送給瀏覽器的體積很小的純文本信息,用戶(hù)以后訪(fǎng)問(wèn)同一個(gè)Web服務(wù)器時(shí)瀏覽器會(huì )把它們原樣發(fā)送給服務(wù)器。通過(guò)讓服務(wù)器讀取它原先保存到客戶(hù)端的信息,網(wǎng)站能夠為瀏覽者提供一系列的方便,例如在線(xiàn)交易過(guò)程中標識用戶(hù)身份、安全要求不高的場(chǎng)合避免用戶(hù)重復輸入名字和密碼、門(mén)戶(hù)網(wǎng)站的主頁(yè)定制、有針對性地投放廣告,等等。 </P>
<>   Cookie的目的就是為用戶(hù)帶來(lái)方便,為網(wǎng)站帶來(lái)增值。雖然有著(zhù)許多誤傳,事實(shí)上Cookie并不會(huì )造成嚴重的安全威脅。Cookie永遠不會(huì )以任何方式執行,因此也不會(huì )帶來(lái)病毒或攻擊你的系統。另外,由于瀏覽器一般只允許存放300個(gè)Cookie,每個(gè)站點(diǎn)最多存放20個(gè)Cookie,每個(gè)Cookie的大小限制為4 KB,因此Cookie不會(huì )塞滿(mǎn)你的硬盤(pán),更不會(huì )被用作“拒絕服務(wù)”攻擊手段。 </P>
<P>   9.2 Servlet的Cookie API </P>
<P>   要把Cookie發(fā)送到客戶(hù)端,Servlet先要調用new Cookie(name,value)用合適的名字和值創(chuàng )建一個(gè)或多個(gè)Cookie(2.1節),通過(guò)cookie.setXXX設置各種屬性(2.2節),通過(guò)response.addCookie(cookie)把cookie加入應答頭(2.3節)。 </P>
<P>   要從客戶(hù)端讀入Cookie,Servlet應該調用request.getCookies(),getCookies()方法返回一個(gè)Cookie對象的數組。在大多數情況下,你只需要用循環(huán)訪(fǎng)問(wèn)該數組的各個(gè)元素尋找指定名字的Cookie,然后對該Cookie調用getValue方法取得與指定名字關(guān)聯(lián)的值,這部分內容將在2.4節討論。 </P>
<P>   9.2.1 創(chuàng )建Cookie </P>
<P>   調用Cookie對象的構造函數可以創(chuàng )建Cookie。Cookie對象的構造函數有兩個(gè)字符串參數:Cookie名字和Cookie值。名字和值都不能包含空白字符以及下列字符: <BR>  [ ] ( ) = , " / ? @ : ;</P>

<P><BR>   9.2.2 讀取和設置Cookie屬性 </P>
<P>   把Cookie加入待發(fā)送的應答頭之前,你可以查看或設置Cookie的各種屬性。下面摘要介紹這些方法: </P>
<P>getComment/setComment <BR>獲取/設置Cookie的注釋。 <BR>getDomain/setDomain <BR>獲取/設置Cookie適用的域。一般地,Cookie只返回給與發(fā)送它的服務(wù)器名字完全相同的服務(wù)器。使用這里的方法可以指示瀏覽器把Cookie返回給同一域內的其他服務(wù)器。注意域必須以點(diǎn)開(kāi)始(例如.sitename.com),非國家類(lèi)的域(如.com,.edu,.gov)必須包含兩個(gè)點(diǎn),國家類(lèi)的域(如.com.cn,.edu.uk)必須包含三個(gè)點(diǎn)。 <BR>getMaxAge/setMaxAge <BR>獲取/設置Cookie過(guò)期之前的時(shí)間,以秒計。如果不設置該值,則Cookie只在當前會(huì )話(huà)內有效,即在用戶(hù)關(guān)閉瀏覽器之前有效,而且這些Cookie不會(huì )保存到磁盤(pán)上。參見(jiàn)下面有關(guān)LongLivedCookie的說(shuō)明。 <BR>getName/setName <BR>獲取/設置Cookie的名字。本質(zhì)上,名字和值是我們始終關(guān)心的兩個(gè)部分。由于HttpServletRequest的getCookies方法返回的是一個(gè)Cookie對象的數組,因此通常要用循環(huán)來(lái)訪(fǎng)問(wèn)這個(gè)數組查找特定名字,然后用getValue檢查它的值。 <BR>getPath/setPath <BR>獲取/設置Cookie適用的路徑。如果不指定路徑,Cookie將返回給當前頁(yè)面所在目錄及其子目錄下的所有頁(yè)面。這里的方法可以用來(lái)設定一些更一般的條件。例如,someCookie.setPath("/"),此時(shí)服務(wù)器上的所有頁(yè)面都可以接收到該Cookie。 <BR>getSecure/setSecure <BR>獲取/設置一個(gè)boolean值,該值表示是否Cookie只能通過(guò)加密的連接(即SSL)發(fā)送。 <BR>getValue/setValue <BR>獲取/設置Cookie的值。如前所述,名字和值實(shí)際上是我們始終關(guān)心的兩個(gè)方面。不過(guò)也有一些例外情況,比如把名字作為邏輯標記(也就是說(shuō),如果名字存在,則表示true)。 <BR>getVersion/setVersion <BR>獲取/設置Cookie所遵從的協(xié)議版本。默認版本0(遵從原先的Netscape規范);版本1遵從RFC 2109 , 但尚未得到廣泛的支持。 <BR>   9.2.3 在應答頭中設置Cookie </P>
<P>   Cookie可以通過(guò)HttpServletResponse的addCookie方法加入到Set-Cookie應答頭。下面是一個(gè)例子: <BR>  Cookie userCookie = new Cookie("user", "uid1234");<BR>  response.addCookie(userCookie);</P>

<P><BR>   9.2.4 讀取保存到客戶(hù)端的Cookie </P>
<P>   要把Cookie發(fā)送到客戶(hù)端,先要創(chuàng )建Cookie,然后用addCookie發(fā)送一個(gè)Set-Cookie HTTP應答頭。這些內容已經(jīng)在上面的2.1節介紹。從客戶(hù)端讀取Cookie時(shí)調用的是HttpServletRequest的getCookies方法。該方法返回一個(gè)與HTTP請求頭中的內容對應的Cookie對象數組。得到這個(gè)數組之后,一般是用循環(huán)訪(fǎng)問(wèn)其中的各個(gè)元素,調用getName檢查各個(gè)Cookie的名字,直至找到目標Cookie。然后對這個(gè)目標Cookie調用getValue,根據獲得的結果進(jìn)行其他處理。 </P>
<P>   上述處理過(guò)程經(jīng)常會(huì )遇到,為方便計下面我們提供一個(gè)getCookieValue方法。只要給出Cookie對象數組、Cookie名字和默認值,getCookieValue方法就會(huì )返回匹配指定名字的Cookie值,如果找不到指定Cookie,則返回默認值。 </P>
<P>   9.3 幾個(gè)Cookie工具函數 </P>
<P>   下面是幾個(gè)工具函數。這些函數雖然簡(jiǎn)單,但是,在和Cookie打交道的時(shí)候很有用。 </P>
<P>   9.3.1 獲取指定名字的Cookie值 </P>
<P>   該函數是ServletUtilities.java的一部分。getCookieValue通過(guò)循環(huán)依次訪(fǎng)問(wèn)Cookie對象數組的各個(gè)元素,尋找是否有指定名字的Cookie,如找到,則返回該Cookie的值;否則,返回參數中給出的默認值。getCookieValue能夠在一定程度上簡(jiǎn)化Cookie值的提取。 <BR>  public static String getCookieValue(Cookie[] cookies,<BR>               String cookieName,<BR>               String defaultValue) {<BR>    for(int i=0; i<cookies.length; i++) {<BR>      Cookie cookie = cookies;<BR>      if (cookieName.equals(cookie.getName()))<BR>        return(cookie.getValue());<BR>    }<BR>    return(defaultValue);<BR>  }</P>

<P><BR>   9.3.2自動(dòng)保存的Cookie </P>
<P>   下面是LongLivedCookie類(lèi)的代碼。如果你希望Cookie能夠在瀏覽器退出的時(shí)候自動(dòng)保存下來(lái),則可以用這個(gè)LongLivedCookie類(lèi)來(lái)取代標準的Cookie類(lèi)。 <BR>package hall;</P>
<P>import javax.servlet.http.*;</P>
<P>public class LongLivedCookie extends Cookie {<BR>  public static final int SECONDS_PER_YEAR = 60*60*24*365;<BR>  public LongLivedCookie(String name, String value) {<BR>    super(name, value);<BR>    setMaxAge(SECONDS_PER_YEAR);<BR>  }<BR>}</P>

<P><BR>   9.4.實(shí)例:定制的搜索引擎界面 </P>
<P>   下面也是一個(gè)搜索引擎界面的例子,通過(guò)修改前面HTTP狀態(tài)代碼的例子得到。在這個(gè)Servlet中,用戶(hù)界面是動(dòng)態(tài)生成而不是由靜態(tài)HTML文件提供的。Servlet除了負責讀取表單數據并把它們發(fā)送給搜索引擎之外,還要把包含表單數據的Cookie發(fā)送給客戶(hù)端。以后客戶(hù)再次訪(fǎng)問(wèn)同一表單時(shí),這些Cookie的值將用來(lái)預先填充表單,使表單自動(dòng)顯示最近使用過(guò)的數據。 </P>
<P>   SearchEnginesFrontEnd.java </P>
<P>   該Servlet構造一個(gè)主要由表單構成的用戶(hù)界面。第一次顯示的時(shí)候,它和前面用靜態(tài)HTML頁(yè)面提供的界面差不多。然而,用戶(hù)選擇的值將被保存到Cookie(本頁(yè)面將數據發(fā)送到CustomizedSearchEngines Servlet,由后者設置Cookie)。用戶(hù)以后再訪(fǎng)問(wèn)同一頁(yè)面時(shí),即使瀏覽器是退出之后再啟動(dòng),表單中也會(huì )自動(dòng)填好上一次搜索所填寫(xiě)的內容。 </P>
<P>   注意該Servlet用到了ServletUtilities.java,其中g(shù)etCookieValue前面已經(jīng)介紹過(guò),headWithTitle用于生成HTML頁(yè)面的一部分。另外,這里也用到了前面已經(jīng)說(shuō)明的LongLiveCookie類(lèi),我們用它來(lái)創(chuàng )建作廢期限很長(cháng)的Cookie。 <BR>package hall;</P>
<P>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;<BR>import java.net.*;</P>
<P>public class SearchEnginesFrontEnd extends HttpServlet {<BR>  public void doGet(HttpServletRequest request,<BR>                 HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    Cookie[] cookies = request.getCookies();<BR>    String searchString =<BR>      ServletUtilities.getCookieValue(cookies,<BR>             "searchString",<BR>             "Java Programming");<BR>    String numResults =<BR>      ServletUtilities.getCookieValue(cookies,<BR>             "numResults",<BR>             "10");<BR>    String searchEngine =<BR>      ServletUtilities.getCookieValue(cookies,<BR>              "searchEngine",<BR>              "google");<BR>    response.setContentType("text/html");<BR>    PrintWriter out = response.getWriter();<BR>    String title = "Searching the Web";<BR>    out.println(ServletUtilities.headWithTitle(title) +<BR>                "<BODY BGCOLOR=\"#FDF5E6\">\n" +<BR>                "<H1 ALIGN=\"CENTER\">Searching the Web</H1>\n" +<BR>                "\n" +<BR>                "<FORM ACTION=\"/servlet/hall.CustomizedSearchEngines\">\n" +<BR>                "<CENTER>\n" +<BR>                "Search String:\n" +<BR>                "<INPUT TYPE=\"TEXT\" NAME=\"searchString\"\n" +<BR>                "       VALUE=\"" + searchString + "\"><BR>\n" +<BR>                "Results to Show Per Page:\n" +<BR>                "<INPUT TYPE=\"TEXT\" NAME=\"numResults\"\n" + <BR>                "       VALUE=" + numResults + " SIZE=3><BR>\n" +<BR>                "<INPUT TYPE=\"RADIO\" NAME=\"searchEngine\"\n" +<BR>                "       VALUE=\"google\"" +<BR>                checked("google", searchEngine) + ">\n" +<BR>                "Google |\n" +<BR>                "<INPUT TYPE=\"RADIO\" NAME=\"searchEngine\"\n" +<BR>                "       VALUE=\"infoseek\"" +<BR>                checked("infoseek", searchEngine) + ">\n" +<BR>                "Infoseek |\n" +<BR>                "<INPUT TYPE=\"RADIO\" NAME=\"searchEngine\"\n" +<BR>                "       VALUE=\"lycos\"" +<BR>                checked("lycos", searchEngine) + ">\n" +<BR>                "Lycos |\n" +<BR>                "<INPUT TYPE=\"RADIO\" NAME=\"searchEngine\"\n" +<BR>                "       VALUE=\"hotbot\"" +<BR>                checked("hotbot", searchEngine) + ">\n" +<BR>                "HotBot\n" +<BR>                "<BR>\n" +<BR>                "<INPUT TYPE=\"SUBMIT\" VALUE=\"Search\">\n" +<BR>                "</CENTER>\n" +<BR>                "</FORM>\n" +<BR>                "\n" +<BR>                "</BODY>\n" +<BR>                "</HTML>\n");<BR>  }</P>
<P>  private String checked(String name1, String name2) {<BR>    if (name1.equals(name2))<BR>      return(" CHECKED");<BR>    else<BR>      return("");<BR>  }<BR>}</P>

<P><BR>   CustomizedSearchEngines.java </P>
<P>   前面的SearchEnginesFrontEnd Servlet把數據發(fā)送到CustomizedSearchEngines Servlet。本例在許多方面與前面介紹HTTP狀態(tài)代碼時(shí)的例子相似,區別在于,本例除了要構造一個(gè)針對搜索引擎的URL并向用戶(hù)發(fā)送一個(gè)重定向應答之外,還要發(fā)送保存用戶(hù)數據的Cookies。 <BR>package hall;</P>
<P>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;<BR>import java.net.*;</P>
<P>public class CustomizedSearchEngines extends HttpServlet {<BR>  public void doGet(HttpServletRequest request,<BR>                    HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    <BR>    String searchString = request.getParameter("searchString");<BR>    Cookie searchStringCookie =<BR>      new LongLivedCookie("searchString", searchString);<BR>    response.addCookie(searchStringCookie);<BR>    searchString = URLEncoder.encode(searchString);<BR>    String numResults = request.getParameter("numResults");<BR>    Cookie numResultsCookie =<BR>      new LongLivedCookie("numResults", numResults);<BR>    response.addCookie(numResultsCookie);<BR>    String searchEngine = request.getParameter("searchEngine");<BR>    Cookie searchEngineCookie =<BR>      new LongLivedCookie("searchEngine", searchEngine);<BR>    response.addCookie(searchEngineCookie);<BR>    SearchSpec[] commonSpecs = SearchSpec.getCommonSpecs();<BR>    for(int i=0; i<commonSpecs.length; i++) {<BR>      SearchSpec searchSpec = commonSpecs;<BR>      if (searchSpec.getName().equals(searchEngine)) {<BR>        String url =<BR>          searchSpec.makeURL(searchString, numResults);<BR>        response.sendRedirect(url);<BR>        return;<BR>      }<BR>    }<BR>    response.sendError(response.SC_NOT_FOUND,<BR>                       "No recognized search engine specified.");<BR>  }</P>
<P>  public void doPost(HttpServletRequest request,<BR>                     HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    doGet(request, response);<BR>  }<BR>} <BR></P>
作者: firstcosmos    時(shí)間: 2005-12-15 18:40
<>十、會(huì )話(huà)狀態(tài)  <BR> <BR> <BR>10.1 會(huì )話(huà)狀態(tài)概述 </P>
<>   HTTP協(xié)議的“無(wú)狀態(tài)”(Stateless)特點(diǎn)帶來(lái)了一系列的問(wèn)題。特別是通過(guò)在線(xiàn)商店購物時(shí),服務(wù)器不能順利地記住以前的事務(wù)就成了嚴重的問(wèn)題。它使得“購物籃”之類(lèi)的應用很難實(shí)現:當我們把商品加入購物籃時(shí),服務(wù)器如何才能知道籃子里原先有些什么?即使服務(wù)器保存了上下文信息,我們仍舊會(huì )在電子商務(wù)應用中遇到問(wèn)題。例如,當用戶(hù)從選擇商品的頁(yè)面(由普通的服務(wù)器提供)轉到輸入信用卡號和送達地址的頁(yè)面(由支持SSL的安全服務(wù)器提供),服務(wù)器如何才能記住用戶(hù)買(mǎi)了些什么? </P>
<>   這個(gè)問(wèn)題一般有三種解決方法: </P>
<P>Cookie。利用HTTP Cookie來(lái)存儲有關(guān)購物會(huì )話(huà)的信息,后繼的各個(gè)連接可以查看當前會(huì )話(huà),然后從服務(wù)器的某些地方提取有關(guān)該會(huì )話(huà)的完整信息。這是一種優(yōu)秀的,也是應用最廣泛的方法。然而,即使Servlet提供了一個(gè)高級的、使用方便的Cookie接口,仍舊有一些繁瑣的細節問(wèn)題需要處理: <BR>從其他Cookie中分別出保存會(huì )話(huà)標識的Cookie。 <BR>為Cookie設置合適的作廢時(shí)間(例如,中斷時(shí)間超過(guò)24小時(shí)的會(huì )話(huà)一般應重置)。 <BR>把會(huì )話(huà)標識和服務(wù)器端相應的信息關(guān)聯(lián)起來(lái)。(實(shí)際保存的信息可能要遠遠超過(guò)保存到Cookie的信息,而且象信用卡號等敏感信息永遠不應該用Cookie來(lái)保存。) <BR>改寫(xiě)URL。你可以把一些標識會(huì )話(huà)的數據附加到每個(gè)URL的后面,服務(wù)器能夠把該會(huì )話(huà)標識和它所保存的會(huì )話(huà)數據關(guān)聯(lián)起來(lái)。這也是一個(gè)很好的方法,而且還有當瀏覽器不支持Cookie或用戶(hù)已經(jīng)禁用Cookie的情況下也有效這一優(yōu)點(diǎn)。然而,大部分使用Cookie時(shí)所面臨的問(wèn)題同樣存在,即服務(wù)器端的程序要進(jìn)行許多簡(jiǎn)單但單調冗長(cháng)的處理。另外,還必須十分小心地保證每個(gè)URL后面都附加了必要的信息(包括非直接的,如通過(guò)Location給出的重定向URL)。如果用戶(hù)結束會(huì )話(huà)之后又通過(guò)書(shū)簽返回,則會(huì )話(huà)信息會(huì )丟失。 <BR>隱藏表單域。HTML表單中可以包含下面這樣的輸入域:<INPUT TYPE="HIDDEN" NAME="session" VALUE="...">。這意味著(zhù),當表單被提交時(shí),隱藏域的名字和數據也被包含到GET或POST數據里,我們可以利用這一機制來(lái)維持會(huì )話(huà)信息。然而,這種方法有一個(gè)很大的缺點(diǎn),它要求所有頁(yè)面都是動(dòng)態(tài)生成的,因為整個(gè)問(wèn)題的核心就是每個(gè)會(huì )話(huà)都要有一個(gè)唯一標識符。 <BR>   Servlet為我們提供了一種與眾不同的方案:HttpSession API。HttpSession API是一個(gè)基于Cookie或者URL改寫(xiě)機制的高級會(huì )話(huà)狀態(tài)跟蹤接口:如果瀏覽器支持Cookie,則使用Cookie;如果瀏覽器不支持Cookie或者Cookie功能被關(guān)閉,則自動(dòng)使用URL改寫(xiě)方法。Servlet開(kāi)發(fā)者無(wú)需關(guān)心細節問(wèn)題,也無(wú)需直接處理Cookie或附加到URL后面的信息,API自動(dòng)為Servlet開(kāi)發(fā)者提供一個(gè)可以方便地存儲會(huì )話(huà)信息的地方。 </P>
<P>   10.2 會(huì )話(huà)狀態(tài)跟蹤API </P>
<P>   在Servlet中使用會(huì )話(huà)信息是相當簡(jiǎn)單的,主要的操作包括:查看和當前請求關(guān)聯(lián)的會(huì )話(huà)對象,必要的時(shí)候創(chuàng )建新的會(huì )話(huà)對象,查看與某個(gè)會(huì )話(huà)相關(guān)的信息,在會(huì )話(huà)對象中保存信息,以及會(huì )話(huà)完成或中止時(shí)釋放會(huì )話(huà)對象。 </P>
<P>   10.2.1 查看當前請求的會(huì )話(huà)對象 </P>
<P>   查看當前請求的會(huì )話(huà)對象通過(guò)調用HttpServletRequest的getSession方法實(shí)現。如果getSession方法返回null,你可以創(chuàng )建一個(gè)新的會(huì )話(huà)對象。但更經(jīng)常地,我們通過(guò)指定參數使得不存在現成的會(huì )話(huà)時(shí)自動(dòng)創(chuàng )建一個(gè)會(huì )話(huà)對象,即指定getSession的參數為true。因此,訪(fǎng)問(wèn)當前請求會(huì )話(huà)對象的第一個(gè)步驟通常如下所示: <BR>  HttpSession session = request.getSession(true);</P>

<P>   10.2.2 查看和會(huì )話(huà)有關(guān)的信息 </P>
<P>   HttpSession對象生存在服務(wù)器上,通過(guò)Cookie或者URL這類(lèi)后臺機制自動(dòng)關(guān)聯(lián)到請求的發(fā)送者。會(huì )話(huà)對象提供一個(gè)內建的數據結構,在這個(gè)結構中可以保存任意數量的鍵-值對。在2.1或者更早版本的Servlet API中,查看以前保存的數據使用的是getValue("key")方法。getValue返回Object,因此你必須把它轉換成更加具體的數據類(lèi)型。如果參數中指定的鍵不存在,getValue返回null。 </P>
<P>   API 2.2版推薦用getAttribute來(lái)代替getValue,這不僅是因為getAttribute和setAttribute的名字更加匹配(和getValue匹配的是putValue,而不是setValue),同時(shí)也因為setAttribute允許使用一個(gè)附屬的HttpSessionBindingListener 來(lái)監視數值,而putValue則不能。 </P>
<P>   但是,由于目前還只有很少的商業(yè)Servlet引擎支持2.2,下面的例子中我們仍舊使用getValue。這是一個(gè)很典型的例子,假定ShoppingCart是一個(gè)保存已購買(mǎi)商品信息的類(lèi): <BR>  HttpSession session = request.getSession(true);<BR>  ShoppingCart previousItems = <BR>    (ShoppingCart)session.getValue("previousItems");<BR>  if (previousItems != null) {<BR>    doSomethingWith(previousItems);<BR>  } else {<BR>    previousItems = new ShoppingCart(...);<BR>    doSomethingElseWith(previousItems);<BR>  }</P>

<P>   大多數時(shí)候我們都是根據特定的名字尋找與它關(guān)聯(lián)的值,但也可以調用getValueNames得到所有屬性的名字。getValuesNames返回的是一個(gè)String數組。API 2.2版推薦使用getAttributeNames,這不僅是因為其名字更好,而且因為它返回的是一個(gè)Enumeration,和其他方法(比如HttpServletRequest的getHeaders和getParameterNames)更加一致。 </P>
<P>   雖然開(kāi)發(fā)者最為關(guān)心的往往是保存到會(huì )話(huà)對象的數據,但還有其他一些信息有時(shí)也很有用。 </P>
<P>getID:該方法返回會(huì )話(huà)的唯一標識。有時(shí)該標識被作為鍵-值對中的鍵使用,比如會(huì )話(huà)中只保存一個(gè)值時(shí),或保存上一次會(huì )話(huà)信息時(shí)。 <BR>isNew:如果客戶(hù)(瀏覽器)還沒(méi)有綁定到會(huì )話(huà)則返回true,通常意味著(zhù)該會(huì )話(huà)剛剛創(chuàng )建,而不是引用自客戶(hù)端的請求。對于早就存在的會(huì )話(huà),返回值為false。 <BR>getCreationTime:該方法返回建立會(huì )話(huà)的以毫秒計的時(shí)間,從1970.01.01(GMT)算起。要得到用于打印輸出的時(shí)間值,可以把該值傳遞給Date構造函數,或者GregorianCalendar的setTimeInMillis方法。 <BR>getLastAccessedTime:該方法返回客戶(hù)最后一次發(fā)送請求的以毫秒計的時(shí)間,從1970.01.01(GMT)算起。 <BR>getMaxInactiveInterval:返回以秒計的最大時(shí)間間隔,如果客戶(hù)請求之間的間隔不超過(guò)該值,Servlet引擎將保持會(huì )話(huà)有效。負數表示會(huì )話(huà)永遠不會(huì )超時(shí)。 <BR>   10.2.3 在會(huì )話(huà)對象中保存數據 </P>
<P>   如上節所述,讀取保存在會(huì )話(huà)中的信息使用的是getValue方法(或,對于2.2版的Servlet規范,使用getAttribute)。保存數據使用putValue(或setAttribute)方法,并指定鍵和相應的值。注意putValue將替換任何已有的值。有時(shí)候這正是我們所需要的(如下例中的referringPage),但有時(shí)我們卻需要提取原來(lái)的值并擴充它(如下例previousItems)。示例代碼如下: <BR>  HttpSession session = request.getSession(true);<BR>  session.putValue("referringPage", request.getHeader("Referer"));<BR>  ShoppingCart previousItems = <BR>    (ShoppingCart)session.getValue("previousItems");<BR>  if (previousItems == null) {<BR>    previousItems = new ShoppingCart(...);<BR>  }<BR>  String itemID = request.getParameter("itemID");<BR>  previousItems.addEntry(Catalog.getEntry(itemID));</P>
<P>  session.putValue("previousItems", previousItems);</P>

<P>   10.3 實(shí)例:顯示會(huì )話(huà)信息 </P>
<P>   下面這個(gè)例子生成一個(gè)Web頁(yè)面,并在該頁(yè)面中顯示有關(guān)當前會(huì )話(huà)的信息。 <BR>package hall;</P>
<P>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;<BR>import java.net.*;<BR>import java.util.*;</P>
<P>public class ShowSession extends HttpServlet {<BR>  public void doGet(HttpServletRequest request,<BR>                 HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    HttpSession session = request.getSession(true);<BR>    response.setContentType("text/html");<BR>    PrintWriter out = response.getWriter();<BR>    String title = "Searching the Web";<BR>    String heading;<BR>    Integer accessCount = new Integer(0);;<BR>    if (session.isNew()) {<BR>      heading = "Welcome, Newcomer";<BR>    } else {<BR>      heading = "Welcome Back";<BR>      Integer oldAccessCount =<BR>        // 在Servlet API 2.2中使用getAttribute而不是getValue<BR>        (Integer)session.getValue("accessCount"); <BR>      if (oldAccessCount != null) {<BR>        accessCount =<BR>          new Integer(oldAccessCount.intValue() + 1);<BR>      }<BR>    }<BR>    // 在Servlet API 2.2中使用putAttribute<BR>    session.putValue("accessCount", accessCount); <BR>      <BR>    out.println(ServletUtilities.headWithTitle(title) +<BR>                "<BODY BGCOLOR=\"#FDF5E6\">\n" +<BR>                "<H1 ALIGN=\"CENTER\">" + heading + "</H1>\n" +<BR>                "<H2>Information on Your Session:</H2>\n" +<BR>                "<TABLE BORDER=1 ALIGN=CENTER>\n" +<BR>                "<TR BGCOLOR=\"#FFAD00\">\n" +<BR>                "  <TH>Info Type<TH>Value\n" +<BR>                "<TR>\n" +<BR>                "  <TD>ID\n" +<BR>                "  <TD>" + session.getId() + "\n" +<BR>                "<TR>\n" +<BR>                "  <TD>Creation Time\n" +<BR>                "  <TD>" + new Date(session.getCreationTime()) + "\n" +<BR>                "<TR>\n" +<BR>                "  <TD>Time of Last Access\n" +<BR>                "  <TD>" + new Date(session.getLastAccessedTime()) + "\n" +<BR>                "<TR>\n" +<BR>                "  <TD>Number of Previous Accesses\n" +<BR>                "  <TD>" + accessCount + "\n" +<BR>                "</TABLE>\n" +<BR>                "</BODY></HTML>");<BR>  }<BR>  public void doPost(HttpServletRequest request,<BR>                 HttpServletResponse response)<BR>      throws ServletException, IOException {<BR>    doGet(request, response);<BR>  }<BR>}  <BR></P>
作者: firstcosmos    時(shí)間: 2005-12-15 18:40
<>十一、JSP及語(yǔ)法概要  <BR> <BR> <BR>11.1 概述 </P>
<>   JavaServer Pages(JSP)使得我們能夠分離頁(yè)面的靜態(tài)HTML和動(dòng)態(tài)部分。HTML可以用任何通常使用的Web制作工具編寫(xiě),編寫(xiě)方式也和原來(lái)的一樣;動(dòng)態(tài)部分的代碼放入特殊標記之內,大部分以“<%”開(kāi)始,以“%>”結束。例如,下面是一個(gè)JSP頁(yè)面的片斷,如果我們用<a href="http://host/OrderConfirmation.jsp?title=Core+Web+Programming" target="_blank" >http://host/OrderConfirmation.jsp?title=Core+Web+Programming</A>這個(gè)URL打開(kāi)該頁(yè)面,則結果顯示“Thanks for ordering Core Web Programming”。 <BR>Thanks for ordering<BR><I><%= request.getParameter("title") %></I></P>
<>   JSP頁(yè)面文件通常以.jsp為擴展名,而且可以安裝到任何能夠存放普通Web頁(yè)面的地方。雖然從代碼編寫(xiě)來(lái)看,JSP頁(yè)面更象普通Web頁(yè)面而不象Servlet,但實(shí)際上,JSP最終會(huì )被轉換成正規的Servlet,靜態(tài)HTML直接輸出到和Servlet service方法關(guān)聯(lián)的輸出流。 </P>
<P>   JSP到Servlet的轉換過(guò)程一般在出現第一次頁(yè)面請求時(shí)進(jìn)行。因此,如果你希望第一個(gè)用戶(hù)不會(huì )由于JSP頁(yè)面轉換成Servlet而等待太長(cháng)的時(shí)間,希望確保Servlet已經(jīng)正確地編譯并裝載,你可以在安裝JSP頁(yè)面之后自己請求一下這個(gè)頁(yè)面。 </P>
<P>   另外也請注意,許多Web服務(wù)器允許定義別名,所以一個(gè)看起來(lái)指向HTML文件的URL實(shí)際上可能指向Servlet或JSP頁(yè)面。 </P>
<P>   除了普通HTML代碼之外,嵌入JSP頁(yè)面的其他成分主要有如下三種:腳本元素(Scripting Element),指令(Directive),動(dòng)作(Action)。腳本元素用來(lái)嵌入Java代碼,這些Java代碼將成為轉換得到的Servlet的一部分;JSP指令用來(lái)從整體上控制Servlet的結構;動(dòng)作用來(lái)引入現有的組件或者控制JSP引擎的行為。為了簡(jiǎn)化腳本元素,JSP定義了一組可以直接使用的變量(預定義變量),比如前面代碼片斷中的request就是其中一例。 </P>
<P>   注意本文以JSP 1.0規范為基礎。和0.92版相比,新版本的JSP作了許多重大的改動(dòng)。雖然這些改動(dòng)只會(huì )使JSP變得更好,但應注意1.0的JSP頁(yè)面幾乎和早期的JSP引擎完全不兼容。 </P>
<P>   11.2 JSP語(yǔ)法概要表 JSP元素  語(yǔ)法  說(shuō)明  備注  <BR>JSP表達式  <%= expression %>  計算表達式并輸出結果。  等價(jià)的XML表達是: <BR><jsp:expression> <BR>expression <BR></jsp:expression> </P>
<P>可以使用的預定義變量包括:request,response,out,session,application,config,pageContext。這些預定義變量也可以在JSP Scriptlet中使用。 </P>
<P>JSP Scriptlet  <% code %>  插入到service方法的代碼。  等價(jià)的XML表達是: <BR><jsp:scriptlet> <BR>code <BR></jsp:scriptlet> </P>
<P>JSP聲明  <%! code %>  代碼被插入到Servlet類(lèi)(在service方法之外)。  等價(jià)的XML表達是: <BR><jsp:declaration> <BR>code <BR></jsp:declaration> </P>
<P>page指令  <%@ page att="val" %>  作用于Servlet引擎的全局性指令。  等價(jià)的XML表達是 <BR><jsp:directive.page att="val"\>。 </P>
<P>合法的屬性如下表,其中粗體表示默認值: </P>
<P>import="package.class" <BR>contentType="MIME-Type" <BR>isThreadSafe="true|false" <BR>session="true|false" <BR>buffer="size kb|none" <BR>autoflush="true|false" <BR>extends="package.class" <BR>info="message" <BR>errorPage="url" <BR>isErrorPage="true|false" <BR>language="java" </P>
<P>include指令  <%@ include file="url" %>  當JSP轉換成Servlet時(shí),應當包含本地系統上的指定文件。  等價(jià)的XML表達是: </P>
<P><jsp:directive.include <BR>file="url"\>. </P>
<P>其中URL必須是相對URL。 </P>
<P>利用jsp:include動(dòng)作可以在請求的時(shí)候(而不是JSP轉換成Servlet時(shí))引入文件。 </P>
<P>JSP注釋  <%-- comment --%>  注釋?zhuān)籎SP轉換成Servlet時(shí)被忽略。  如果要把注釋嵌入結果HTML文檔,使用普通的HTML注釋標記<-- comment -->。  <BR>jsp:include動(dòng)作  <jsp:include <BR>page="relative URL" <BR>flush="true"/>  當Servlet被請求時(shí),引入指定的文件。  如果你希望在頁(yè)面轉換的時(shí)候包含某個(gè)文件,使用JSP include指令。 <BR>注意:在某些服務(wù)器上,被包含文件必須是HTML文件或JSP文件,具體由服務(wù)器決定(通常根據文件擴展名判斷)。 </P>
<P>jsp:useBean動(dòng)作  <jsp:useBean att=val*/> 或者 <BR><jsp:useBean att=val*> <BR>... <BR></jsp:useBean>  尋找或實(shí)例化一個(gè)Java Bean。  可能的屬性包括: <BR>id="name" <BR>scope="page|request<BR>|session|application" <BR>class="package.class" <BR>type="package.class" <BR>beanName="package.class" </P>
<P>jsp:setProperty動(dòng)作  <jsp:setProperty att=val*/>  設置Bean的屬性。既可以設置一個(gè)確定的值,也可以指定屬性值來(lái)自請求參數。  合法的屬性包括: <BR>name="beanName" <BR>property="propertyName|*" <BR>param="parameterName" <BR>value="val" </P>
<P>jsp:getProperty動(dòng)作  <jsp:getProperty <BR>name="propertyName" <BR>value="val"/>  提取并輸出Bean的屬性。     <BR>jsp:forward動(dòng)作  <jsp:forward <BR>page="relative URL"/>  把請求轉到另外一個(gè)頁(yè)面。     <BR>jsp:plugin動(dòng)作  <jsp:plugin <BR>attribute="value"*> <BR>... <BR></jsp:plugin>  根據瀏覽器類(lèi)型生成OBJECT或者EMBED標記,以便通過(guò)Java Plugin運行Java Applet。     </P>
<P><BR>   11.3 關(guān)于模板文本(靜態(tài)HTML) </P>
<P>   許多時(shí)候,JSP頁(yè)面的很大一部分都由靜態(tài)HTML構成,這些靜態(tài)HTML也稱(chēng)為“模板文本”。模板文本和普通HTML幾乎完全相同,它們都遵從相同的語(yǔ)法規則,而且模板文本也是被Servlet直接發(fā)送到客戶(hù)端。此外,模板文本也可以用任何現有的頁(yè)面制作工具來(lái)編寫(xiě)。 </P>
<P>   唯一的例外在于,如果要輸出“<%”,則模板文本中應該寫(xiě)成“<\%”。  <BR></P>
作者: firstcosmos    時(shí)間: 2005-12-15 18:40
<>十二、腳本元素、指令和預定義變量  <BR> <BR> <BR>12.1 JSP腳本元素 </P>
<>   JSP腳本元素用來(lái)插入Java代碼,這些Java代碼將出現在由當前JSP頁(yè)面生成的Servlet中。腳本元素有三種格式: </P>
<>表達式格式<%= expression %>:計算表達式并輸出其結果。 <BR>Scriptlet格式<% code %>:把代碼插入到Servlet的service方法。 <BR>聲明格式<%! code %>:把聲明加入到Servlet類(lèi)(在任何方法之外)。 <BR>   下面我們詳細說(shuō)明它們的用法。 </P>
<P>   12.1.1 JSP表達式 </P>
<P>   JSP表達式用來(lái)把Java數據直接插入到輸出。其語(yǔ)法如下: <BR><%= Java Expression %></P>

<P>   計算Java表達式得到的結果被轉換成字符串,然后插入到頁(yè)面。計算在運行時(shí)進(jìn)行(頁(yè)面被請求時(shí)),因此可以訪(fǎng)問(wèn)和請求有關(guān)的全部信息。例如,下面的代碼顯示頁(yè)面被請求的日期/時(shí)間: <BR>Current time: <%= new java.util.Date() %></P>

<P>   為簡(jiǎn)化這些表達式,JSP預定義了一組可以直接使用的對象變量。后面我們將詳細介紹這些隱含聲明的對象,但對于JSP表達式來(lái)說(shuō),最重要的幾個(gè)對象及其類(lèi)型如下: </P>
<P>request:HttpServletRequest; <BR>response:HttpServletResponse; <BR>session:和request關(guān)聯(lián)的HttpSession <BR>out:PrintWriter(帶緩沖的版本,JspWriter),用來(lái)把輸出發(fā)送到客戶(hù)端 <BR>   下面是一個(gè)例子: <BR>Your hostname: <%= request.getRemoteHost() %></P>

<P>   最后,如果使用XML的話(huà),JSP表達式也可以寫(xiě)成下面這種形式: <BR><jsp:expression><BR>Java Expression<BR></jsp:expression></P>

<P>   請記住XML元素和HTML不一樣。XML是大小寫(xiě)敏感的,因此務(wù)必使用小寫(xiě)。有關(guān)XML語(yǔ)法的說(shuō)明,請參見(jiàn)《XML教程 》 </P>
<P>   12.1.2 JSP Scriptlet </P>
<P>   如果你要完成的任務(wù)比插入簡(jiǎn)單的表達式更加復雜,可以使用JSP Scriptlet。JSP Scriptlet允許你把任意的Java代碼插入Servlet。JSP Scriptlet語(yǔ)法如下: <BR><% Java Code %></P>

<P>   和JSP表達式一樣,Scriptlet也可以訪(fǎng)問(wèn)所有預定義的變量。例如,如果你要向結果頁(yè)面輸出內容,可以使用out變量: <BR><% <BR>String queryData = request.getQueryString();<BR>out.println("Attached GET data: " + queryData); <BR>%></P>

<P>   注意Scriptlet中的代碼將被照搬到Servlet內,而Scriptlet前面和后面的靜態(tài)HTML(模板文本)將被轉換成println語(yǔ)句。這就意味著(zhù),Scriptlet內的Java語(yǔ)句并非一定要是完整的,沒(méi)有關(guān)閉的塊將影響Scriptlet外的靜態(tài)HTML。例如,下面的JSP片斷混合了模板文本和Scriptlet: <BR><% if (Math.random() < 0.5) { %><BR>Have a <B>nice</B> day!<BR><% } else { %><BR>Have a <B>lousy</B> day!<BR><% } %></P>

<P>   上述JSP代碼將被轉換成如下Servlet代碼: <BR>if (Math.random() < 0.5) { <BR>  out.println("Have a <B>nice</B> day!");<BR>} else { <BR>  out.println("Have a <B>lousy</B> day!");<BR>}</P>

<P>   如果要在Scriptlet內部使用字符“%>”,必須寫(xiě)成“%\>”。另外,請注意<% code %>的XML等價(jià)表達是: <BR><jsp:scriptlet><BR>Code<BR></jsp:scriptlet></P>

<P>   12.1.3 JSP聲明 </P>
<P>   JSP聲明用來(lái)定義插入Servlet類(lèi)的方法和成員變量,其語(yǔ)法如下: <BR><%! Java Code %></P>

<P>   由于聲明不會(huì )有任何輸出,因此它們往往和JSP表達式或Scriptlet結合在一起使用。例如,下面的JSP代碼片斷輸出自從服務(wù)器啟動(dòng)(或Servlet類(lèi)被改動(dòng)并重新裝載以來(lái))當前頁(yè)面被請求的次數: <BR><%! private int accessCount = 0; %><BR>自從服務(wù)器啟動(dòng)以來(lái)頁(yè)面訪(fǎng)問(wèn)次數為:<BR><%= ++accessCount %></P>

<P>   和Scriptlet一樣,如果要使用字符串“%>”,必須使用“%\>”代替。最后,<%! code %>的XML等價(jià)表達方式為: <BR><jsp:declaration><BR>Code<BR></jsp:declaration></P>

<P>   12.2 JSP指令 </P>
<P>   JSP指令影響Servlet類(lèi)的整體結構,它的語(yǔ)法一般如下: <BR><%@ directive attribute="value" %></P>

<P>   另外,也可以把同一指令的多個(gè)屬性結合起來(lái),例如: <BR><%@ directive attribute1="value1" <BR>         attribute2="value2"<BR>         ...<BR>         attributeN="valueN" %></P>

<P>   JSP指令分為兩種類(lèi)型:第一是page指令,用來(lái)完成下面這類(lèi)任務(wù):導入指定的類(lèi),自定義Servlet的超類(lèi),等等;第二是include指令,用來(lái)在JSP文件轉換成Servlet時(shí)引入其他文件。JSP規范也提到了taglib指令,其目的是讓JSP開(kāi)發(fā)者能夠自己定義標記,但JSP 1.0不支持該指令,有希望它將成為JSP 1.1的主要改進(jìn)之一。 </P>
<P>   12.2.1 page指令 </P>
<P>   page指令的作用是定義下面一個(gè)或多個(gè)屬性,這些屬性大小寫(xiě)敏感。 </P>

<P>import="package.class",或者import="package.class1,...,package.classN":</P>
<P>用于指定導入哪些包,例如:<%@ page import="java.util.*" %>。import是唯一允許出現一次以上的屬性。</P>
<P><BR>contentType="MIME-Type" 或contentType="MIME-Type; charset=Character-Set":</P>
<P>該屬性指定輸出的MIME類(lèi)型。默認是text/html。例如,下面這個(gè)指令:<BR><%@ page contentType="text/plain" %>。<BR>和下面的Scriptlet效果相同:<BR><% response.setContentType("text/plain"); %> </P>
<P><BR>isThreadSafe="true|false"</P>
<P>默認值true表明Servlet按照標準的方式處理,即假定開(kāi)發(fā)者已經(jīng)同步對實(shí)例變量的訪(fǎng)問(wèn),由單個(gè)Servlet實(shí)例同時(shí)地處理多個(gè)請求。如果取值false,表明Servlet應該實(shí)現SingleThreadModel,請求或者是逐個(gè)進(jìn)入,或者多個(gè)并行的請求分別由不同的Servlet實(shí)例處理。</P>
<P><BR>session="true|false"</P>
<P>默認值true表明預定義變量session(類(lèi)型為HttpSession)應該綁定到已有的會(huì )話(huà),如果不存在已有的會(huì )話(huà),則新建一個(gè)并綁定session變量。如果取值false,表明不會(huì )用到會(huì )話(huà),試圖訪(fǎng)問(wèn)變量session將導致JSP轉換成Servlet時(shí)出錯。</P>
<P><BR>buffer="size kb|none"</P>
<P>該屬性指定JspWrite out的緩存大小。默認值和服務(wù)器有關(guān),但至少應該是8 KB。</P>
<P><BR>autoflush="true|false"</P>
<P>默認值true表明如果緩存已滿(mǎn)則刷新它。autoflush很少取false值,false值表示如果緩存已滿(mǎn)則拋出異常。如果buffer="none",autoflush不能取false值。</P>
<P><BR>extends="package.class"</P>
<P>該屬性指出將要生成的Servlet使用哪個(gè)超類(lèi)。使用該屬性應當十分小心,因為服務(wù)器可能已經(jīng)在用自定義的超類(lèi)。</P>
<P><BR>info="message"</P>
<P>該屬性定義一個(gè)可以通過(guò)getServletInfo方法提取的字符串。</P>
<P><BR>errorPage="url"</P>
<P>該屬性指定一個(gè)JSP頁(yè)面,所有未被當前頁(yè)面捕獲的異常均由該頁(yè)面處理。</P>
<P><BR>isErrorPage="true|false"</P>
<P>該屬性指示當前頁(yè)面是否可以作為另一JSP頁(yè)面的錯誤處理頁(yè)面。默認值false。</P>
<P><BR>language="java"</P>
<P>該屬性用來(lái)指示所使用的語(yǔ)言。目前沒(méi)有必要關(guān)注這個(gè)屬性,因為默認的Java是當前唯一可用的語(yǔ)言。 <BR>   定義指令的XML語(yǔ)法為: <BR><jsp:directive.directiveType attribute=value /></P>

<P>   例如,下面這個(gè)指令: <BR><%@ page import="java.util.*" %></P>

<P>   它的XML等價(jià)表達是: <BR><jsp:directive.page import="java.util.*" /></P>

<P>   12.2.2 include指令 </P>
<P>   include指令用于JSP頁(yè)面轉換成Servlet時(shí)引入其他文件。該指令語(yǔ)法如下: <BR><%@ include file="relative url" %></P>

<P>   這里所指定的URL是和發(fā)出引用指令的JSP頁(yè)面相對的URL,然而,與通常意義上的相對URL一樣,你可以利用以“/”開(kāi)始的URL告訴系統把URL視為從Web服務(wù)器根目錄開(kāi)始。包含文件的內容也是JSP代碼,即包含文件可以包含靜態(tài)HTML、腳本元素、JSP指令和動(dòng)作。 </P>
<P>   例如,許多網(wǎng)站的每個(gè)頁(yè)面都有一個(gè)小小的導航條。由于HTML框架存在不少問(wèn)題,導航條往往用頁(yè)面頂端或左邊的一個(gè)表格制作,同一份HTML代碼重復出現在整個(gè)網(wǎng)站的每個(gè)頁(yè)面上。include指令是實(shí)現該功能的非常理想的方法。使用include指令,開(kāi)發(fā)者不必再把導航HTML代碼拷貝到每個(gè)文件中,從而可以更輕松地完成維護工作。 </P>
<P>   由于include指令是在JSP轉換成Servlet的時(shí)候引入文件,因此如果導航條改變了,所有使用該導航條的JSP頁(yè)面都必須重新轉換成Servlet。如果導航條改動(dòng)不頻繁,而且你希望包含操作具有盡可能好的效率,使用include指令是最好的選擇。然而,如果導航條改動(dòng)非常頻繁,你可以使用jsp:include動(dòng)作。jsp:include動(dòng)作在出現對JSP頁(yè)面請求的時(shí)候才會(huì )引用指定的文件,請參見(jiàn)本文后面的具體說(shuō)明。 </P>
<P>   12.3 實(shí)例:腳本元素和指令的應用 </P>
<P>   下面是一個(gè)使用JSP表達式、Scriptlet、聲明、指令的簡(jiǎn)單例子。 <BR><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><BR><HTML><BR><HEAD><BR><TITLE>JavaServer Pages</TITLE><BR></HEAD></P>
<P><BODY BGCOLOR="#FDF5E6" TEXT="#000000" LINK="#0000EE"<BR>      VLINK="#551A8B" ALINK="#FF0000"><BR><CENTER><BR><TABLE BORDER=5 BGCOLOR="#EF8429"><BR>  <TR><TH CLASS="TITLE"><BR>      JSP應用實(shí)例</TABLE><BR></CENTER><BR><P><BR>下面是一些利用各種JSP功能生成的動(dòng)態(tài)內容:<BR><UL><BR>  <LI><B>表達式.</B><BR><BR>      你的主機名: <%= request.getRemoteHost() %>.<BR>  <LI><B>JSP Scriptlet.</B><BR><BR>      <% out.println("查詢(xún)字符串: " +<BR>                     request.getQueryString()); %><BR>  <LI><B>聲明(和表達式).</B><BR><BR>      <%! private int accessCount = 0; %><BR>      服務(wù)器啟動(dòng)以來(lái)訪(fǎng)問(wèn)次數: <%= ++accessCount %><BR>  <LI><B>指令(和表達式).</B><BR><BR>      <%@ page import = "java.util.*" %><BR>      當前日期: <%= new Date() %><BR></UL></P>
<P></BODY><BR></HTML></P>

<P>   12.4 JSP預定義變量 </P>
<P>   為了簡(jiǎn)化JSP表達式和Scriptlet的代碼,JSP提供了8個(gè)預先定義的變量(或稱(chēng)為隱含對象)。這些變量是request、response、out、session、application、config、pageContext和page。 </P>
<P>   12.4.1 request </P>
<P>   這是和請求關(guān)聯(lián)的HttpServletRequest,通過(guò)它可以查看請求參數(調用getParameter),請求類(lèi)型(GET,POST,HEAD,等),以及請求的HTTP頭(Cookie,Referer,等)。嚴格說(shuō)來(lái),如果請求所用的是HTTP之外的其他協(xié)議,request可以是ServletRequest的子類(lèi)(而不是HttpServletRequest),但在實(shí)踐中幾乎不會(huì )用到。 </P>
<P>   12.4.2 response </P>
<P>   這是和應答關(guān)聯(lián)的HttpServletResponse。注意,由于輸出流(參見(jiàn)下面的out)是帶緩沖的,因此,如果已經(jīng)向客戶(hù)端發(fā)送了輸出內容,普通Servlet不允許再設置HTTP狀態(tài)代碼,但在JSP中卻是合法的。 </P>
<P>   12.4.3 out </P>
<P>   這是用來(lái)向客戶(hù)端發(fā)送內容的PrintWriter。然而,為了讓response對象更為實(shí)用,out是帶緩存功能的PrintWriter,即JspWriter。JSP允許通過(guò)page指令的buffer屬性調整緩存的大小,甚至允許關(guān)閉緩存。 </P>
<P>   out一般只在Scriptlet內使用,這是因為JSP表達式是自動(dòng)發(fā)送到輸出流的,很少需要顯式地引用out。 </P>
<P>   12.4.4 session </P>
<P>   這是和請求關(guān)聯(lián)的HttpSession對象。前面我們已經(jīng)介紹過(guò)會(huì )話(huà)的自動(dòng)創(chuàng )建,我們知道,即使不存在session引用,這個(gè)對象也是自動(dòng)綁定的。但有一個(gè)例外,這就是如果你用page指令的session屬性關(guān)閉了會(huì )話(huà),此時(shí)對session變量的引用將導致JSP頁(yè)面轉換成Servlet時(shí)出錯。 </P>
<P>   12.4.5 application </P>
<P>   這是一個(gè)ServletContext,也可以通過(guò)getServletConfig().getContext()獲得。 </P>
<P>   12.4.6 config </P>
<P>   這是當前頁(yè)面的ServletConfig對象。 </P>
<P>   12.4.7 pageContext </P>
<P>   主要用來(lái)管理頁(yè)面的屬性。 </P>
<P>   12.4.8 page </P>
<P>   它是this的同義詞,當前用處不大。它是為了Java不再是唯一的JSP編程語(yǔ)言而準備的占位符。  <BR></P>
作者: firstcosmos    時(shí)間: 2005-12-15 18:41
<>十三、JSP動(dòng)作 <BR> <BR> <BR>JSP動(dòng)作利用XML語(yǔ)法格式的標記來(lái)控制Servlet引擎的行為。利用JSP動(dòng)作可以動(dòng)態(tài)地插入文件、重用JavaBean組件、把用戶(hù)重定向到另外的頁(yè)面、為Java插件生成HTML代碼。 </P>
<>   JSP動(dòng)作包括: </P>
<>jsp:include:在頁(yè)面被請求的時(shí)候引入一個(gè)文件。 <BR>jsp:useBean:尋找或者實(shí)例化一個(gè)JavaBean。 <BR>jsp:setProperty:設置JavaBean的屬性。 <BR>jsp:getProperty:輸出某個(gè)JavaBean的屬性。 <BR>jsp:forward:把請求轉到一個(gè)新的頁(yè)面。 <BR>jsp:plugin:根據瀏覽器類(lèi)型為Java插件生成OBJECT或EMBED標記。 <BR>   13.1 jsp:include動(dòng)作 </P>
<P>   該動(dòng)作把指定文件插入正在生成的頁(yè)面。其語(yǔ)法如下: <BR><jsp:include page="relative URL" flush="true" /></P>

<P>   前面已經(jīng)介紹過(guò)include指令,它是在JSP文件被轉換成Servlet的時(shí)候引入文件,而這里的jsp:include動(dòng)作不同,插入文件的時(shí)間是在頁(yè)面被請求的時(shí)候。jsp:include動(dòng)作的文件引入時(shí)間決定了它的效率要稍微差一點(diǎn),而且被引用文件不能包含某些JSP代碼(例如不能設置HTTP頭),但它的靈活性卻要好得多。 </P>
<P>   例如,下面的JSP頁(yè)面把4則新聞?wù)迦胍粋(gè)“What's New ?”頁(yè)面。改變新聞?wù)獣r(shí)只需改變這四個(gè)文件,而主JSP頁(yè)面卻可以不作修改: </P>
<P>   WhatsNew.jsp <BR><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><BR><HTML><BR><HEAD><BR><TITLE>W(wǎng)hat's New</TITLE><BR></HEAD></P>
<P><BODY BGCOLOR="#FDF5E6" TEXT="#000000" LINK="#0000EE"<BR>      VLINK="#551A8B" ALINK="#FF0000"></P>
<P><CENTER><BR><TABLE BORDER=5 BGCOLOR="#EF8429"><BR>  <TR><TH CLASS="TITLE"><BR>      What's New at JspNews.com</TABLE><BR></CENTER><BR><P><BR>Here is a summary of our four most recent news stories:<BR><OL><BR>  <LI><jsp:include page="news/Item1.html" flush="true"/><BR>  <LI><jsp:include page="news/Item2.html" flush="true"/><BR>  <LI><jsp:include page="news/Item3.html" flush="true"/><BR>  <LI><jsp:include page="news/Item4.html" flush="true"/><BR></OL><BR></BODY><BR></HTML></P>

<P>   13.2 jsp:useBean動(dòng)作 </P>
<P>   jsp:useBean動(dòng)作用來(lái)裝載一個(gè)將在JSP頁(yè)面中使用的JavaBean。這個(gè)功能非常有用,因為它使得我們既可以發(fā)揮Java組件重用的優(yōu)勢,同時(shí)也避免了損失JSP區別于Servlet的方便性。jsp:useBean動(dòng)作最簡(jiǎn)單的語(yǔ)法為: <BR><jsp:useBean id="name" class="package.class" /></P>

<P>   這行代碼的含義是:“創(chuàng )建一個(gè)由class屬性指定的類(lèi)的實(shí)例,然后把它綁定到其名字由id屬性給出的變量上”。不過(guò),就象我們接下來(lái)會(huì )看到的,定義一個(gè)scope屬性可以讓Bean關(guān)聯(lián)到更多的頁(yè)面。此時(shí),jsp:useBean動(dòng)作只有在不存在同樣id和scope的Bean時(shí)才創(chuàng )建新的對象實(shí)例,同時(shí),獲得現有Bean的引用就變得很有必要。 </P>
<P>   獲得Bean實(shí)例之后,要修改Bean的屬性既可以通過(guò)jsp:setProperty動(dòng)作進(jìn)行,也可以在Scriptlet中利用id屬性所命名的對象變量,通過(guò)調用該對象的方法顯式地修改其屬性。這使我們想起,當我們說(shuō)“某個(gè)Bean有一個(gè)類(lèi)型為X的屬性foo”時(shí),就意味著(zhù)“這個(gè)類(lèi)有一個(gè)返回值類(lèi)型為X的getFoo方法,還有一個(gè)setFoo方法以X類(lèi)型的值為參數”。 </P>
<P>   有關(guān)jsp:setProperty動(dòng)作的詳細情況在后面討論。但現在必須了解的是,我們既可以通過(guò)jsp:setProperty動(dòng)作的value屬性直接提供一個(gè)值,也可以通過(guò)param屬性聲明Bean的屬性值來(lái)自指定的請求參數,還可以列出Bean屬性表明它的值應該來(lái)自請求參數中的同名變量。 </P>
<P>   在JSP表達式或Scriptlet中讀取Bean屬性通過(guò)調用相應的getXXX方法實(shí)現,或者更一般地,使用jsp:getProperty動(dòng)作。 </P>
<P>   注意包含Bean的類(lèi)文件應該放到服務(wù)器正式存放Java類(lèi)的目錄下,而不是保留給修改后能夠自動(dòng)裝載的類(lèi)的目錄。例如,對于Java Web Server來(lái)說(shuō),Bean和所有Bean用到的類(lèi)都應該放入classes目錄,或者封裝進(jìn)jar文件后放入lib目錄,但不應該放到servlets下。 </P>
<P>   下面是一個(gè)很簡(jiǎn)單的例子,它的功能是裝載一個(gè)Bean,然后設置/讀取它的message屬性。 </P>
<P>   BeanTest.jsp <BR><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><BR><HTML><BR><HEAD><BR><TITLE>Reusing JavaBeans in JSP</TITLE><BR></HEAD></P>
<P><BODY><BR><CENTER><BR><TABLE BORDER=5><BR>  <TR><TH CLASS="TITLE"><BR>      Reusing JavaBeans in JSP</TABLE><BR></CENTER><BR><P></P>
<P><jsp:useBean id="test" class="hall.SimpleBean" /><BR><jsp:setProperty name="test" <BR>          property="message" <BR>          value="Hello WWW" /><BR><H1>Message: <I><BR><jsp:getProperty name="test" property="message" /><BR></I></H1><BR>             <BR></BODY><BR></HTML></P>

<P>   SimpleBean.java </P>
<P>   BeanTest頁(yè)面用到了一個(gè)SimpleBean。SimpleBean的代碼如下: <BR>package hall;</P>
<P>public class SimpleBean {<BR>  private String message = "No message specified";</P>
<P>  public String getMessage() {<BR>    return(message);<BR>  }</P>
<P>  public void setMessage(String message) {<BR>    this.message = message;<BR>  }<BR>}</P>

<P>   13.3 關(guān)于jsp:useBean的進(jìn)一步說(shuō)明 </P>
<P>   使用Bean最簡(jiǎn)單的方法是先用下面的代碼裝載Bean: <BR><jsp:useBean id="name" class="package.class" /> </P>

<P>   然后通過(guò)jsp:setProperty和jsp:getProperty修改和提取Bean的屬性。不過(guò)有兩點(diǎn)必須注意。第一,我們還可以用下面這種格式實(shí)例化Bean: <BR>  <jsp:useBean ...> <BR>    Body <BR>  </jsp:useBean></P>

<P>   它的意思是,只有當第一次實(shí)例化Bean時(shí)才執行Body部分,如果是利用現有的Bean實(shí)例則不執行Body部分。正如下面將要介紹的,jsp:useBean并非總是意味著(zhù)創(chuàng )建一個(gè)新的Bean實(shí)例。 </P>
<P>   第二,除了id和class外,jsp:useBean還有其他三個(gè)屬性,即:scope,type,beanName。下表簡(jiǎn)要說(shuō)明這些屬性的用法。 屬性  用法  <BR>id  命名引用該Bean的變量。如果能夠找到id和scope相同的Bean實(shí)例,jsp:useBean動(dòng)作將使用已有的Bean實(shí)例而不是創(chuàng )建新的實(shí)例。  <BR>class  指定Bean的完整包名。  <BR>scope  指定Bean在哪種上下文內可用,可以取下面的四個(gè)值之一:page,request,session和application。 <BR>默認值是page,表示該Bean只在當前頁(yè)面內可用(保存在當前頁(yè)面的PageContext內)。 <BR>request表示該Bean在當前的客戶(hù)請求內有效(保存在ServletRequest對象內)。 <BR>session表示該Bean對當前HttpSession內的所有頁(yè)面都有效。 <BR>最后,如果取值application,則表示該Bean對所有具有相同ServletContext的頁(yè)面都有效。 <BR>scope之所以很重要,是因為jsp:useBean只有在不存在具有相同id和scope的對象時(shí)才會(huì )實(shí)例化新的對象;如果已有id和scope都相同的對象則直接使用已有的對象,此時(shí)jsp:useBean開(kāi)始標記和結束標記之間的任何內容都將被忽略。 </P>
<P>type  指定引用該對象的變量的類(lèi)型,它必須是Bean類(lèi)的名字、超類(lèi)名字、該類(lèi)所實(shí)現的接口名字之一。請記住變量的名字是由id屬性指定的。  <BR>beanName  指定Bean的名字。如果提供了type屬性和beanName屬性,允許省略class屬性。  </P>
<P><BR>   13.4 jsp:setProperty動(dòng)作 </P>
<P>   jsp:setProperty用來(lái)設置已經(jīng)實(shí)例化的Bean對象的屬性,有兩種用法。首先,你可以在jsp:useBean元素的外面(后面)使用jsp:setProperty,如下所示: <BR><jsp:useBean id="myName" ... /><BR>...<BR><jsp:setProperty name="myName" <BR>    property="someProperty" ... /></P>

<P>   此時(shí),不管jsp:useBean是找到了一個(gè)現有的Bean,還是新創(chuàng )建了一個(gè)Bean實(shí)例,jsp:setProperty都會(huì )執行。第二種用法是把jsp:setProperty放入jsp:useBean元素的內部,如下所示: <BR><jsp:useBean id="myName" ... ><BR>  ...<BR>  <jsp:setProperty name="myName" <BR>     property="someProperty" ... /><BR></jsp:useBean></P>

<P>   此時(shí),jsp:setProperty只有在新建Bean實(shí)例時(shí)才會(huì )執行,如果是使用現有實(shí)例則不執行jsp:setProperty。 </P>
<P>   jsp:setProperty動(dòng)作有下面四個(gè)屬性: 屬性  說(shuō)明  <BR>name  name屬性是必需的。它表示要設置屬性的是哪個(gè)Bean。  <BR>property  property屬性是必需的。它表示要設置哪個(gè)屬性。有一個(gè)特殊用法:如果property的值是“*”,表示所有名字和Bean屬性名字匹配的請求參數都將被傳遞給相應的屬性set方法。  <BR>value  value屬性是可選的。該屬性用來(lái)指定Bean屬性的值。字符串數據會(huì )在目標類(lèi)中通過(guò)標準的valueOf方法自動(dòng)轉換成數字、boolean、Boolean、byte、Byte、char、Character。例如,boolean和Boolean類(lèi)型的屬性值(比如“true”)通過(guò)Boolean.valueOf轉換,int和Integer類(lèi)型的屬性值(比如“42”)通過(guò)Integer.valueOf轉換。 <BR>value和param不能同時(shí)使用,但可以使用其中任意一個(gè)。 </P>
<P>param  param是可選的。它指定用哪個(gè)請求參數作為Bean屬性的值。如果當前請求沒(méi)有參數,則什么事情也不做,系統不會(huì )把null傳遞給Bean屬性的set方法。因此,你可以讓Bean自己提供默認屬性值,只有當請求參數明確指定了新值時(shí)才修改默認屬性值。 <BR>例如,下面的代碼片斷表示:如果存在numItems請求參數的話(huà),把numberOfItems屬性的值設置為請求參數numItems的值;否則什么也不做。 </P>
<P><jsp:setProperty name="orderBean" <BR>property="numberOfItems" <BR>param="numItems" /> </P>
<P>如果同時(shí)省略value和param,其效果相當于提供一個(gè)param且其值等于property的值。進(jìn)一步利用這種借助請求參數和屬性名字相同進(jìn)行自動(dòng)賦值的思想,你還可以在property(Bean屬性的名字)中指定“*”,然后省略value和param。此時(shí),服務(wù)器會(huì )查看所有的Bean屬性和請求參數,如果兩者名字相同則自動(dòng)賦值。 </P>

<P>   下面是一個(gè)利用JavaBean計算素數的例子。如果請求中有一個(gè)numDigits參數,則該值被傳遞給Bean的numDigits屬性;numPrimes也類(lèi)似。 </P>
<P>   JspPrimes.jsp <BR><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><BR><HTML><BR><HEAD><BR><TITLE>在JSP中使用JavaBean</TITLE><BR></HEAD></P>
<P><BODY></P>
<P><CENTER><BR><TABLE BORDER=5><BR>  <TR><TH CLASS="TITLE"><BR>      在JSP中使用JavaBean</TABLE><BR></CENTER><BR><P></P>
<P><jsp:useBean id="primeTable" class="hall.NumberedPrimes" /><BR><jsp:setProperty name="primeTable" property="numDigits" /><BR><jsp:setProperty name="primeTable" property="numPrimes" /></P>
<P>Some <jsp:getProperty name="primeTable" property="numDigits" /> <BR>digit primes: <BR><jsp:getProperty name="primeTable" property="numberedList" /></P>
<P></BODY><BR></HTML></P>

<P>   注:NumberedPrimes的代碼略。 </P>
<P>   13.5 jsp:getProperty動(dòng)作 </P>
<P>   jsp:getProperty動(dòng)作提取指定Bean屬性的值,轉換成字符串,然后輸出。jsp:getProperty有兩個(gè)必需的屬性,即:name,表示Bean的名字;property,表示要提取哪個(gè)屬性的值。下面是一個(gè)例子,更多的例子可以在前文找到。 <BR><jsp:useBean id="itemBean" ... /><BR>...<BR><UL><BR>  <LI>Number of items: <BR>      <jsp:getProperty name="itemBean" property="numItems" /><BR>  <LI>Cost of each:<BR>      <jsp:getProperty name="itemBean" property="unitCost" /><BR></UL></P>

<P>   13.6 jsp:forward動(dòng)作 </P>
<P>   jsp:forward動(dòng)作把請求轉到另外的頁(yè)面。jsp:forward標記只有一個(gè)屬性page。page屬性包含的是一個(gè)相對URL。page的值既可以直接給出,也可以在請求的時(shí)候動(dòng)態(tài)計算,如下面的例子所示: <BR><jsp:forward page="/utils/errorReporter.jsp" /><BR><jsp:forward page="<%= someJavaExpression %>" /></P>

<P>   13.7 jsp:plugin動(dòng)作 </P>
<P>   jsp:plugin動(dòng)作用來(lái)根據瀏覽器的類(lèi)型,插入通過(guò)Java插件 運行Java Applet所必需的OBJECT或EMBED元素。 </P>
<P>   附錄:JSP注釋和字符引用約定 </P>
<P>   下面是一些特殊的標記或字符,你可以利用它們插入注釋或可能被視為具有特殊含義的字符。 語(yǔ)法  用途  <BR><%-- comment --%>  JSP注釋?zhuān)卜Q(chēng)為“隱藏注釋”。JSP引擎將忽略它。標記內的所有JSP腳本元素、指令和動(dòng)作都將不起作用。  <BR><!-- comment -->  HTML注釋?zhuān)卜Q(chēng)為“輸出的注釋”,直接出現在結果HTML文檔中。標記內的所有JSP腳本元素、指令和動(dòng)作正常執行。  <BR><\%  在模板文本(靜態(tài)HTML)中實(shí)際上希望出現“<%”的地方使用。  <BR>%\>  在腳本元素內實(shí)際上希望出現“%>”的地方使用。  <BR>\'  使用單引號的屬性?xún)鹊膯我。不過(guò),你既可以使用單引號也可以使用雙引號,而另外一種引號將具有普通含義。  <BR>\"  使用雙引號的屬性?xún)鹊碾p引號。參見(jiàn)“\'”的說(shuō)明。   <BR></P>




歡迎光臨 91手機維修論壇 (http://www.jstransmit.com/) Powered by Discuz! X3.4
白水县| 新津县| 陇西县| 大渡口区| 遂溪县| 洪洞县| 连州市| 冀州市| 攀枝花市| 内丘县| 南昌县| 谷城县| 上林县| 郴州市| 通城县| 济宁市| 邵阳市| 金溪县| 盘山县| 长白| 深圳市| 武邑县| 聂荣县| 鄂托克前旗| 临潭县| 兴隆县| 将乐县| 汤阴县| 皋兰县| 辽源市| 库尔勒市| 陇西县| 岑巩县| 遂宁市| 土默特左旗| 新沂市| 咸阳市| 项城市| 焉耆| 古浪县| 满城县|