1. 程式人生 > >圖解 servlet 與jsp的關系

圖解 servlet 與jsp的關系

網絡傳輸 context 並發 線程 tom 初始 blank string ons

Servlet是Java提供的用於開發Web服務器應用程序的一個組件,運行在服務器端,由Servlet容器所管理,用於生成動態的內容。Servlet是平臺獨立的Java類,編寫一個Servlet,實際上就是按照Servlet規範編寫一個Java類。

技術分享

如圖所示,Java提供一系列接口類(所謂接口類就是類中所有方法只提供方法聲明,不提供任何的方法實現,這些類的實現就留給後繼者去做。):Servlet、ServletConfig、Serializable,然後通過多重繼承產生一個最通用的Servlet實現類(圖中Gerneric Servlet類),接下來,通過一個多重繼承與實現,產生一個新的實現類HttpServlet,用戶在開發Servlet程序時只需繼承這個類,從而產生一個自己的類(圖中Hello_Servlet類),然後根據實際開發功能與信息處理需要,去實現該類中的相關方法即可。這就是前面提到的按照Servlet規範編寫一個Java類,從而編寫一個Servlet。

至於JSP(JavaServlet Page)從圖中可以看出,實際上它也是從Servlet繼承而來。只不過它在Servlet當中又添加/修改了一些方法,作了新的封裝。具體到Tomcat Web應用服務器中,它通過一個多重繼承,分別從Java的HttpJspPage和HttpServlet兩個類那裏繼承和實現一些方法,然後封裝一個叫做HttpJspBase的類從而實現了一個通用化的JSP類,用戶在開發自己的JSP時,只需要從HttpJspBase繼承一個自己的類(如圖中Hello_jsp類),然後根據需要去實現相應的方法即可。

因此這也是為什麽JSP的代碼中總是閃現Servlet代碼框架影子的原因,其實它們只是為實現同樣的功能而進行了不同封裝的組件而已,血脈裏留著的是一樣的血。

“既生瑜何生亮?”呵呵,因為JSP確實比Servlet要更勝一籌,所謂“青出於藍勝於藍”,既然Sun公司要在Servlet基礎上推出JSP技術,那肯定是因為JSP有它更高明的地方。

使用Servlet產生動態網頁,需要在代碼中打印輸出很多HTML的標簽,此外,在Servlet中,我們不得不將靜態現實的內容和動態產生內容的代碼混合在一起。使用Servlet開發動態網頁,程序員和網頁編輯人員將無法一起工作,因為網頁編輯人員不了解Java語言,無法修改Servlet代碼,而Java程序員可能也不是很了解網頁編輯人員的意圖,以至於無法修改和實現網頁功能。為了解決這些問題,Sun公司就推出了JSP技術。


JSP是Servlet的擴展,在沒有JSP之前,就已經出現了Servlet技術。Servlet是利用輸出流動態生成HTML頁面,包括每一個HTML標簽和每個在HTML頁面中出現的內容。

JSP通過在標準的HTML頁面中插入Java代碼,其靜態的部分無須Java程序控制,只有那些需要從數據庫讀取並根據程序動態生成信息時,才使用Java腳本控制。

事實上,JSP是Servlet的一種特殊形式,每個JSP頁面就是一個Servlet實例——JSP頁面由系統編譯成Servlet,Servlet再負責響應用戶請求。JSP其實也是Servlet的一種簡化,使用JSP時,其實還是使用Servlet,因為Web應用中的每個JSP頁面都會由Servlet容器生成對應的Servlet。對於Tomcat而言,JSP頁面生成的Servlet放在work路徑對應的Web應用下。

以apache-tomcat-7.0.37\webapps\myapp\index.jsp為例,

1 <html>  
2 <body>  
3 <center>   
4 Now time is: <%=new java.util.Date()%>   
5 </center>  
6 </body>  
7 </html> 

當啟動Tomcat之後,可以在Tomcat的apache-tomcat-7.0.37\work\Catalina\localhost\myapp\org\apache\jsp目錄下找到如下文件:indexd.java和index.class。這兩個文件都是Tomcat生成的,Tomcat根據JSP頁面生成對應Servlet的Java文件及class文件。

