JSP與Servlet
最後更新:2017-02-28
來源:互聯網
上載者:User
js|servlet JSP與Servlet
這篇文章的主要目的不是單純的介紹JSP,也不是詳細的介紹Servlet。這是一篇講述JSP和Servlet之間關係的基礎性文章。這篇文章主要是針對那些學習JSP的人而寫的。至於Servlet和JavaBean以及Servlet和XML我的兩個同學在他們的文檔中將會給出明確的解釋。
本文的主要結構:
1. Servlet是什麼?
2. JSP與Servlet.
3. Servlet 概述
4. 附錄一
5. 附錄二
在講述的過程中,主要是針對JSP和Servlet關係區別來寫。
而本文的內容順序之所以按這種方式來寫是為了體現技術的發展順序。
附錄一提供了有關怎樣來運行一個Servlet的內容,完全是按本人的經驗來寫,其內容已經經過本人的證實。
附錄二中收集了一些純粹的實踐筆記。(轉載)
一. Servlet是什麼?
客戶機/伺服器計算的發展。Java提供了一整套客戶機/伺服器解決方案,在這個方案中,程式可以自動地下載到用戶端並執行,這就是applet。但是它僅僅是問題的一半。問題的另一半就是Servlet。
servlet可以被認為是伺服器端的applet。servlet被Web伺服器載入和執行,就如同applet被瀏覽器載入和執行一樣。servlet從用戶端(通過Web伺服器)接收請求,執行某種作業,然後返回結果。使用servlet的基本流程如下:
·用戶端通過HTTP提出請求.
·Web伺服器接收該請求並將其發給servlet。如果這個servlet尚未被載入,Web伺服器將把它載入到Java虛擬機器並且執行它。
·servlet將接收該HTTP請求並執行某種處理。
·servlet將向Web伺服器返回應答。
·Web伺服器將從servlet收到的應答發送給用戶端。
由於servlet是在伺服器上執行,通常與applet相關的安全性的問題並不需實現。要注意的是Web瀏覽器並不直接和servlet通訊,servlet是由Web伺服器載入和執行的。
而servlet是用Java編寫的,所以它們一開始就是平台無關的。這樣,Java編寫一次就可以在任何平台運行(write once,run anywhere)的承諾就同樣可以在伺服器上實現了。servlet還有一些CGI指令碼所不具備的獨特優點: (本人對CGI並不是十分瞭解,所以這些特點不能完全的體會到,這也是摘自論壇的貼子,請見諒)
servlet是持久的。servlet只需Web伺服器載入一次,而且可以在不同請求之間保持服務(例如一次資料庫連接)。與之相反,CGI指令碼是短暫的、瞬態的。每一次對CGI指令碼的請求,都會使Web伺服器載入並執行該指令碼。一旦這個CGI指令碼運行結束,它就會被從記憶體中清除,然後將結果返回到用戶端。CGI指令碼的每一次使用,都會造成程式初始化過程(例如串連資料庫)的重複執行。
servlet是與平台無關的。如前所述,servlet是用Java編寫的,它自然也繼承了Java的平台無關性。
servlet是可擴充的。由於servlet是用Java編寫的,它就具備了Java所能帶來的所有優點。Java是健壯的、物件導向的程式設計語言,它很容易擴充以適應你的需求。servlet自然也具備了這些特徵。
servlet是安全的。從外界調用一個servlet的惟一方法就是通過Web伺服器。這提供了高水平的安全性保障,尤其是在你的Web伺服器有防火牆保護的時候。
setvlet可以在多種多樣的客戶機上使用。由於servlet是用Java編寫的,所以你可以很方便地在HTML中使用它們,就像你使用applet一樣。
那麼,Servlet是怎樣執行的?怎樣來寫一個Servlet,它的基本架構是怎麼樣的?
這些問題,將在後面部分給予介紹。
二.JSP與Servlet
現在已經對Servlet有了大概的瞭解,現在我們就來說說JSP和Servlet的關係。
JSP是一種指令碼語言,封裝了Java Servlet系統的介面,簡化了Java和Servlet的使用難度,同時通過擴充JSP標籤(TAG)提供了網頁動態執行的能力。儘管如此,JSP仍沒有超出Java和Servlet的範圍,不僅JSP頁面上可以直接寫Java代碼,而且JSP是先被譯成Servlet之後才實際啟動並執行。JSP在伺服器上執行,並將執行結果輸出到用戶端瀏覽器,我們可以說基本上與瀏覽器無關。它是與JavaScript不同的,JavaScript是在用戶端的指令碼語言,在用戶端執行,與伺服器無關。
那麼JSP是什嗎?就是Servlet.
JSP與Servlet之間的主要差異在於,JSP提供了一套簡單的標籤,和HTML融合的比較好,可以使不瞭解Servlet的人可以做出動態網頁來。對於Java語言不熟悉的人(比如像我),會覺得JSP開發比較方便。JSP修改後可以立即看到結果,不需要手工編譯,JSP引擎會來做這些工作;而Servelt缺需要編譯,重新啟動Servlet引擎等一系列動作。但是在JSP中,HTML與程式碼混雜在一起,而Servlet卻不是這樣。也許大家比較混亂了,那麼Servlet又是什嗎?下面我們對JSP的運行來做一個簡單的介紹,告訴大家怎樣來執行一個JSP檔案:
當Web伺服器(或Servlet引擎,應用伺服器)支援JSP引擎時,JSP引擎會照著JSP的文法,將JSP檔案轉換成Servlet代碼源檔案,接著Servlet會被編譯成Java可執行位元組碼(bytecode),並以一般的Servlet方式載入執行
JSP文法簡單,可以方便的嵌入HTML之中,很容易加入動態部分,方便的輸出HTML。在Servlet中輸出HTML缺需要調用特定的方法,對於引號之類的字元也要做特殊的處理,加在複雜的HTML頁面中作為動態部分,比起JSP來說是比較困難的。
除去了轉換和編譯階段,JSP和Servlet之間的區別實在是不大。
JSP引擎通常架構在Servlet引擎之上,本身就是一個Servlet,把JSP檔案轉譯成Servlet原始碼,再調用Java編譯器,編譯成Servlet。這也是JSP在第一次調用時速度比較慢的原因,在第一次編譯之後,JSP與Servlet速度相同.下面我們來看看為什麼他們在第一次編譯後再編譯的速度相同:
在整個運行過程中,JSP引擎會檢查編譯好的JSP(以Servlet形式存在)是否比原始的JSP檔案還新,如果是,JSP引擎不會編譯;如果不是,表示JSP檔案比較新,就會重新執行轉譯與編譯的過程。
為了有個深刻的瞭解,我們看一下JSP的運行和開發環境:
瀏覽器:常見的瀏覽器有IE和Netscape兩種。
資料庫:常用的資料庫有Oracle,SQL Server,Informix,DB2,Sybase,Access,MySQL等。
作業系統:常見的有Windows,Linux,以及各種Unix系統。
Web伺服器:常見的有IIS,Apache,Netscape Enterprise Server等。
JSP引擎:一般JSP引擎都以Servlet引擎為基礎,並以Servlet的形式出現。同時,在各種免費和商業引擎的實現中,Servlet引擎和Jsp引擎通常也是一起出現,我們成為Servlet/JSP引擎,或從某種成為JSP引擎。
JSP引擎是可以提供JSP和Servlet運行支援並對其生存周期進行管理的系統級實體。
在JSP頁面第一次被請求時,JSP引擎會將JSP原始檔案轉換成Servlet原始碼,然後調用Java編譯器,編譯成Servlet,並在Servlet引擎中執行。當再次有請求的時候,JSP引擎會見差異編譯好的JSP是否比原來的JSP原始檔案要新,如果是,運行Servlet;如果不是,表示檔案已經更新的了,就會從新執行轉換和編譯的過程。
說到這裡,也基本把JSP和Servlet的關係說清楚了,從我的感覺上看用JSP就可以了,簡單又方便,又可以和Bean 很好的相容使用,功能又很強大,為什麼又出現了Servlet,它又有什麼用?何況它的編寫又相對複雜。為了把問題說得更清楚一點,我想在這裡說一下曆史,順便再講一下為什麼還要用Servlet,Servlet的好處是什麼。
曆史簡述:(摘自某論壇有刪節,改寫)
簡單的說,SUN首先發展出SERVLET,其功能比較強勁,體系設計也很先進,只是,它輸出HTML語句還是採用了老的CGI方式,是一句一句輸出,所以,編寫和修改HTML非常不方便。
後來SUN推出了類似於ASP的鑲嵌型的JSP(是Servlet發展的產物),把JSP TAG鑲嵌到HTML語句中,這樣,就大大簡化和方便了網頁的設計和修改。新型的網路語言如ASP,PHP,JSP都是鑲嵌型的SCRIPT語言。
從網路三層結構的角度看,一個網路項目最少分三層:data layer,business layer, presentation layer。當然也可以更複雜。SERVLET用來寫business layer是很強大的,但是對於寫presentation layer就很不方便。JSP則主要是為了方便寫presentation layer而設計的。當然也可以寫business layer。寫慣了ASP,PHP,CGI的朋友,經常會不自覺的把presentation layer和business layer混在一起。把資料庫處理資訊放到JSP中,其實,它應該放在business layer中。
根據SUN自己的推薦,JSP中應該僅僅存放與presentation layer有關的內容,也就是說,只放輸出HTML網頁的部份。而所有的資料計算,資料分析,資料庫連接處理,統統是屬於business layer,應該放在JAVA BEANS中。通過JSP調用JAVA BEANS,實現兩層的整合。
實際上,微軟推出的DNA技術,簡單說,就是ASP+COM/DCOM技術。與JSP+BEANS完全類似,所有的presentation layer由ASP完成,所有的business layer由COM/DCOM完成。通過調用,實現整合。現在微軟推出的.NET也是通過這個理念,所有的presentation layer由ASP.NET完成,business layer由C#或VB.NET或VC.NET來完成。
為什麼要採用這些組件技術呢?因為單純的ASP/JSP語言是非常低效率執行的,如果出現大量使用者點擊,純SCRIPT語言很快就到達了他的功能上限,而組件技術就能大幅度提高功能上限,加快執行速度。
另外一方面,純SCRIPT語言將presentation layer和business layer混在一起,造成修改不方便,並且代碼不能重複利用。如果想修改一個地方,經常會牽涉到十幾頁CODE,採用組件技術就只改組件就可以了。
綜上所述,SERVLET是一個早期的不完善的產品,寫business layer很好,寫presentation layer就很不好,並且兩層混雜,顯得十分混亂。
所以,推出JSP+BAEN,用JSP寫presentation layer,用BAEN寫business layer。SUN自己的意思也是將來用JSP替代SERVLET。
看了上面的敘述,大家可能對JSP與Servlet共存有了比較好的認識。可以看到JSP和Bean結合後的的實用性,強大的表現功能,易用性都是Servlet所不能及的。那麼是不是Servlet就被取代了?不是!在以後的發展中,它還是有著巨大的作用的。上面只不過是將了問題的一方面,下面我們來看看Servlet本身的特點。
由於它是由java來寫的,所以相關的特點我們就不說了,上文已經有了詳細的介紹,我們來看看其他的:
Servlet是用於程式開發伺服器端應用程式的一種編程模型,如果只是一個普通的java應用,可以不使用servlet來編寫,但是如果想要提供基於web的服務能力,那麼就必須按照這種模型來編寫,而且servlet也必須允許在符合servlet規範的java web server or app server之上,否則無法運行。除非你自己實現一個web server,但是其複雜度是比較高的,特別是在企業級應用中,對系統的穩定性和健壯性都要求比較高,所以servlet的模型實際上是簡化了編寫穩健的伺服器端的應用開發過程。Servlet 可以作為提供web服務能力的一個接入方式
現在也許可以理解了什麼是Servlet什麼是JSP,它們之間的關係是怎樣的。下面我就對Servlet這個技術做一個簡要的介紹。
Servlet概述
一.Servlet的結構
在Servlet API中最重要的是Servlet interface. 所有的servlets implement(執行)這個interface, 方式多種:或者是直接的,或者通過extending 這個class執行它,如 HttpServlet. 這個Servlet interface 提供安排servlet與用戶端聯絡的方法. Servlet 編寫者可以在他們開發servlet程式時提供更多一些或所有的這樣方法.
當一個servlet接收來自用戶端的調用請求, 它接收兩個對象: 一個是ServletRequest,另外一個是ServletResponse. 這個ServletRequest class 概括從用戶端到伺服器之間的聯絡, 而 ServletResponse class 概括從servlet返回用戶端的聯絡.
ServletRequest interface 可以擷取到這樣一些資訊如由用戶端傳送的闡述名稱,用戶端正在使用的協議, 產生請求並且接收請求的伺服器遠端主機名稱. 它也提供擷取資料流的servlet, ServletInputStream, 這些資料是用戶端引用中使用HTTP POST 和 PUT 方法遞交的. 一個ServletRequest的子類可以讓servlet擷取更多的協議特性資料. 例如: HttpServletRequest 包含擷取HTTP-specific頭部資訊的方法.
ServletResponse interface 給出相應用戶端的servlet方法. 它允許servlet設定內容長度和回應的mime類型, 並且提供輸出資料流, ServletOutputStream, 通過編寫者可以發回相應資料. ServletResponse子類可以給出更多protocol-specific容量的資訊。 例如: HttpServletResponse 包含允許servlet操作HTTP-specific頭部資訊的方法.
上面有關classes 和 interfaces描述構成了一個基本的Servlet架構. HTTP servlets有一些附加的可以提供session-tracking capabilities的方法. servlet編寫者可以用這些API在有他人操作時維護servlet與用戶端之間的狀態.
二.編寫Servlet
Servlets 執行 javax.servlet.Servlet interface. servlet編寫者可以通過直接implement interface開發servlet, 但這樣通常沒有必要. 因為大多數servlet是針對用HTTP協議的web伺服器, 這樣最通用開發servlet辦法是用 javax.servlet.http.HttpServlet 內.HttpServlet 類通過extend GenericServlet基類執行 Servlet interface, 提供了處理HTTP協議的功能. 他的service方法支援標準HTTP/1.1請求. 一般地, 用HttpServlet指定的類編寫的servlets可以多線程地並發運行service方法.
Servlet編寫者注意HttpServlet類有幾個欠缺的方法,你可以自己定義方法中內容,但是必須使用這些方法名稱以使servlet知道你想做什麼,
doGet, 用於處理 GET、有條件的GET 和頭部 HEAD請求
doPost, 使用者處理 POST 請求
doPut, 用於處理 PUT 請求
doDelete, 用於處理 DELETE請求
HttpServlet的service方法, 一般地, 當它接收到一個OPTIONS請求時,會調用doOptions 方法, 當接收一個TRACE請求是調用doTrace . doOptions預設執行方式是自動決定什麼樣的HTTP被選擇並且返回哪個資訊.
在你使用這些方法時,必須帶兩個闡述. 第一個包含來自用戶端的資料HttpServletRequest. 第二個參數包含用戶端的響應HttpServletResponse. 在下例中是這樣的情況.
一個HttpServletRequest對象提供到達HTTP 頭部資料, 也允許你擷取用戶端的資料. 怎樣擷取這些資料取決於HTTP端要求方法.
不管任何HTTP方式, 你可以用]getParameterValues方法, 這個用來返回特定名稱的參數值.
對於用 HTTP GET 請求的方式, 這個getQueryString方法將會返回一個可以用來解剖分析的。對於用HTTP POST, PUT, 和 DELETE請求的方式, 你有兩種方法可以選擇. 如果是文本資料,你能通過getReader方法用BufferedReader擷取;如果是位元據, 能通過getReader 方法用 ServletInputStream擷取.
為了響應用戶端, 一個HttpServletResponse對象提供返回資料給使用者的兩個方法. 你可以用getWriter 方法返回,或者 getOutputStream 方法以輸出資料流返回. 你應該用getWriter返迴文本資料,而用getOutputStream返回位元據.
在使用Writer 或 OutputStream之前, HTTP 頭部應該先被設定. HttpServletResponse內提供這樣一個方法,之後可以用writer 或 outputstream 將響應主體部分發回使用者. 完成後要關閉 writer 或 output stream以便讓伺服器知道響應已經完畢.
附錄一
運行你的Servlet!
當一個servlet已經寫好怎樣來運行測試呢?我花了好長時間來研究這個,也許是因為我太笨。但其實現在想想也不是很難。我想通過一個例子詳細的說說,這樣會有一個感性的把握。我會把我當時遇到的主要問題用黑體字寫出,那時我當時主要浪費時間的地方,希望大家也注意。(我用的運行環境是Tomcat5.0)
首先我們來寫一個最簡單的servlet:
package test;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class HelloServlet extends HttpServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
response.setContentType("text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
PrintWriter out=response.getWriter();
out.println("<HTML>");
out.println("<BODY>");
out.println("<p>Hello!這是我的第一個Java Servlet程式。</p>");
out.println("</BODY>");
out.println("</HTML>");
}
}
由於我們把它進行了打包,所以把這個編譯好的.class檔案放到\Tomcat檔案夾\webapps\ourappfiles\WEB-INF\classes\test的檔案夾下。
接著我們需要寫一個調用該Servlet的html檔案:
<html>
<head>
<title>Java Servlets Sample-Properties</title>
</head>
<body>
<form method="get" action="test.HelloServlet">
<input name="test" type="submit" value="Test HelloServlet servlet">
</body>
</html>
注意:這裡的method不能用post,不然不會在IE中正常顯示,我當初就是在這個地方沒有弄好,浪費了好多時間。至於為什麼這樣寫,我也弄不太清楚,由於水平有限,多多包涵。
現在我們還差最後一步,編寫我們的web.xml檔案。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>helloservlet</servlet-name>
<servlet-class>test.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloservlet</servlet-name>
<url-pattern>/test.HelloServlet</url-pattern>
</servlet-mapping>
</web-app>
把編寫好的web.xml檔案放到\Tomcat檔案夾\webapps\ourappfiles\WEB-INF下。
好了,現在萬事俱備,就差啟動Tomcat運行我們的Servlet了。
以上就是運行Servlet的幾個步驟。
附錄二
這個附錄純粹是另一個讀書筆記,我感覺比較好,所以摘錄下來。裡面寫的是經驗的結晶,我還沒有這麼多的經驗,所以只有摘抄別人的以作補充了。
1.ServletConfig
l 一個ServletConfig對象是servlet container在servlet initialization的時候傳遞給servlet的。
ServletConfig包涵 ServletContext 和 一些 Name/Value pair (來自於deployment descriptor)
l ServletContext介面封裝了Web應用程式的上下文概念。
2.會話跟蹤
1) Session
l 當一個Client請求多個Servlets時,一個session可以被多個servlet共用。
l 通常情況下,如果server detect到browser支援cookie,那麼URL就不會重寫。
2) cookie
l 在Java Servlet中,如果你光 Cookie cookie = new Cookie(name,value)
那麼當使用者退出Browser時,cookie會被刪除掉,而不會被儲存在用戶端的硬碟上。
如果要儲存 cookie,需加一句 cookie.setMaxAge(200)
l cookie是跟某一個server相關的,運行在同一個server上的servlet共用一個cookie.
3) URL Rewriting
在使用URL Rewriting來維護Session ID的時候,每一次HTTP請求都需要EncodeURL()
典型的用在兩個地方
1) out.print(“form action=\” ”);
out.print(response.encodeURL(“sessionExample”));
out.print(“form action=\” ”);
out.print(“method = GET>”);
2) out.print(“<p><a href=\” ”);
out.print(response.encodeURL(“SessionExample?database=foo&datavalue=bar”));
out.println(“\” >URL encoded </a>”);
3.SingleThreadModel
預設的,每一個servlet definition in a container只有一個servlet class的執行個體。
只有實現了SingleThreadModel,container才會讓servlet有多個執行個體。
Servlet specification上建議,不要使用synchronized,而使用SingleThreadModel。
SingleThreadModel(沒有方法)
保證servlet在同一時刻只處理一個客戶的請求。
SingleThreadModel是耗費資源的,特別是當有大量的請求發送給Servlet時,SingleThreadModel的作用是使包容器以同步時鐘的方式調用service方法。
這等同於在servlet的service()方法種使用synchronized.
Single Thread Model一般使用在需要響應一個heavy request的時候,比如是一個需要和資料庫打交道的串連。
2. 在重載Servlet地init( )方法後,一定要記得調用super.init( );
3. the client通過發送一個blank line表示它已經結束request
而the server通過關閉the socket來表示response已結束了。
4. 一個Http Servlet可以送三種東西給Client
1) a single status code
2) any number of http headers
3) a response body
5. Servlet之間資訊共用的一個最簡單的方法就是
System.getProperties().put(“key”,”value”);
6. Post和Get
Post:將form內各欄位名稱和內容放置在html header內傳送給server
Get: ?之後的查詢字串要使用URLEncode,經過URLEncode後,這個字串不再帶有空格,以後將在server上恢複所帶有的空格。
Get是Web上最經常使用的一種要求方法,每個超連結都使用這種方法。
7. Web.xml就是Web Applicatin 的deployment descriptor
作用有:組織各類元素
設定init param
設定安全性
8. Request Dispatcher用來把接收到的request forward processing到另一個servlet
要在一個response裡包含另一個servlet的output時,也要用到Request Dispatcher.
9. Servlet和Jsp在同一個JVM中,可以通過ServeltContext的
setAttribute( )
getAttribute( )
removeAttribute( )
來共用對象
10. 利用request.getParameter( )得到的String存在字元集問題。
可以用 strTitle = request.getParameter(“title”);
strTitle = new String(strTitle.getBytes(“8859-1”),”gb2312”);
如果你希望得到更大得相容性
String encoding = response.getCharacterEncoding(); //確定Application server用什麼編碼來讀取輸入的。
strTitle = new String(strTitle.getBytes(encoding),”gb2312”);