Servlets和JSP開發原則
最後更新:2017-02-28
來源:互聯網
上載者:User
js|servlet Servlet和JSP技術是用Java程式開發伺服器端應用的主要技術,是開發商務應用表示端的標準。Java開發人員喜歡使用它有多種原因,其一是對於已經熟悉Java語言的開發人員來說這個技術容易學習;其二是Java把“一次編寫,到處運行”的理念帶入到Web應用中,實現了“一次編寫,到處實現”。而且更為重要的是,如果遵循一些良好的設計原則的話,就可以把表示和內容相分離,創造出高品質的、可以複用的、易於維護和修改的應用程式。比方說,在HTML文檔中如果嵌入過多的Java代碼(scriptlet),就會導致開發出來的應用非常複雜、難以閱讀、不容易複用,而且對以後的維護和修改也會造成困難。事實上,在CSDN的JSP/Servlet論壇中,經常可以看到一些提問,代碼很長,可以邏輯卻不是很清晰,大量的HTML和Java代碼混雜在一起,讓人看得一頭霧水。這就是隨意開發的弊端。
如果你已經基本瞭解JSP和Servlet的各項技術(最好也開發過一些Web應用),那麼我們可以一起探討一下如何開發“好”的應用的一些指導原則。我們首先對Servlet和JSP技術做一個瀏覽。
Servlet和JSP概覽
早期的動態網頁主要採用CGI(Common Gateway Interface,公用網關介面)技術,你可以使用不同的語言編寫CGI程式,如VB、C/C++或Delphi等。雖然CGI技術發展成熟且功能強大,但由於編程困難、效率低下、修改複雜等缺點,所以有逐漸被取代的趨勢。在所有的新技術中,JSP/Servlet具備更高效、更容易編程、功能更強、更安全和具有良好的可移植性,因而被許多人認為是未來最有發展前途的動態網站技術。
與CGI相似,Servlet支援要求/響應模型。當一個客戶向伺服器遞交一個請求時,伺服器把請求送給Servlet,Servlet負責處理請求並產生響應,然後送給伺服器,再由伺服器發送給客戶。與CGI不同的是,Servlet沒有產生新的進程,而是與HTTP Server處於同一進程中。它通過使用線程技術,減小了伺服器的開銷。Servlet處理請求的過程是這樣的:當收到來自用戶端的請求後,調用service方法,該方法中Servlet先判斷到來的請求是什麼類型的(GET/POST/HEAD…),然後調用相應的處理方法(doGet/doPost/doHead…)並產生響應。
別看這麼複雜,其實簡單說來Servlet就是一個Java類。與一般類的不同之處是,這個類運行在一個Servlet容器內,可以提供session管理和對象生命週期管理。因而當你使用Servlet的時候,你可以得到Java平台的所有好處,包括安全性管理、使用JDBC訪問資料庫以及跨平台的能力。而且,Servlet使用線程,因而可以開發出效率更高的Web應用。
JavaServer Pages (JSP)
JSP技術是J2EE的一個關鍵技術,它在更高一級的層次上抽象Servlet。它可以讓常規靜態HTML與動態產生的內容相結合,看起來像一個HTML網頁,卻作為Servlet來運行。現在有許多商業應用伺服器支援JSP技術,比如BEA WebLogic、IBM WebSphere、 JRun等等。使用JSP比用Servlet更簡單。如果你有一個支援JSP的Web伺服器,並且有一個JSP檔案,你可以把它放倒任何靜態HTML檔案可以放置的位置,不用編譯,不用打包,也不用進行ClassPath的設定,就可以像訪問普通網頁那樣訪問它,伺服器會自動幫你做好其他的工作。
JSP工作原理
JSP 檔案看起來就像一個普通靜態HTML檔案,只不過裡麵包含了一些Java代碼。它使用.jsp的尾碼,用來告訴伺服器這個檔案需要特殊的處理。當我們訪問一個JSP頁面的時候,這個檔案首先會被JSP引擎翻譯為一個Java源檔案,其實就是一個Servlet,並進行編譯,然後像其他Servlet一樣,由Servlet引擎來處理。Servlet引擎裝載這個類,處理來自客戶的請求,並把結果返回給客戶,如下圖所示:
screen.width-333)this.width=screen.width-333;">
圖1: 調用JSP頁面的流程
以後再有客戶訪問這個頁面的時候,只要該檔案沒有發生過更改,JSP引擎就直接調用已經裝載的Servlet。如果已經做過修改的話,那就會再次執行以上過程,翻譯、編譯並裝載。其實這就是所謂的“第一人懲罰”。因為首次訪問的時候要執行一系列以上的過程,所以會耗費一些時間;以後的訪問就不會這樣了。
開發原則
這一部分我們列出一些開發原則,重點是JSP頁面。關於如何分離表現和內容的MVC因為要涉及到JSP和Servlet的整合,我們稍候再談。
不要在JSP頁面中嵌入過量的Java代碼:對於非常簡單或是測試性的代碼,把所有的Java 代碼直接放入JSP頁面內是沒有問題的。但是這種方法不應該被過度使用,否則就會產生一大堆HTML和Java混合起來的代碼,讓人難以閱讀和理解。解決方案是寫一個單獨的類,用來執行相關的計算。一旦這個類測試通過,就可以把它放在任何執行同樣計算的場合中。這樣可以促進代碼的複用。
選擇合適的包含(include)機制: 如果一個應用中每個頁面有一樣的抬頭和底部,或者還有導航條,那麼就應該把它們放到一個單獨的檔案中,然後在每一個頁面中使用包含機制把它們加入到這個頁面中:
Include 指令: <%@ include file="filename" %>或等效xml文法
<jsp:directive.includefile=”filename” />
Include 動作: <jsp:include page="page.jsp" flush="true" />
Include指令是當JSP頁面翻譯為Servlet的時候包含另外一個檔案,Include 動作是當請求時包含另外一個檔案的輸出。如果被包含的檔案不是經常改動的時候,我建議使用Include 指令,這樣速度更快。如果被包含的檔案需要不時改動或者知道請求時才能決定需要包含的內容時,那麼應該使用Include 動作。
如果你使用JSP標準標記庫(JavaServer pages Standard Tag Library即JSTL)的話,那麼還有第三中包含機制<c:import>,可以用來包含本地或者遠端資源。例如:
<c:import url="./copyright.html"/>
<c:import url="http://www.somewhere.com/hello.xml"/>
不要把商務邏輯和表示混合在一起: 複雜的應用涉及大量的代碼,因而把商務邏輯和前端的表示相分離就顯得格外重要,這種分離可以讓任何一方的變化不會影響到另外一方。所以,所有的JSP代碼都應該限制在展示層,可是如果這樣的話,你如何?你的商務邏輯呢?這就是JavaBean所做的事情。JavaBean技術是一個獨立於平台的組件模型,它讓開發人員編寫、測試通過一個組件後,可以隨處使用,提高了複用性。在JSP技術中,JavaBean實現了商務邏輯部分,它把資料返回給JSP頁面,由JSP頁面負責格式化資料並輸出到用戶端的瀏覽器。在JSP頁面中使用JavaBean組件的好處是:
產生了可以複用的組件:任何應用都可以使用這些組件
可以把商務邏輯和表示相分離:你可以修改資料的顯示方式而不用考慮商務邏輯。這樣做的結果也可以明確工作中開發人員的分工,網頁開發人員可以把精力放到如何顯示資料上,Java開發人員則更為關注商務邏輯的實現。
對於JavaBean你不用提供原始碼,這樣你的代碼就不會被瀏覽器網頁的人輕易獲得,可以保護你的勞動成果。
如果你的應用中使用了EJB組件,那麼商務邏輯就應該放置在EJB中,因為EJB模型提供了生命週期管理、交易管理以及多客戶訪問域對象(Entity Beans)。你可以仔細看一下Enterprise BluePrints中的例子,它就是這麼做的。
使用定製的標記: 上面我們已經討論過,把所有Java代碼嵌入到JSP頁面內並不合適,因為網頁開發人員並不一定懂得Java語言,更難以理解Java文法。JavaBean可以封裝很多Java代碼,不過在JSP頁面內使用JavaBean仍然要求頁面開發人員瞭解一些Java文法。
JSP技術中包含了定製標記庫的功能。Java開發人員可以產生自己的標記庫,這樣網頁設計人員就可以使用類似HTML的文法來使用這些標記。編寫和使用自己定製的標記庫可以在更大程度上促進商務邏輯和表示的分離。使用定製標記庫主要有以下好處:
可以消除在JSP頁面中使用scriptlet 標記使用的任何參數都可以通過屬性傳入,從而不需要使用Java代碼就可以達到希望的目的。
可以簡化使用 網頁設計人員不需要學會使用Java文法,他們可以用類似HTML文法就可以使用標記。
不懂Java的網頁設計人員可以使用標記庫來完成單獨使用HTML不能完成的任務。
提高了複用性 標記庫完全可以複用,這可以節省開發與測試的時間。Scriptlet代碼只能在“拷貝粘貼”層級上進行“複用”。
簡單說來,你可以像用HTML構建展示層一樣使用標記庫完成非常複雜的任務。下面是表頁標記庫的一些注意事項:
1. 保持簡潔性:如果一個標記需要好幾個屬性的話,那麼儘可能把它分為幾個標記。
2. 保持複用性:同標記的使用人員(網頁設計人員)多多交流,盡量開發出可以高度複用的標記庫。
3. 不要一切都從頭開始:現在已經有一些可以免費使用的標記庫,比如Jakarta Taglibs。如果你要用到一個標記,先看看是不是已經有現成的可以使用。
不要“重新發明輪子”,不要一切從頭開始: 通過定製組件可以提高複用性,不過定製組件仍然需要編寫、測試和偵錯工具。問題是這個事情別人可能已經實現了,而且你的實現方式並不一定比人家做得更好。這就是JSP標準標記庫(JavaServer Pages Standard Tag Library, JSTL)要做的事情(JSTL請參考JSTL官方網站)。JSTL提供了迴圈、讀屬性、遍曆各種資料結構、條件運算式求值等各種標記。它也提供了一些複雜的標記,甚至像解析XML文檔的標記它都有。所以如果你要用到一個標記的話,最好先看看有沒有別人已經實現的可以使用,而不要次次從頭開始,自己搞一套。
使用JSTL表達使語言(JSTL Expression Language): 傳遞給JSP頁面的資料一般通過JSP範圍屬性或者請求參數來進行。專門為網頁開發人員設計的運算式語言(Expression Language, EL)把使用範圍屬性傳遞資訊作為從商務邏輯向JSP頁面傳遞資訊的標準方式。這裡要注意的是,EL只是JSP技術中關鍵的一個方面,並不是一種通用的程式設計語言。相反,它只是一種資料訪問語言,它可以簡化應用程式的資料的訪問,不用Scriptlet和請求時運算式求值就可以訪問資料。
在JSP中,網頁設計師要使用運算式文法<%= name %>或JavaBean組件來取得某些變數或屬性的值,例如:
<tagLib:tag attribute="<%=
pageContext.getAttribute("name") %>">
或
<%= aCustomerBean.getAddress().getCountry() %>
表達使語言讓網頁設計師可以使用簡化的文法來訪問資訊。如果你只是要訪問一個簡單的變數,你可以使用這樣的文法:
<tagLib:tag attribute="${name}">
如果你要訪問一個嵌套JavaBean的屬性,你可以這樣:
<tagLib:tag attribute ="${
aCustomerBean.address.country}">
運算式語言(EL)借用了JavaScript 的文法,所以如果你對JavaScript 很熟悉的話,你就會覺得巨爽。
使用過濾器(filter): 過濾器是一個對象,可以傳輸請求或修改響應。它可以在請求到達Servlet/JSP之前對其進行預先處理,而且能夠在響應離開Servlet/JSP之後對其進行後處理。所以如果你有幾個Servlet/JSP需要執行同樣的資料轉換或頁面處理的話,你就可以寫一個過濾器類,然後在部署描述檔案(web.xml)中把該過濾器與對應的Servlet/JSP聯絡起來。
建立過濾器其實很容易,你只須實現javax.servlet.Filter介面及它的三個方法:
public void init(FilterConfig config)
public void doFilter(ServletRequest req, ServletResponse rep,
FilterChain chain)
public void destroy()
這樣,你就可以完成你的過濾器。
使用可移植的安全模型: 大部分的應用伺服器都提供了安全模型,不過一般它們都是針對某一個伺服器或某一個廠商專有的。如果你的應用需要移植的話,那麼你的應用最好使用可以移植的安全模型。如果你的應用有一些預先定義的固定使用者的話,那麼你可以使用FROM驗證和BASIC驗證。可是如果你要動態產生客戶的話(一般都是這種情況),你可能就需要使用伺服器特定的API來建立和系統管理使用者。這樣當你的應用移植到另外一個伺服器時,你可能就會碰到API不相容的問題。這種情況下,最好的解決方案是使用適配器(Adapter)模式(如果你對設計模式不熟悉的話,請參看GoF的《設計模式》一書)。
用資料庫來儲存持久性資料: Servlet/JSP中可以使用HttpSession對象也就是會話對象來儲存使用者的臨時資料。不過如果你想儲存持久性資料的時候,你應該使用資料庫,資料儲存資料會更安全,而且對客戶所用的瀏覽器沒有什麼要求。這樣即使你的應用伺服器由於某種原因崩潰了,你的資料依然良好。
快取頁面: 應用程式中總有一些東西是相對固定的,而另外一些東西是經常變化的。你應該使用靜態HTML文檔來儲存那些相對固定的內容,這樣用戶端就可以進行快取,客戶每次訪問你的應用時,只需訪問已經改動的部分。這樣可以加快客戶的訪問速度。
使用串連池: 如果你要自己寫資料庫存取碼的話,我覺得使用你應該學會如何使用資料庫連接池技術。每一個伺服器都有針對資料庫連接池的配置文檔,你要學習一下如何使用。資料庫連接池可以加速你的應用的資料訪問的速度,而且由於伺服器替你管理了資料庫連接,這可以節省你的很多工作。
快取資料庫的訪問結果: 如果你的應用要對資料庫進行頻繁訪問的話,你可以使用一個對象來緩衝你的資料,這樣你就可以節省大量訪問資料庫的開銷。在《J2EE核心模式》和《實用J2EE設計模式編程指南》兩本書中都有關於值對象模式(Value Object Pattern)的詳細探討,你可以參考這兩本書來獲得相應的知識。
使用Data Access Objects模式:如果你的應用需要訪問多個資料庫系統或者可能會移植到其它的儲存系統中,那麼你針對特定廠商的最佳化代碼就可能會失效。使用通用的代碼存在執行效率的問題,而使用最佳化代碼又存在移植的問題。所以就產生了Data Access Objects模式(Data Access Object Pattern, DAO),該模式既提供了各資料庫廠商的適應性,又能利用到他們提供的獨特的好處。按照物件導向的分離任務的原則,該模式將與公司資訊系統(Enterprise Information System, EIS)通訊需要的邏輯隔離到它自己的類中。這樣,事物對象,如Servlet/JSP組件、JavaBean就可以利用Data Access Objects(DAO)處理所有與EIS有關的事務。
最好採用JSP的XML文法: JSP技術中經常存在著兩種完成同一個任務的文法,一種是常規的JSP文法,一種是對應的XML文法。雖然兩種文法作用相同,你最好還是使用XML文法。存在兩種文法的原因是,JSP文法可以與以前的代碼相容,而J2EE使用XML作為其交換資料的核心,所以同時提供了XML文法。隨著J2EE的發展,XML的作用會越來越大,所以我建議你使用XML文法。
研究Sun提供的J2EE BluePrints: Sun的Enterprise BluePrints 提供了大量指導原則、設計模式和很好的例子(寵物店,Pet Store)。你可以好好研究一下這些內容,這樣可以提高你的設計和開發水平。
整合Servlet和JSP
JSP技術規範種給出了兩種使用JSP開發Web應用的方式,這兩種方式可以歸納為模型一和模型二,這兩種模型的主要差別在於它們處理業務的流程不同。模型一,如下圖所示,稱之為JSP+JavaBeans模型。在這一模型中,JSP頁面獨自響應請求並將處理結果返回給客戶,所有的資料通過JavaBean來處理,JSP實現頁面的表現。
screen.width-333)this.width=screen.width-333;">
圖2: JSP模型一
從上圖可以看出,模型一也實現了頁面表現和商務邏輯相分離。然而使用這種方式就要在JSP頁面使用大量的Java代碼,當需要處理的商務邏輯很複雜時,這種情況會變得非常糟糕。大量嵌入式代碼使整個頁面程式變得異常複雜。對於前端介面設計的網頁開發人員來說,這簡直是一場噩夢。所以,模型一不能滿足大型應用的需要,但是對於小型應用,因為該模型簡單,不用涉及諸多要素,從而可以很好地滿足小型應用的需要,所以在簡單應用中,可以考慮模型一。
模型二,如下圖所示,稱之為JSP+Servlet+JavaBeans模型。這一模型結合了JSP和Servlet技術,充分利用了JSP和Servlet兩種技術原有的優勢。這個模型使用JSP技術來表現頁面,使用Servlet技術完成大量的交易處理,使用Bean來儲存資料。Servlet用來處理請求的事務,充當一個控制者的角色,並負責向客戶發送請求。它建立JSP需要的Bean和對象,然後根據使用者請求的行為,決定將哪個JSP頁面發送給客戶。
screen.width-333)this.width=screen.width-333;">
圖3: JSP模型二
從開發的觀點看,模型二具有更清晰的頁面表現,清楚的開發角色的劃分,可以充分利用Team Dev中的網頁設計人員和Java開發人員。這些優勢在大型項目中表現得尤為突出,網頁設計人員可以充分發揮自己的美術和設計才能來充分表現頁面,程式編寫人員可以充分發揮自己的商務邏輯處理思維,實現項目中的業務處理。
另外,從設計結構來看,這種模型充分體現了模型視圖控制器(MVC)的設計架構。事實上,現存的很多開發架構都是基於這種模型的,充分實現了MVC ,例如Apache Struts架構和JavaServer Faces架構