index.java

 1     //JSP頁面經過Tomcat編譯後默認的包  
 2     package org.apache.jsp;  
 3       
 4     import javax.servlet.*;  
 5     import javax.servlet.http.*;  
 6     import javax.servlet.jsp.*;  
 7       
 8     //繼承HttpJspBase類,該類其實是個Servlet的子類  
 9     public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase  
10         implements org.apache.jasper.runtime.JspSourceDependent {  
11       
12       private static final javax.servlet.jsp.JspFactory _jspxFactory =  
13               javax.servlet.jsp.JspFactory.getDefaultFactory();  
14       
15       private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;  
16       
17       private javax.el.ExpressionFactory _el_expressionfactory;  
18       private org.apache.tomcat.InstanceManager _jsp_instancemanager;  
19       
20       public java.util.Map<java.lang.String,java.lang.Long> getDependants() {  
21         return _jspx_dependants;  
22       }  
23       
24       public void _jspInit() {  
25         _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();  
26         _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());  
27       }  
28       
29       public void _jspDestroy() {  
30       }  
31       
32       //用於響應用戶的方法  
33       public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)  
34             throws java.io.IOException, javax.servlet.ServletException {  
35       
36         final javax.servlet.jsp.PageContext pageContext;  
37         javax.servlet.http.HttpSession session = null;  
38         final javax.servlet.ServletContext application;  
39         final javax.servlet.ServletConfig config;  
40         //獲得頁面輸出流  
41         javax.servlet.jsp.JspWriter out = null;  
42         final java.lang.Object page = this;  
43         javax.servlet.jsp.JspWriter _jspx_out = null;  
44         javax.servlet.jsp.PageContext _jspx_page_context = null;  
45       
46       
47         //開始生成響應  
48         try {  
49           //設置輸出的頁面格式  
50           response.setContentType("text/html");  
51           pageContext = _jspxFactory.getPageContext(this, request, response,  
52                     null, true, 8192, true);  
53           _jspx_page_context = pageContext;  
54           application = pageContext.getServletContext();  
55           config = pageContext.getServletConfig();  
56           session = pageContext.getSession();  
57           //頁面輸出流  
58           out = pageContext.getOut();  
59           _jspx_out = out;  
60       
61           //輸出流,開始輸出頁面文檔  
62           out.write("<html>\r\n");  
63           out.write("<body>\r\n");  
64           out.write("<center> \r\n");  
65           out.write("Now time is: ");  
66           out.print(new java.util.Date());  
67           out.write(" \r\n");  
68           out.write("</center>\r\n");  
69           out.write("</body>\r\n");  
70           out.write("</html>");  
71         } catch (java.lang.Throwable t) {  
72           if (!(t instanceof javax.servlet.jsp.SkipPageException)){  
73             out = _jspx_out;  
74             if (out != null && out.getBufferSize() != 0)  
75               try { out.clearBuffer(); } catch (java.io.IOException e) {}  
76             if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);  
77             else throw new ServletException(t);  
78           }  
79         } finally {  
80           _jspxFactory.releasePageContext(_jspx_page_context);  
81         }  
82       }  
83     }  


JSP頁面中內置了幾個對象,如pageContext、application、config、page、session、out等_jspService()方法,這幾個內置對象就是在這裏定義的。

根據上面的JSP頁面工作原理圖,可以得到如下結論: JSP文件必須在JSP服務器內運行。JSP文件必須生成Servlet才能執行。每個JSP頁面的第一個訪問者速度很慢,因為必須等待JSP編譯成Servlet。JSP頁面的訪問者無須安裝任何客戶端,甚至不需要可以運行Java的運行環境,因為JSP頁面輸送到客戶端的是標準HTML頁面。index.jsp頁面中的每個字符都由index.java文件的輸出流生成.
servlet是在web服務器上的java程序,它提供服務,由它來傳遞給你html的格式。Servlet API為Servlet提供了統一的編程接口
Servlet必須部署在Servlet容器,才能響應客戶端的請求 對外提供服務。要對外統一接口,由容器來調用。
jsp側重顯示;servlet側重控制邏輯。
MVC模式:Jsp + Servlet + JavaBean。M-JavaBean V-Jsp C-Servlet
小應用程序(Applet)是指采用Java創建的基於HTML的程序。瀏覽器將其暫時下載到用戶的硬盤上,並在Web頁打開時在本地運行。們可以直接嵌入到網頁或者其他特定的容器中,並能夠產生特殊的效果。

