JSP技術(shù)優(yōu)缺點(diǎn)深入分析
作為一名資深的 Java 技術(shù)專家和 Enhydra 支持者,本文作者強(qiáng)烈建議開(kāi)發(fā)人員在選擇 Web 應(yīng)用程序編程語(yǔ)言時(shí),使用其他可以替代 JavaServer Pages (JSP) servlets 的技術(shù)。JSP 技術(shù)是Sun 的J2EE 平臺(tái)和編程模型的一部分,用于解決將單調(diào)的內(nèi)容轉(zhuǎn)換為外觀優(yōu)美的表示層時(shí)遇到的困難。事實(shí)上,并非所有的Web開(kāi)發(fā)人員都對(duì)JSP 技術(shù)很滿意。由于 Sun 技術(shù)出現(xiàn)了很多不同的版本,您可以從眾多表示技術(shù)中選擇一種替代技術(shù)。本文將深入查看JSP代碼并介紹一些有吸引力的替代選擇。
表示技術(shù)專門(mén)用于將單調(diào)粗糙的Web 內(nèi)容轉(zhuǎn)換成帶有漂亮的表示層的內(nèi)容。JavaServer Pages (JSP) 技術(shù)是 Sun 的表示模型,并且是 J2EE 平臺(tái)的一部分,它獲得了極大的關(guān)注。使用 JSP 技術(shù)有優(yōu)點(diǎn)也有缺點(diǎn)。Web 開(kāi)發(fā)人員應(yīng)該了解這些優(yōu)缺點(diǎn),并且知道還有其他代替技術(shù)。實(shí)際上,現(xiàn)在有很多可供選擇的表示技術(shù)。本文先介紹表示技術(shù)要解決哪些問(wèn)題,然后考察 JSP 模型特有的優(yōu)缺點(diǎn)。最后,將介紹一些其他表示技術(shù),它們可以代替 Sun 表示技術(shù)。
歷史背景
在深入介紹表示技術(shù)之前,有必要了解一下該技術(shù)產(chǎn)生的時(shí)代背景。就在10 年前,瘦客戶機(jī)還是個(gè)新鮮事物。我們?nèi)匀惶幱谧烂鎽?yīng)用程序的時(shí)代,使用功能有限的 286 微處理器和現(xiàn)在看來(lái)不屑一顧的 14 寸顯示器。時(shí)代變了!現(xiàn)在我的臺(tái)式機(jī)只需要運(yùn)行一個(gè) Web 瀏覽器,服務(wù)器由 Sun、IBM、HP、Compaq 提供,計(jì)算、業(yè)務(wù)邏輯和內(nèi)容則又由其他公司提供。那么顯示器呢?現(xiàn)在我們使用的是 21 寸到 25 寸不等、等離子寬屏顯示器。這樣我們就可以看到復(fù)雜的 HTML 表示,它們充當(dāng)這些強(qiáng)大的應(yīng)用程序的前端。以前的單調(diào)界面已經(jīng)無(wú)法滿足需要;我們現(xiàn)在需要使用華麗的圖形、可以移動(dòng)的圖像、色彩協(xié)調(diào)的表示,并且要求它能夠加快呈現(xiàn)速度。
前提條件
如今,在羽毛漸豐的 Windows 應(yīng)用程序經(jīng)過(guò)十年的發(fā)展之后,我們還處在表示模式的巨大轉(zhuǎn)型之中。Visual Basic 和 C 程序員發(fā)現(xiàn)他們?nèi)匀辉谑褂煤蠖讼到y(tǒng)或單調(diào)的 Windows 應(yīng)用程序,或是在工具箱中加入了一種具有 Web 能力的語(yǔ)言,例如 Java 語(yǔ)言。如果一個(gè)應(yīng)用程序無(wú)法支持至少 3 到 4 種 ML 式語(yǔ)言(例如 HTML、XML 和 WML),即使不是徹底失敗,也會(huì)被認(rèn)為是很糟糕的。當(dāng)然,這就表示我們非常重視能輕松開(kāi)發(fā) Web 表示層的能力。
事實(shí)證明,使用新的 Internet 以及所有可用的語(yǔ)言(Java、C、Perl、Pascal 和 Ada 等)并不像我們希望的那樣簡(jiǎn)單。在后端系統(tǒng)使用編程語(yǔ)言并利用它們生成適合客戶機(jī)的標(biāo)記語(yǔ)言時(shí),出現(xiàn)了大量問(wèn)題。隨著瀏覽器端的選擇越來(lái)越多(例如 DHTML 和 JavaScript 編碼),Web 領(lǐng)域迫切需要圖形設(shè)計(jì)知識(shí),以及可以使用標(biāo)準(zhǔn) HTML 創(chuàng)建復(fù)雜界面的工具。但開(kāi)發(fā)應(yīng)用程序前端的能力無(wú)法跟上這些需求的步伐。此時(shí),表示技術(shù) 應(yīng)運(yùn)而生。
表示技術(shù)的專門(mén)任務(wù)是:將內(nèi)容(即沒(méi)有包含表示細(xì)節(jié)的數(shù)據(jù))轉(zhuǎn)換為表示,也就是您在手機(jī)、PalmPilot 或 Web 瀏覽器看到的各種用戶界面。這些表示技術(shù)要解決哪些問(wèn)題?讓我們來(lái)了解一下。
分離和集成
表示技術(shù)的主要目的是允許分離內(nèi)容和表示。換而言之,業(yè)務(wù)邏輯單元(假設(shè) C 或 Java 等編程語(yǔ)言)不需要使用特定于表示的方式生成數(shù)據(jù)。數(shù)據(jù)或內(nèi)容,按照原始格式返回,沒(méi)有進(jìn)行格式化。表示技術(shù)隨后對(duì)內(nèi)容應(yīng)用格式化或進(jìn)行表示。最終的結(jié)果是各種數(shù)據(jù)被圖形、格式、色彩和徽標(biāo)所包圍。
查看清單 1 和清單 2 中的示例,了解一下原始內(nèi)容和應(yīng)用了表示技術(shù)的內(nèi)容之間的差異。
清單1:展示了原始的內(nèi)容,全部都是數(shù)據(jù),可以按照任何方式使用。
Russell Crowe Tom Hanks Meg Ryan Mary Stuart Masterson Alec Baldwin Ashley Judd Keanu Reeves |
清單2:要比清單 1 更加復(fù)雜,使用表示技術(shù)對(duì)相同的數(shù)據(jù)進(jìn)行了裝飾,并可以立即表示在支持 HTML 的瀏覽器中。
﹤HTML﹥ ﹤HEAD﹥ ﹤TITLE﹥Search Results: Actors﹤/TITLE﹥ ﹤/HEAD﹥ ﹤BODY﹥ ﹤H2 ALIGN="center"﹥Search Results: Actors﹤/H2﹥ ﹤CENTER﹥ ﹤HR width="85%"﹥ ﹤TABLE width="50%" CELLPADDING="3" CELLSPACING="3" border="1" BGCOLOR="#FFFFCC"﹥ ﹤TR BGCOLOR="#FFCCCC"﹥ ﹤TH width="50%" ALIGN="center"﹥Last Name﹤/TH﹥ ﹤TH width="50%" ALIGN="center"﹥First Name﹤/TH﹥ ﹤/TR﹥ ﹤TR﹥ ﹤TD width="50%"﹥Baldwin﹤/TD﹥ ﹤TD width="50%"﹥Alec﹤/TD﹥ ﹤/TR﹥ ﹤TR﹥ ﹤TD width="50%"﹥Crowe﹤/TD﹥ ﹤TD width="50%"﹥Russell﹤/TD﹥ ﹤/TR﹥ ﹤TR﹥ ﹤TD width="50%"﹥Hanks﹤/TD﹥ ﹤TD width="50%"﹥Tom﹤/TD﹥ ﹤/TR﹥ ﹤TR﹥ ﹤TD width="50%"﹥Judd﹤/TD﹥ ﹤TD width="50%"﹥Ashley﹤/TD﹥ ﹤/TR﹥ ﹤TR﹥ ﹤TD width="50%"﹥Masterson﹤/TD﹥ ﹤TD width="50%"﹥Mary Stuart﹤/TD﹥ ﹤/TR﹥ ﹤TR﹥ ﹤TD width="50%"﹥Reeves﹤/TD﹥ ﹤TD width="50%"﹥Keanu﹤/TD﹥ ﹤/TR﹥ ﹤TR﹥ ﹤TD width="50%"﹥Ryan﹤/TD﹥ ﹤TD width="50%"﹥Meg﹤/TD﹥ ﹤/TR﹥ ﹤/TABLE﹥ ﹤/CENTER﹥ ﹤/BODY﹥ ﹤/HTML﹥ |
可以看到,清單 1 中的內(nèi)容更清晰,非專業(yè)人員更加容易使用和理解,而清單 2 中的內(nèi)容特定于瀏覽器表示。很難從中提取數(shù)據(jù)或?qū)?shù)據(jù)用作其他用途。#p#
這個(gè)基本的區(qū)別,即分離表示和內(nèi)容而不是集成它們(至少在用戶需要使用信息時(shí)),是任何表示技術(shù)前提,包括 JSP 技術(shù)。此外,任何無(wú)法實(shí)現(xiàn)這個(gè)基本目標(biāo)的表示技術(shù)都不能真正體現(xiàn)創(chuàng)建的初衷。
工作和重復(fù)工作
除了分離表示和內(nèi)容外,另一個(gè)衡量表示技術(shù)的可用性的指標(biāo)是:能夠消除多少重復(fù)的工作。表示和內(nèi)容的分離也促使內(nèi)容開(kāi)發(fā)人員之間的角色分離。程序員可以關(guān)注上例所示的原始內(nèi)容,而圖形設(shè)計(jì)師或網(wǎng)絡(luò)管理員則關(guān)注表示。然而,在獲得圖形設(shè)計(jì)師設(shè)計(jì)的表示(或標(biāo)記)并將它應(yīng)用到程序員代碼提供的內(nèi)容中時(shí),角色之間仍然有一定重復(fù)。
在最簡(jiǎn)單的情況下,設(shè)計(jì)師提供標(biāo)記,而開(kāi)發(fā)人員提供代碼并把標(biāo)記插入到表示技術(shù)中。應(yīng)用程序被 “啟動(dòng)”,內(nèi)容魔術(shù)般地變成了用戶界面。當(dāng)然,我們都知道,開(kāi)發(fā)遠(yuǎn)遠(yuǎn)沒(méi)有結(jié)束。接下來(lái)要重新修訂版本、修改界面,還必須添加新的業(yè)務(wù)規(guī)則。這能真正考驗(yàn)表示技術(shù)的靈活性。雖然很容易更新插入到表示層的原始內(nèi)容,但是圖形設(shè)計(jì)師很少能夠輕松地編輯他們的初始工作。經(jīng)常要修改表示層(我們常常按照銷售部門(mén)的 “指使” 進(jìn)行修改)。因此,問(wèn)題產(chǎn)生了:設(shè)計(jì)師要修改哪些內(nèi)容來(lái)調(diào)整他們的工作?是他們提供給開(kāi)發(fā)人員的原始標(biāo)記語(yǔ)言頁(yè)面嗎?也許不是,因?yàn)檫@個(gè)頁(yè)面很可能插入了自定義標(biāo)記或代碼(JSP 頁(yè)面、模板引擎),被轉(zhuǎn)換為一個(gè) Java servlet,或修改為完全無(wú)法識(shí)別的內(nèi)容。
設(shè)計(jì)師通常需要重新設(shè)計(jì)頁(yè)面并重新將其提交給開(kāi)發(fā)人員。然后再由開(kāi)發(fā)人員將頁(yè)面重新轉(zhuǎn)換為特定的格式,以供表示技術(shù)使用。或者,設(shè)計(jì)師必須學(xué)習(xí)一種腳本編制語(yǔ)言,或至少知道開(kāi)發(fā)人員提供的頁(yè)面源代碼中哪部分是違規(guī)的。當(dāng)然,這種方法容易出錯(cuò),并且使用起來(lái)不安全。當(dāng)您了解到某種表示技術(shù)允許清晰地分離內(nèi)容和表示后,您應(yīng)該確保將修改表示層所需的重復(fù)工作減至最小。
JSP 技術(shù)的承諾
現(xiàn)在,讓我們具體看一下 JSP 編碼。JSP 技術(shù)承諾為設(shè)計(jì)師和開(kāi)發(fā)人員提供他們所需的惟一表示技術(shù)。JSP 技術(shù)是 J2EE 平臺(tái)的一部分,這充分展示了 Sun 為其 Java 產(chǎn)品提供的強(qiáng)大支持。為了使您了解這個(gè)解決方案的流行程度,請(qǐng)嘗試在 amazon.com 中搜索一下 ‘JSP’;您將發(fā)現(xiàn)大量與 JSP 技術(shù)有關(guān)的書(shū)籍,它會(huì)遠(yuǎn)遠(yuǎn)超過(guò)任何單獨(dú)一種 Java API.在詳細(xì)探討 JSP 技術(shù)引發(fā)的具體問(wèn)題之前,您應(yīng)該清楚地了解這種技術(shù)的承諾。
內(nèi)容和表示
首先,JSP 技術(shù)與內(nèi)容和表示的分離有關(guān),是 Sun 發(fā)布的有關(guān) JSP 頁(yè)面的最主要目標(biāo)。實(shí)際上,一些代碼開(kāi)發(fā)人員抱怨將 out.println("﹤HTML﹥﹤HEAD﹥﹤TITLE﹥" + pageInfo.getTitle() + "﹤/TITLE﹥﹤/HEAD﹥"); 鍵入到 servlet,這直接導(dǎo)致了 JSP 的設(shè)計(jì)。在硬編碼內(nèi)容中混入運(yùn)行時(shí)變量加重了 servlet 開(kāi)發(fā)人員的負(fù)擔(dān),并且使開(kāi)發(fā)人員更加難對(duì)表示層進(jìn)行修改,即使非常小的修改也是如此。
JSP 技術(shù)解決了這個(gè)問(wèn)題,它允許在運(yùn)行時(shí)將普通的 HTML 頁(yè)面(后來(lái)還包括 WHM 或其他標(biāo)記語(yǔ)言)編譯到 Java servlet 中,實(shí)際上效仿了 out.println() 范例,而不需要開(kāi)發(fā)人員編寫(xiě)代碼。它允許您將變量插入到在運(yùn)行時(shí)才進(jìn)行解釋的頁(yè)面。
在一個(gè) JSP 頁(yè)面中,清單 2 所示的 HTML 片段應(yīng)該類似清單 3 中的示例。
﹤%@ page import="com.ibm.display.PageUtils" %﹥ ﹤%@ page import="com.ibm.display.PageInfo" %﹥ ﹤% PageInfo pageInfo = (PageInfo)session.getAttribute("PAGE_DATA") %﹥ ﹤HTML﹥ ﹤HEAD﹥ ﹤TITLE﹥ ﹤%=pageInfo.getTitle()%﹥ ﹤/TITLE﹥ ﹤/HEAD﹥ ﹤BODY﹥ ﹤!-- Other HTML content --﹥ ﹤/BODY﹥ ﹤/HTML﹥ |
根據(jù)最初的原則判斷,JSP 技術(shù)(至少在其說(shuō)明的設(shè)計(jì)中)可以滿足表示技術(shù)的基本原則,正如上面概況的一樣:內(nèi)容與表示分離。
代碼和標(biāo)記
JSP 技術(shù)特性列表上的第二項(xiàng)可能會(huì)出現(xiàn)一些問(wèn)題。JSP 代碼可以讓您將 Java 代碼直接插入到標(biāo)記頁(yè)面。在開(kāi)發(fā) JSP 規(guī)范時(shí),Microsoft Active Server Pages (ASP) 大獲成功,因此 Sun 與 Microsoft 之間的競(jìng)爭(zhēng)空前激烈。這導(dǎo)致了這個(gè)決策的產(chǎn)生。JavaServer Pages 的名稱與 Active Server Pages 類似并非偶然。并且對(duì)眾多 API 特性的模仿也是蓄意而為。因此 JSP 創(chuàng)建者需要能夠?qū)?Java 代碼添加到他們的標(biāo)記中。
為了演示將 Java 代碼加入到標(biāo)記中,清單 4 中的 JSP 代碼片段根據(jù)需要?jiǎng)討B(tài)地添加行,以表示 actors 的 Vector 中的每一項(xiàng)。
﹤%@ page import="com.ibm.display.PageUtils" %﹥ ﹤%@ page import="com.ibm.display.PageInfo" %﹥ ﹤%@ page import="com.ibm.people.Actor" %﹥ ﹤%@ page import="java.util.Iterator" %﹥ ﹤%@ page import="java.util.Vector" %﹥ ﹤% PageInfo pageInfo = (PageInfo)session.getAttribute("PAGE_DATA") Vector actors = pageInfo.getActors() %﹥ ﹤HTML﹥ ﹤HEAD﹥ ﹤TITLE﹥ ﹤%=pageInfo.getTitle()%﹥ ﹤/TITLE﹥ ﹤/HEAD﹥ ﹤BODY﹥ ﹤H2 ALIGN="center"﹥Search Results: Actors﹤/H2﹥ ﹤CENTER﹥ ﹤HR width="85%"﹥ ﹤TABLE width="50%" CELLPADDING="3" CELLSPACING="3" border="1" bgcolor="#FFFFCC"﹥ ﹤% for (Iterator i = actors.iterator(); i.hasNext()) { Actor actor = (Actor)i.next(); %﹥ ﹤TR BGCOLOR="#FFCCCC"﹥ ﹤TH width="50%" ALIGN="center"﹥ ﹤%=actor.getLastName()%﹥ ﹤/TH﹥ ﹤TH width="50%" ALIGN="center"﹥ ﹤%=actor.getFirstName()%﹥ ﹤/TH﹥ ﹤/TR﹥ ﹤% } %﹥ ﹤/TABLE﹥ ﹤/CENTER﹥ ﹤/BODY﹥ ﹤/HTML﹥ |
注意,目前為止,我僅僅介紹了 JSP 技術(shù)的最初設(shè)計(jì)目標(biāo);在下一節(jié)介紹 JSP 技術(shù)存在的問(wèn)題之后,我將對(duì)這個(gè)目標(biāo)作出自己的論斷。不過(guò),您可能已經(jīng)開(kāi)始有點(diǎn)好奇,因?yàn)閷⒋a嵌入到 JSP 頁(yè)面中似乎與 JSP 技術(shù)的首要目標(biāo)(分離內(nèi)容和表示)有所沖突。實(shí)際上,我還沒(méi)有就此展開(kāi)論述。
設(shè)計(jì)師和開(kāi)發(fā)人員
JSP 技術(shù)的最終(也是值得稱贊)的目標(biāo)是,它嘗試在應(yīng)用程序開(kāi)發(fā)過(guò)程中形成清晰定義的角色。通過(guò)在表面上分離內(nèi)容和表示,JSP 技術(shù)能夠更加清晰地區(qū)分設(shè)計(jì)師和開(kāi)發(fā)人員角色。設(shè)計(jì)師使用標(biāo)準(zhǔn)的 HTML、WML 或其他合適的語(yǔ)言創(chuàng)建標(biāo)記,而開(kāi)發(fā)人員編寫(xiě)代碼。當(dāng)然,如今很多設(shè)計(jì)師學(xué)習(xí)了 JavaScript 語(yǔ)言,因此,這些設(shè)計(jì)師開(kāi)始學(xué)習(xí) JSP 編碼也不是什么令人吃驚的事情。通常,設(shè)計(jì)師并不會(huì)單純地創(chuàng)建純標(biāo)記,他們會(huì)編寫(xiě)一個(gè)完整的 JSP 頁(yè)面并將其交給開(kāi)發(fā)人員。然后經(jīng)過(guò)頻繁的修改,開(kāi)發(fā)人員再將 JSP 頁(yè)面作為完整應(yīng)用程序的前端使用。但是,這里的關(guān)鍵問(wèn)題是仍然有很多設(shè)計(jì)師沒(méi)有 學(xué)習(xí) JSP 編碼,他們也必須能夠在這種環(huán)境下工作。
出現(xiàn)的問(wèn)題
我剛剛介紹了一種良好的表示技術(shù)應(yīng)該提供的功能,以及 JSP 技術(shù)嘗試解決的具體問(wèn)題。現(xiàn)在,我將轉(zhuǎn)入正題:JSP 技術(shù)雖然建立在良好理念的基礎(chǔ)之上,但是卻出現(xiàn)了一些問(wèn)題。在選擇 JSP 編寫(xiě)您的應(yīng)用程序之前(您可能仍然會(huì)這樣做),至少應(yīng)該注意一些容易出現(xiàn)的問(wèn)題。
您還需要注意經(jīng)常被忽略的 J2EE 編程平臺(tái):僅僅因?yàn)槠脚_(tái)附帶了 API 并不意味著一定要使用它。和這種想法同樣可笑的是,很多開(kāi)發(fā)人員在使用 JSP、EJB 或 JMS API 時(shí),都在想如果不使用這些 API 的話,他們的應(yīng)用程序就不是真正的 “J2EE 應(yīng)用程序” 了。實(shí)際上,平臺(tái)提供的 API 遠(yuǎn)遠(yuǎn)超過(guò)大多數(shù)應(yīng)用程序的需要。如果您不能使用或?qū)?JSP 技術(shù)還持有懷疑態(tài)度,那么可以不使用它!在選擇 JSP 編寫(xiě)應(yīng)用程序之前,仔細(xì)研究它的優(yōu)點(diǎn)和 缺點(diǎn)。讓我們看看其中一些缺點(diǎn)。#p#
可移植性和語(yǔ)言鎖定
JSP 技術(shù)將您鎖定到某種特定的語(yǔ)言。這一點(diǎn)不應(yīng)該給予太多的關(guān)注。至少在我看來(lái),Java 技術(shù)是企業(yè)應(yīng)用程序的惟一 選擇。在這個(gè)領(lǐng)域,根本不存在可以獨(dú)立于語(yǔ)言的解決方案。當(dāng)然,在這個(gè)時(shí)候,我沒(méi)有把 Microsoft .NET 平臺(tái)牽涉進(jìn)來(lái)。只有時(shí)間可以告訴我們這個(gè)平臺(tái)是否可以真正獨(dú)立于語(yǔ)言(我很懷疑這一點(diǎn))。
然而,選擇 JSP 技術(shù)將強(qiáng)制您使用 Java 語(yǔ)言,至少對(duì)于內(nèi)容和表示是這樣的。盡管 CORBA 可以用于業(yè)務(wù)邏輯,JSP 編碼要求必須熟悉 servlet 和核心 Java 語(yǔ)言。因?yàn)楹芏嚅_(kāi)發(fā)人員通過(guò) J2EE 平臺(tái)接觸 JSP 編碼,因此這通常算不成問(wèn)題。
混合和獨(dú)立
在本篇文章中,我始終圍繞分離內(nèi)容和表示這一概念。您可能對(duì)此已經(jīng)感到不耐煩,那么現(xiàn)在讓我們看看 JSP 究竟能不能實(shí)現(xiàn)這個(gè)目標(biāo)。正如我們之前討論的一樣,JSP 宣稱 一直致力于實(shí)現(xiàn)內(nèi)容和表示分離,那么我們可以因此認(rèn)為它實(shí)現(xiàn)了目標(biāo),是嗎?未必如此。
內(nèi)容和表示之間的界限變得模糊
JSP 允許將 Java 代碼插入到標(biāo)記語(yǔ)言頁(yè)面中,這個(gè)非常危險(xiǎn)的特性允許將內(nèi)容混合到表示中。更糟糕的是,業(yè)務(wù)邏輯通常會(huì)進(jìn)入到 JSP 頁(yè)面中,如清單 5 所示。
﹤%@ page import="com.ibm.display.PageUtils" %﹥ ﹤%@ page import="com.ibm.display.PageInfo" %﹥ ﹤%@ page import="com.ibm.logic.AdminUtils" %﹥ ﹤%@ page import="com.ibm.people.Actor" %﹥ ﹤%@ page import="java.util.Iterator" %﹥ ﹤%@ page import="java.util.Vector" %﹥ ﹤% PageInfo pageInfo = (PageInfo)session.getAttribute("PAGE_DATA") %﹥ ﹤HTML﹥ ﹤HEAD﹥ ﹤TITLE﹥ ﹤%=pageInfo.getTitle()%﹥ ﹤/TITLE﹥ ﹤/HEAD﹥ ﹤BODY﹥ ﹤H2 ALIGN="center"﹥Search Results: Actors﹤/H2﹥ ﹤CENTER﹥ ﹤HR width="85%"﹥ ﹤TABLE width="50%" CELLPADDING="3" CELLSPACING="3" border="1" BGCOLOR="#FFFFCC"﹥ ﹤% // Based on user's permissions, perform search differently (business logic!) Vector actors = pageInfo.getActors() if (pageInfo.getUserInfo().hasPermission("ADMINISTRATOR")) { actors = AdminUtils.getActors(pageInfo.getSearchCriteria()); } else { actors = pageInfo.getActors(); } for (Iterator i = actors.iterator(); i.hasNext()) { Actor actor = (Actor)i.next(); %﹥ ﹤TR BGCOLOR="#FFCCCC"﹥ ﹤TH width="50%" ALIGN="center"﹥ ﹤%=actor.getLastName()%﹥ ﹤/TH﹥ ﹤TH width="50%" ALIGN="center"﹥ ﹤%=actor.getFirstName()%﹥ ﹤/TH﹥ ﹤/TR﹥ ﹤% } %﹥ ﹤/TABLE﹥ ﹤/CENTER﹥ ﹤/BODY﹥ ﹤/HTML﹥ |
JSP 的擁護(hù)者會(huì)很快告訴您 JSP 標(biāo)記庫(kù) 可以幫助您避免這個(gè)問(wèn)題。標(biāo)記庫(kù)允許將自定義標(biāo)記(例如 ﹤AUTHORS /﹥)添加到 JSP 頁(yè)面,然后在運(yùn)行時(shí)在標(biāo)記庫(kù)內(nèi)將其解析為代碼片段。
使用自定義標(biāo)記和相關(guān)的標(biāo)記庫(kù)允許把以上示例轉(zhuǎn)換為清單 6 所示的內(nèi)容。
﹤CENTER﹥ ﹤TABLE width="50%" CELLPADDING="3" CELLSPACING="3" border="1" BGCOLOR="#FFFFCC"﹥ ﹤ACTORS /﹥ ﹤/TABLE﹥ ﹤/CENTER﹥ |
在運(yùn)行時(shí),將執(zhí)行標(biāo)記的代碼并把正確的結(jié)果插入到頁(yè)面中。但是這并沒(méi)有解決問(wèn)題。反對(duì) JSP 技術(shù)的理由并不在于能否 分離內(nèi)容和表示,而是在于是否必須 分離。只要 JSP 編碼允許內(nèi)聯(lián)編碼,那么就可以很方便地對(duì)內(nèi)聯(lián)代碼進(jìn)行最后的修改(特別是逼近最后期限時(shí)),而不是將代碼轉(zhuǎn)換為一個(gè)標(biāo)記庫(kù)。如果這不是真的,那么 Java 語(yǔ)言為何會(huì)馬上比 C 和 C++ 更流行:Java 禁用了 C 中大量有問(wèn)題的特性,例如指針相加。雖然您可以總是強(qiáng)調(diào)您不需要 在 C 中執(zhí)行指針相加,或者優(yōu)秀的程序員將插入代碼 scriptlet,我們都知道實(shí)際會(huì)發(fā)生什么。Java 語(yǔ)言是一種更好的選擇,因?yàn)樗鼑?yán)禁 使用這些不好的習(xí)慣。但是 JSP 在這方面更類似于 C,允許實(shí)現(xiàn)一些非常糟糕的實(shí)踐。
檢驗(yàn) JSP 技術(shù)是否成功達(dá)到其所述目標(biāo)的另一種方法是看它能否在實(shí)踐中實(shí)現(xiàn)這個(gè)目標(biāo);顯然,如果認(rèn)為 JSP 無(wú)法實(shí)際實(shí)現(xiàn)目標(biāo),這是不公平的。大多數(shù)模板引擎,比如 FreeMarker 和 WebMacro,都提供了相同的內(nèi)聯(lián)編碼功能,通常附帶了一種類似 Perl 的語(yǔ)言。然而,諸如 Enhydra 的 XMLC 這樣的技術(shù)不 允許進(jìn)行這種類型的編碼。相反,這些技術(shù)將一個(gè)純標(biāo)記語(yǔ)言頁(yè)面作為輸入,然后生成 Java 方法。這實(shí)際上改變了編程流程;應(yīng)用程序并不像 JSP 技術(shù)那樣使用頁(yè)面從應(yīng)用程序調(diào)用邏輯,而是使用方法影響頁(yè)面的值(Enhydra)。以 Enhydra 為例,使用 XMLC 將頁(yè)面轉(zhuǎn)換為一個(gè) DOM 樹(shù),然后使用 DOM 的 HTML 綁定更新頁(yè)面中的 “字段”(有關(guān) Enhydra XMLC 的更多信息,請(qǐng)查閱 參考資料)。
這里的重點(diǎn)是,JSP 技術(shù)實(shí)現(xiàn)目標(biāo)的能力遠(yuǎn)遠(yuǎn)超過(guò) XMLC,例如,僅僅是允許標(biāo)記庫(kù)這一項(xiàng)就比 XMLC 強(qiáng)很多。但是 Sun 規(guī)范總體趨向于始終維護(hù)向后兼容性,或至少在相當(dāng)長(zhǎng)的一段時(shí)間內(nèi)維護(hù)向后兼容性。JSP 規(guī)范的當(dāng)前版本為 1.1,它允許使用 scriptlets,因此在未來(lái)幾年內(nèi) JSP 頁(yè)面內(nèi)都會(huì)支持這個(gè)特性。在深入探究 JSP 編碼之前,請(qǐng)注意,在其強(qiáng)調(diào)的完全分離內(nèi)容和表示的理念和實(shí)際實(shí)現(xiàn)之間存在一個(gè)很大的缺口,它充其量只是假裝分離了用戶界面和驅(qū)動(dòng)應(yīng)用程序的代碼。
單處理和多任務(wù)處理
如前所述,理想狀態(tài)下,設(shè)計(jì)師應(yīng)該能夠執(zhí)行單獨(dú)處理,只關(guān)注圖形設(shè)計(jì),而開(kāi)發(fā)人員應(yīng)該能夠?qū)⒆⒁饬性诰幊躺稀R虼耍O(shè)計(jì)師可以在將頁(yè)面轉(zhuǎn)換為適合應(yīng)用程序的格式后,再對(duì)其進(jìn)行處理。對(duì)于 JSP 頁(yè)面來(lái)說(shuō),將頁(yè)面轉(zhuǎn)換為適合應(yīng)用程序的格式就是指向頁(yè)面導(dǎo)入 JavaBeans、插入內(nèi)聯(lián)編碼并添加自定義標(biāo)記庫(kù)。問(wèn)題是有些設(shè)計(jì)師使用的是 HTML 編輯器,比如 HoTMetaL、Macromedia Dreamweaver 或 FrontPage,這些編輯器無(wú)法識(shí)別代碼 scriptlets 或標(biāo)記庫(kù),這意味著設(shè)計(jì)師實(shí)際上只收到了頁(yè)面的一部分。想象一下,標(biāo)記庫(kù)或代碼片段只生成了表的若干行,或是頁(yè)面中其他格式化的細(xì)節(jié),這是多么麻煩的事情。設(shè)計(jì)師使用了不兼容的 HTML 編輯器,無(wú)法看到這些元素的外觀。在開(kāi)發(fā)人員完成編碼后,設(shè)計(jì)師不能輕松地對(duì)頁(yè)面進(jìn)行修改,這時(shí),不僅沒(méi)有清晰地劃分角色,JSP 編碼實(shí)際上將這兩種角色合二為一:開(kāi)發(fā)人員必須執(zhí)行多個(gè)任務(wù),必須擔(dān)當(dāng)開(kāi)發(fā)人員、設(shè)計(jì)師以及其他角色。
如果您仍然對(duì)此表示懷疑,那么請(qǐng)下載 J2EE Reference Implementation 并將其中一個(gè)附帶的 JSP 頁(yè)面加載到一個(gè) WYSIWYG HTML 編輯器,例如 Dreamweaver.頁(yè)面立即被一些黃色區(qū)域填充,告訴您頁(yè)面中包含的所有 “錯(cuò)誤” 標(biāo)記。當(dāng)然,黃色內(nèi)容來(lái)自于 JSP 標(biāo)記和代碼,而不是頁(yè)面出現(xiàn)了什么真正的錯(cuò)誤。
迄今為止,尚未出現(xiàn)支持 JSP 功能的 WYSIWYG 編輯器,我也沒(méi)有聽(tīng)說(shuō)過(guò)任何與此相關(guān)的項(xiàng)目。盡管模板引擎也具有相同的問(wèn)題,但是很多基于 Java 的解決方案,例如我最喜歡的 Enhydra,都允許您將標(biāo)記頁(yè)面作為輸入提供給表示技術(shù)。在這種情況下,設(shè)計(jì)師可以根據(jù)需要頻繁地進(jìn)行修改,并重新提供標(biāo)記頁(yè)面。運(yùn)行表示技術(shù)的引擎或編譯程序?qū)?biāo)記頁(yè)面轉(zhuǎn)換為適當(dāng)?shù)母袷剑⑶也恍枰薷娜魏未a(典型情況下)。最終獲得了理想的結(jié)果:設(shè)計(jì)師和開(kāi)發(fā)人員各司其職。
因此,要注意 JSP 技術(shù)作出的承諾和它實(shí)際交付的實(shí)現(xiàn)。在實(shí)際中,要在一個(gè) JSP 技術(shù)驅(qū)動(dòng)的環(huán)境下發(fā)揮功效,必須讓開(kāi)發(fā)人員處理大部分標(biāo)記,或至少讓設(shè)計(jì)師學(xué)習(xí)一些 JSP 編碼。
HTML 和 XML
JSP 技術(shù)最嚴(yán)重的缺陷之一(也是經(jīng)常被忽視的一個(gè)缺陷)就是它與 XML 不兼容。更確切地說(shuō),并且特別針對(duì) HTML 領(lǐng)域,JSP 頁(yè)面不要求具備 XHTML 兼容性。XHTML 是一個(gè) World Wide Web Consortium (W3C) 規(guī)范,目前正在取代 HTML 4.0.XHTML 在實(shí)現(xiàn)格式良好的 XML 文檔方面定義了 HTML 標(biāo)記集。例如,
標(biāo)記必須被轉(zhuǎn)換為
才能確保 XML 兼容性(如果這個(gè)例子沒(méi)有解釋清楚的話,可以查閱 參考資料 列出的 XML 規(guī)范,以及關(guān)于 XHTML 的 developerWorks 文章)。同樣的規(guī)則適用于圖像標(biāo)記,并且在 XHTML 1.1(即將到來(lái))中,大部分字體屬性和其他樣式被移入到 CSS 樣式表中。另外,大多數(shù)標(biāo)準(zhǔn) HTML 文檔可以輕松地轉(zhuǎn)換為 XHTML 1.0,這意味著可以使用任何與 XML 兼容的解析器讀取,例如 Apache Xerces,并且可以作為 XML 進(jìn)行處理。
您會(huì)問(wèn) “這有什么關(guān)系呢?”。答案是關(guān)系重大。因?yàn)?XML 正在快速成為一個(gè)在應(yīng)用程序之間和應(yīng)用程序內(nèi)部進(jìn)行通信的全球標(biāo)準(zhǔn)。使用 XML 格式傳遞書(shū)籍,可以讓任何使用基本 XML 數(shù)據(jù)綁定功能的應(yīng)用程序輕松地使用您的應(yīng)用程序的數(shù)據(jù)。想象一下,通過(guò)將您的數(shù)據(jù)遷移到 XML 格式,您就可以與信用卡公司進(jìn)行網(wǎng)上交易!多數(shù)情況下,您的數(shù)據(jù)表示還需要與其他公司進(jìn)行交互。最常見(jiàn)的情況是門(mén)戶應(yīng)用程序,它接受來(lái)自各種提供者的內(nèi)容(例如,天氣信息、股票報(bào)價(jià)和新聞),通常附帶有提供者的標(biāo)記。然而,由于 JSP 頁(yè)面將代碼和自定義標(biāo)記庫(kù)相混合,因此無(wú)法在這種環(huán)境下良好地工作。
JSP 頁(yè)面很少具有格式良好的 XML 文檔,并且不重視是否符合 XHTML,而 XHTML 這種標(biāo)記語(yǔ)言并不允許使用各種 JSP 自定義標(biāo)記庫(kù)。然而,更重要的是,插入到 JSP 頁(yè)面的代碼片段并不屬于任何標(biāo)記形式,因此當(dāng)另一個(gè)應(yīng)用程序處理它們時(shí),將產(chǎn)生解析器加載錯(cuò)誤。
在您提出質(zhì)疑之前,讓我們先了解一下整個(gè)情況。如果應(yīng)用程序允許 JSP 頁(yè)面由初始客戶機(jī)處理,結(jié)果將產(chǎn)生純 HTML(或 WML、VoXML 等)。然而,大多數(shù)請(qǐng)求這個(gè)數(shù)據(jù)的應(yīng)用程序使用了一定程度的緩存,因?yàn)榫W(wǎng)絡(luò)往返開(kāi)銷很昂貴。在這些情況下,緩存過(guò)的頁(yè)面將返回過(guò)時(shí)的數(shù)據(jù)。因此,您可能更愿意返回與 XML 兼容的結(jié)果,最好使用靜態(tài)的形式。而 JSP 技術(shù)在這些情況下無(wú)能為力;JSP 頁(yè)面必須始終 在運(yùn)行時(shí)進(jìn)行處理,以去掉 JSP 代碼 scriptlets 和標(biāo)記庫(kù)。
看看最關(guān)鍵的考驗(yàn):其他一些表示技術(shù)能做到這一點(diǎn)嗎?答案是可以。這個(gè)領(lǐng)域最權(quán)威的領(lǐng)導(dǎo)者是 Apache Cocoon 項(xiàng)目,它完全建立在 XML 和一個(gè) XSLT 樣式表應(yīng)用程序(可以在運(yùn)行時(shí)或靜態(tài)狀態(tài)下應(yīng)用)的基礎(chǔ)之上。由于 XML Server Pages(在 Cocoon 框架中稱為 XSP)實(shí)際上是 XML 文檔,因此始終與 XML 兼容。像 Tea 和 Enhydra XMLC 等允許輸入純標(biāo)記語(yǔ)言頁(yè)面的技術(shù)也可以做到這點(diǎn),雖然它們的目的并不在此。在這些情況下,用戶可以使用 XHTML 或標(biāo)準(zhǔn)的 HTML.此外,這比 JSP 技術(shù)要好,因?yàn)?JSP 不能 靜態(tài)地實(shí)現(xiàn)格式良好的 XML.
結(jié)束語(yǔ)
希望我的努力能夠讓您進(jìn)一步了解JSP 技術(shù)的優(yōu)缺點(diǎn),并且您可以將JSP 技術(shù)看作是眾多其他表示技術(shù)的替代品。現(xiàn)在,您可能對(duì)整個(gè)J2EE編程模型也產(chǎn)生了一點(diǎn)懷疑。如果您希望進(jìn)一步研究平臺(tái)選擇,那么可以在 Apache Cocoon、Enhydra 和各種模板引擎中尋找 JSP 技術(shù)的替代選擇。
最后,請(qǐng)記住,本文并不是建議您使用JSP或避免使用它,盡管表面上像是這樣。我的目的是鼓勵(lì)您對(duì)任何技術(shù)進(jìn)行詳細(xì)的分析,確保它是正確的選擇。就像編程模型一樣,有時(shí)它們是合適的,然而有些時(shí)候它們并不適合。多進(jìn)行一些比較,找到最適合自己的技術(shù)并作出明智的決定,而不是倉(cāng)促地決定。
【編輯推薦】