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