目前,Servlet引擎一般是第三方的插件,它通過一定的方法連接到Web服務器,Servlet引擎把它識別為Servlet請求的那些HTTP請求截獲下來處理,而其他的HTTP請求由Web服務器按照通常的方式來處理,Servlet引擎會裝載合適的Servlet到內存中,如果Servlet還沒有運行的話,會分配一個可以使用的線程來處理請求,再把Servlet的輸出返回到發出請求的Web客戶機。

Java Applet正好是相對應的兩種程序類型,Applet運行在客戶端,在瀏覽器內執行,而Servlet在服務器內部運行,通過客戶端提交的請求啟動運行。

同樣的Servlet完全可以在Apache,IIS等不同Web服務器上執行,不管底層的操作系統是Windows,Solaris,Mac,Linux。

Java Servlet有著十分廣泛的應用。使用Servlet還可以實現大量的服務器端的管理維護功能,以及各種特殊的任務,比如,並發處理多個請求,轉送請求,代理等。

典型的Servlet運行環境有JSWDK,Tomcat,Resin等,。它們都自帶一個簡單的HTTP Server,只需簡單配置即可投入使用,你也可以把它們綁定到常用的Web服務器上,如Apache,IIS等,提供小規模的Web服務,如JRun,Web Sphere,Web Logic等等,配置比較復雜,並不適合初學者。但是功能較為強大,有條件的讀者可以一試

 1   import java.io.*;  
 2  import java.util.*;  
 3  import javax.servlet.http.*;  
 4  import javax.servlet.*;  
 5  //導入必要的包  
 6  public class HelloServlet extends HttpServlet {   
 7    //所有Servlet必須從HttpServlet派生  
 8    public void doGet (HttpServletRequest req, HttpServletResponse res)   
 9    throws ServletException, IOException   
10    //doGet()是這個Servlet的核心,真正處理請求的地方  
11  {  
12  res.setContentType("text/html");   
13    //設置相應的類型為text/html  
14  PrintWriter pw = res.getWriter();   
15    //從HttpServletResponse得到輸出流     
16    pw.println("<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 Transitional//EN"">");  
17  pw.println("<head>");  
18  pw.println("<meta http-equiv=""Content-Type"" content=""text/html; charset=ISO-8859-1"">");  
19  pw.println("<!-- The Servlet expression tags interpolate script variables into the HTML -->");  
20  pw.println("<title>Hello, world!</title>");  
21  pw.println("</head>");  
22  pw.println("<body bgcolor=#cc99dd>");  
23  pw.println("<h1>Hello, world!</h1>");  
24  pw.println("</body>");  
25  //上面的語句都是向客戶端打印HTML文本  
26  pw.close();   
27  //關閉HttpServletResponse,使Web服務器知道相應結束  
28 }  
29 public HelloServlet() {} //構造函數,可以不要  

Servlet使用HttpServlet類中的方法與表單進行交互。在HttpServlet類中有幾個未完全實現的方法,你可以自己定義方法的內容,但是必須正確使用方法名稱以使HTTP Server把客戶請求正確的映射到相應的函數上。
  doHeader 用於處理HEADER請求
  doGet 用於處理GET請求,也可以自動的支持HEADER請求
  doPost 用於處理POST請求
  doPut 用於處理PUT請求
  doDelete 用於處理DELETE請求

不管何種HTTP方式,都可以用getParameterValues方法返回特定名稱的參數值。 在進行HTTP網絡傳輸的時候,統一采用的編碼方式是ISO-8859-1

字符編碼轉換常用的方法是
  String native_encoded = "中文字符串"; //得到本地編碼的字節數組
  String net_encoded = new String(native_encoded, "ISO-8859-1"); 例:out.println(new String(new String("<td>你的姓名:</td>").getBytes(),"ISO-8859-1"));

會話狀態的維持是開發Web應用所必須面對的問題,有多種方法可以來解決這個問題,如使用Cookies,或直接把狀態信息加到URL中等,還有Servlet本身提供了一個HttpSession接口來支持會話狀態的維持 。

從服務器這端來看,每一個請求都是獨立的,因此HTTP協議被認為是無狀態協議,當用戶在多個主頁間切換時,服務器無法知道他的身份。Session的出現就是為了彌補這個局限。利用Session,您就可以當一個用戶在多個主頁間切換的時候也能保存他的信息。這樣很多以前根本無法去做的事情就變得簡單多了。
在訪問者從到達某個特定的主頁到離開為止的那段時間,每個訪問者都會單獨獲得一個Session

Java Servlet定義了一個HttpSession接口,實現的Session的功能,在Servlet中使用Session的過程如下:
  (1) 使用HttpServletRequest的getSession方法得到當前存在的session,如果當前沒有定義session,則創建一個新的session,還可以使用方法getSession(true)
  (2) 寫session變量。可以使用方法HttpSession.setAttribute(name,value)來向Session中存儲一個信息。
  (3) 讀Session變量。可以使用方法HttpSession.getAttribute(name)來讀取Session中的一個變量值,如果name是一個沒有定義的變量,那麽返回的是null。需要註意的是,從getAttribute讀出的變量類型是Object,必須使用強制類型轉換,比如:String uid = (String) session.getAttribute("uid");
  (4) 關閉session,當時用完session後,可以使用session.invalidate()方法關閉session。但是這並不是嚴格要求的。因為,Servlet引擎在一段時間之後,自動關閉seesion。
HttpSession session = request.getSession(true); //參數true是指在沒有session時創建一個新的
   Date created = new Date(session.getCreationTime()); //得到session對象創建的時間
   out.println("ID " + session.getId()+"<br>"); //得到該session的id,並打印
   out.println("Created: " + created+"<br>");//打印session創建時間
   session.setAttribute("UID","12345678"); //在session中添加變量UID=12345678
   session.setAttribute("Name","Tom"); //在session中添加變量Name=Tom  10.2.4 Servlet的生命周期

跟客戶端的Applet相似,Servlet也遵循嚴格的生命周期。在每個Servlet實例的生命中有三種類型的事件,這三種事件分別對應於由Servlet引擎所喚醒的三個方法:
  1.init()。當Servlet第一次被裝載時,Servlet引擎調用這個Servlet的init()方法,只調用一次。系統保證,在init方法成功完成以前,是不會調用Servlet去處理任何請求的。
  2.service()。這是Servlet最重要的方法,是真正處理請求的地方。對於每個請求,Servlet引擎將調用Servlet的service方法,並把Servlet請求對象和Servlet響應對象作為參數傳遞給它。
  3.destroy()。這是相對於init的可選方法,當Servlet即將被卸載時由Servlet引擎來調用,這個方法用來清除並釋放在init方法中所分配的資源。
Servlet的生命周期可以被歸納為以下幾步:
  (1) 裝載Servlet,這一項操作一般是動態執行的。然而,Servlet通常會提供一個管理的選項,用於在Servlet啟動時強制裝載和初始化特定的Servlet
  (2) Server創建一個Servlet實例
  (3) Server調用Servlet的init方法
  (4) 一個客戶端請求到達Server
  (5) Server創建一個請求對象
  (6) Server創建一個響應對象
  (7) Server激活Servlet的service方法,傳遞請求和響應對象作為參數
  (8) service方法獲得關於請求對象的信息,處理請求,訪問其他資源,獲得需要的信息
  (9) service方法使用響應對象的方法。將響應傳回Server,最終到達客戶端。Service方法可能激活其他方法以處理請求。如doGet,doPost或其他程序員自己開發的方法
  (10) 對於更多的客戶端請求,Server創建新的請求和響應對象,仍然激活此servlet的service方法,將這兩個對象作為參數傳遞給它,如此重復以上的循環,但無需再次調用init方法,Servlet一般只初始化一次
  (11) 當Server不再需要Servlet時,比如當Server要關閉時,Server調用Servlet的destroy

采用JSP來表現頁面,采用Servlet來完成大量的處理,Servlet扮演一個控制者的角色,並負責響應客戶請求。Servlet創建JSP需要的Bean和對象,根據用戶的行為,決定將哪個JSP頁面發送給用戶。特別要註意的是,JSP頁面中沒有任何商業處理邏輯,它只是簡單的檢索Servlet先前創建的Beans或者對象,再將動態內容插入預定義的模板。

 1     <pre name="code" class="html"></pre>  
 2     <pre></pre>  
 3     <pre name="code" class="html"><pre></pre>  
 4     <pre></pre>  
 5     <pre></pre>  
 6     <pre></pre>  
 7     <pre></pre>  
 8     <pre></pre>  
 9          
10     </pre>  

圖解 servlet 與jsp的關系