top
Loading...
JavaServerPagesservlet技術(下)
JSP 技術的承諾

現在,我們來討論 JSP 編碼的具體內容。JSP 技術承諾為設計人員和開發人員提供他們所需的最合適的表示技術。JSP 技術是 J2EE 平臺的一部分,顯示了 Sun 公司所能給予 Java 產品的最強大支持。為了使您對此解決方案的流行程度有一個概念,您可以試著在 amazon.com 上搜索一下“JSP”,您會發現,論述 JSP 的書籍比論述其他任何一種 Java API 的書籍都要多。在我深入討論 JSP 技術存在的特定問題之前,您需要對它承諾的功能有一個清楚的了解。


內容與表示

首先,JSP 技術是用來分離內容和表示的,這一點最早出現在 Sun 對于 JSP 公布的一系列目標中。實際上,JSP 的設計直接針對開發人員的抱怨,這些開發人員對于在 servlet 代碼中反復鍵入 out.println("<HTML><HEAD><TITLE>"
+ pageInfo.getTitle() + "</TITLE></HEAD>") 感到厭煩。這種硬編碼內容和運行時變量的混合對 servlet 開發人員造成了巨大的負擔,也使開發人員在對表示層進行即便是最小的改動時也困難重重。

JSP 技術通過支持普通 HTML 頁(以及稍后的 WML 或其他標記語言頁)在運行時編譯為 Java servlet,改變了這種情況。它實際上是模仿 out.println() 語句,而無須開發人員編寫代碼。同時還允許在頁面中插入變量,直到運行時才解釋這些變量。

清單 2 所示的 HTML 片段相對應的 JSP 頁應與清單 3 中的示例相似。

清單 3. 一個使用表示技術包含數據的 JSP 頁
<%@ 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><!-- 其他 HTML 內容 --></BODY></HTML>


按這些初始原則判斷,JSP 技術(至少在它的聲明設計中)會滿足表示技術的第一個原則,如上所述:即內容與表示的分離。

代碼與標記

JSP 技術所列的第二個特性可能引起你的注意,那就是,JSP 編碼允許直接向標記頁中插入 Java 代碼。為了理解作出這種決定的原因,我們回想一下制定 JSP 規范時的情況。Sun 與微軟的競爭一直非常激烈,主要源于微軟 Active Server Pages (ASP)的成功。JavaServer Pages 與 Active Server Pages 在名稱上的相似并非巧合。而且模仿 ASP 的多種特性似乎亦是有意的。所以 JSP 的作者選擇了在他們的標記中加入 Java 代碼。

作為向標記中加入 Java 代碼的一個例子,清單 4 中的 JSP 片段自動按需要添加行,以顯示演員 Vector 中的每一項。

清單 4. 插入到標記語言頁中的 Java 代碼
<%@ 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">搜索結果:演員</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 技術的最初目標。在后面的章節中談及關于 JSP 技術的問題時,我才會作出本人對此目標的判斷。但是,您現在可能已經有點懷疑了,因為向 JSP 頁中嵌入代碼似乎會導致與 JSP 技術的第一個目標有關的問題(即把內容和表示分離開來)。但是實際上(啊咳),我還沒有發表意見呢。

設計人員與開發人員

JSP 技術值得一提的最后一個(也是值得贊賞的)目標是,它試圖在應用程序開發過程中建立明確定義的角色。通過表面上將內容和表示分離開來,JSP 技術在設計人員和開發人員之間劃定了一條更加明顯的界線。設計人員只使用標準的 HTML、WML、或其他適當的語言創建標記,開發人員編寫代碼。當然,現在許多設計人員已經學會了JavaScript,所以不應驚奇的是,他們中的許多人也開始學習 JSP 編碼。很多情況下,他們不只是做純標記,而是編寫完整的 JSP 頁,并把它交給開發人員。進行常規的調整后,開發人員把這些 JSP 頁作為整體應用程序某一部分的前端放置到適當位置。但關鍵是,許多設計人員不會 JSP 編碼,所以在這種環境中還有工作可做。

問題

我已清楚地說明了良好的表示技術應提供的東西,以及 JSP 技術試圖解決的特定問題。現在,我準備切入正題:JSP 技術的設計雖然想法很好,但是它帶來了相當多的問題。在選擇在應用程序中使用 JSP 之前(您可能仍會使用),您應該至少知道可能存在的缺陷。

您也應該了解 J2EE 編程平臺常被忽視的一個小問題:此平臺提供一種 API 并不意味著您必須使用它。正像這句話聽起來有點愚蠢一樣,許多開發人員還在 JSP、EJB 或 JMS API 中掙扎,他們認為如果不使用這些 API,他們的應用程序就有點不像是真正的“J2EE 應用程序”。實際上,此平臺承諾的諸多 API,對大多數應用程序來說都不必要。如果您在使用 JSP 技術時出現問題或對它有懷疑,您完全可以不使用它! 在選擇在應用程序中使用 JSP 技術之前,請仔細看一下它的優缺點。現在讓我們看一下它的幾個缺點。

可移植性與語言鎖定

JSP 技術把您鎖定在一種特定的語言中。對于這一點不應該看得太重。在設計企業應用程序時,Java 技術是唯一的語言選擇(至少我的觀點是這樣)。在這個問題上,沒有獨立于語言的解決方案。當然,在游戲的這個階段,我還不考慮 Microsoft .NET 平臺的煙幕及其實際情況。只有時間會證明 Microsoft .NET 平臺是否會發展成為一個真正獨立于語言的產品。(我很懷疑。)

還有,選擇 JSP 技術會強制您使用 Java 語言,至少對表示和內容而言是這樣。雖然 CORBA 可用于業務邏輯,但進行 JSP 編碼確實需要熟悉一些 servlet 以及核心的 Java 語言。由于許多開發人員都是從 J2EE 平臺轉向 JSP 編程,所以這點通常不是問題。

混合與獨立

在全文中,我多次提到把內容和表示分離的想法。您也許已經聽煩了,那么現在到了我們來確定 JSP 是否真的實現了這個目標的時候了。正像我已說過的那樣,既然 JSP 聲稱是為這一分離目標而設計的,所以我們應該假定它實現了這個目標?對嗎?未必。

模糊了內容與表示之間的界限

JSP 允許向標記語言頁中插入 Java 代碼,這一點相當危險,它甚至允許將內容混合到表示中。更糟的是,業務邏輯經常混入 JSP 頁中,如清單 5 所示。

清單 5. 包含業務邏輯的 JSP 頁
<%@ 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">搜索結果:演員</H2> <CENTER> <HR WIDTH="85%"> <TABLE WIDTH="50%" CELLPADDING="3" CELLSPACING="3" BORDER="1" BGCOLOR="#FFFFCC"><% // 根據用戶的權限,執行不同的搜索(業務邏輯!) 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 的擁護者會馬上告訴您 JSP 標記庫可以幫助您避免這種問題。標記庫允許向 JSP 頁加入定制的標記(例如<AUTHORS />),這些標記在運行時解釋為標記庫中的代碼片段。

使用定制標記和相關的標記庫會使上面的示例變為清單 6 中的代碼。

清單 6. 結合到頁中的定制標記和標記庫
<CENTER> <TABLE WIDTH="50%" CELLPADDING="3" CELLSPACING="3" BORDER="1" BGCOLOR="#FFFFCC"> <ACTORS /> </TABLE> </CENTER>

在運行時,這個標記的代碼就會執行,正確的結果會插入到頁中。但這并沒有解決問題。此時,對 JSP 技術不利的論點不在于表示和內容是否能夠分離,而是在于他們是否必須分離。只要 JSP 編程允許內嵌代碼,則使用內嵌代碼作最后的修改就很容易(特別是在限期鄰近時),而不是把代碼轉化到標記庫中。如果不是這樣,請考慮一下 Java 語言的流行速度迅速超過C 和 C++ 的原因:Java 不允許 C 中許多有問題的特性,例如指針加法。盡管您總是可以爭辯在 C 中不是必須執行指針加法,或者優秀的程序員從來不會插入代碼 scriptlet,但是我們都知道實際情況會是怎樣。Java 語言優于 C,是因為它禁止這種壞習慣出現。但 JSP 在這種情況下,與 C 語言極為相似,它允許一些壞習慣。

對于 JSP 技術是否達到了它所宣稱的目標, 還有一個測試標準,就是看它實際上是否能夠達到目標。當然,以不可能達到的標準來要求 JSP 是不公平的。大多數模板引擎(例如 FreeMarker 和 WebMacro)有這種相同的內嵌代碼功能,通常這些模板使用類似 Perl 的語言。但是,像 enhydra 的 XMLC 這樣的技術,不允許這種內嵌代碼。這些技術使用一個純標記語言頁作為輸入來代替,并生成 Java 方法。這種做法實質上是改變了程序流,而不是頁面(JSP 技術)調用應用程序的邏輯,應用程序(enhydra)使用方法來影響頁面中的值。在 enhydra 的特定情況下,XMLC 把頁面轉化為一個 DOM 樹,并使用 DOM 的 HTML 綁定來允許頁中“域”的更新。(關于 enhydra XMLC 的詳細信息,請參閱參考資料。)

在這一點上,JSP 比 XMLC 問題更嚴重。例如,雖然 JSP 技術能夠實現它的目標,但是它只允許使用標記庫。但是,Sun 規范中的總趨勢是始終保持向后兼容,或至少保持相當長的一段時間。當前版本的 JSP 1.1 允許使用 scriptlet,所以估計 JSP 頁包含代碼這一情況還要維持幾年。在深入探討 JSP 編碼前,請注意它實際提供了產品(它至多不過是用戶界面和驅動應用程序的代碼之間的偽分離)和它的目標(即完全分離內容和表示)之間仍有相當大的差距。

單一處理與多任務

如上討論,理想情況下,設計人員應該只執行單一處理,即只進行圖形設計工作,開發人員應該只注重于編碼。這樣,在一個頁面轉化為應用程序所使用的格式后,設計人員應能夠修改它。在 JSP 頁的情況下,這應該在導入 JavaBean、插入內嵌代碼、在頁中加入定制標記庫之后。問題是有些設計人員使用 HTML 編輯器,如 HoTMetaL、Macromedia Dreamweaver 或 FrontPage,這些編輯器不能識別代碼 scriptlet 或標記庫,這意味著設計人員實際上只收到了部分頁面。當標記庫或代碼段在頁中產生表格行或其他格式的具體內容時,其困難程度可想而知。使用不兼容的 HTML 編輯器,設計人員無法看到那些元素是什么樣子。當設計人員無法方便地修訂開發人員編譯后的頁面時,JSP 編碼不是把不同的角色區分開來,而是使這些角色合并在一起:開發人員必須能夠完成多種任務,成為開發人員兼設計人員并承擔其他角色。

這種重要特性沒有使您信服嗎?那么您可以下載 J2EE 參考實現,并把其中任意一個包含的 JSP 頁調入所見即所得的 HTML 編輯器,如 Dreamweaver。這個頁面立即充滿黃色區域,使您知道包含在頁面中的所有“非法”標記。當然,黃色區域是由 JSP 標記和代碼造成的,不是頁中的任何實際錯誤。

到目前為止,還沒有出現任何能夠支持 JSP 的所見即所得編輯器,我也沒有聽說有人正致力于開發這樣的編輯器。模板引擎亦有這種相同的問題,許多基于 Java 的方案(例如我喜歡的 enhydra),允許把標記頁作為輸入提交表示技術。在這種情況下,設計人員可以反復修改標記頁,再把它們重新提交回去。運行表示技術的引擎或編譯器可以將此頁面轉換為正確的格式,并且不需要改變代碼(在通常情況下)。結果正是我們所希望的:設計人員就是設計人員,而開發人員就是開發人員。

所以,和 JSP 技術實際提供的功能相比較,我希望您一定要小心對待 JSP 技術提出的承諾。實際上,為了使應用程序在一個 JSP 技術驅動的環境下成功運行,您必須讓您的開發人員處理大量標記,或者使設計人員至少學習一些 JSP 編程。

HTML 與 XML

JSP 技術的一個最嚴重的缺陷,也是最易被忽視的一點,就是它與 XML 不兼容。更準確的說,尤其是在 HTML 領域中,JSP 頁不需要兼容 XHTML。XHTML 是一個萬維網聯盟 (W3C) 規范,它現在正取代 HTML 4.0。XHTML 按照一種結構完整的 XML 文檔定義 HTML 標記集。例如 <br> 標記必須轉換為 < br/>,以確保遵守 XML 規定。(如果您覺得這一點沒有闡明清楚,可以查閱 XML 規范和 developerWorks 關于 XHTML 的文章,它們在列在參考資料中。)
圖像標記也有類似的規則,在 XHTML 1.1 (最近誕生的) 中,大多數字體屬性和其他樣式轉移到了 CSS 樣式表中。另外,大多數標準的 HTML 文檔可以很容易轉換為 XHTML 1.0,這意味著它們很容易使用 XML 兼容的分析程序閱讀,例如 Apache Xerces,并且能夠以 XML 方式控制。

您會問:“最重要的是什么?”最重要的一點就是 XML 迅速成為互聯網和企業內部網的全球標準。對于任何使用基本 XML 數據處理工具的其他應用程序,以 XML 格式傳送數據,它們可以很容易地使用您的應用程序的數據。試想一下,只須把數據轉換為 XML 格式就能與信用卡公司進行電子商務通信! 很多情況下,您的數據表示也需要和其他公司交換數據。最常見的情況是門戶站點應用程序,它從不同的提供者(例如天氣、股票報價和新聞等)接收內容,這些內容還常常帶有提供者的標志。但是,JSP 頁面由于混合了代碼和定制標記庫,所以無法在這樣的環境中良好工作。

JSP 頁幾乎不是格式完整的 XML 文檔,更不用提符合 XHTML了。因為 XHTML是一種標記語言,它不允許各種 JSP 定制標記庫。但是更重要的是,插入到 JSP 頁中的代碼片段不是任何形式的標記,而且一旦用另一個應用程序處理它們,就會產生分析程序錯誤的負擔。

在您對我進行評論之前,讓我講完整個故事。如果應用程序允許原始客戶機計算 JSP 頁的值,其結果會是純 HTML (或 WML、VoXML 等)。但是,大多數請求數據的應用程序使用某些形式的緩存,因為網絡上的往返是很昂貴的。在這些情況下,緩存的頁面返回陳舊的數據。在這種情況下,您可能更希望返回完全符合純 XML 的結果,最好是靜態表單。但是 JSP 技術對這種情況無能為力。JSP 頁必須始終在運行時求值,這樣才能去掉 JSP 代碼 scriptlet 和標記庫。

檢驗一下:有其他表示技術能夠完成這個任務嗎?答案是肯定的。在此領域的絕對領先者是 Apache Cocoon 項目,它完全基于 XML,是一個 XSLT 樣式表應用程序(即可在運行時應用,也可靜態地應用)。由于 XML Server Pages(在Cocoon 框架中叫作 XSP)實際上是 XML 文檔,所以它們始終是符合 XML 的。其他允許純標記語言頁輸入的技術(例如 Tea 和 enhydra XMLC)也可以允許這一點,雖然它們不強制這樣做。在這些情況下,用戶可以使用 XHTML 或標準 HTML。但是這樣仍然比 JSP 的情況要好,因為在 JSP 中無法無法靜態實現格式完整的 XML。

小結

我希望我為您拓寬了一些眼界,使您看到了 JSP 技術的優缺點。現在,您可以把 JSP 編程看成是多種表示技術中的一種可選技術。在這一點上,您可能對整體的 J2EE 編程模型有所懷疑。現在您也許希望更進一步研究此平臺的替代方案,并在 Apache Cocoon、enhydra 和多種模板中選擇替代 JSP 編碼的方案。

最后,應該記住的是,盡管本文似乎提出了反對意見,但并沒有建議您使用或不使用 JSP。我無意鼓勵您深入到任何技術的深層探究它是否符合您的要求。編程模型就像是例子,有時行得通,有時行不通。三思而后行,找到最適合您的方案再做決定,這總比草率做決定要好。

玩得開心,網上見!

參考資料


參閱當前的 JSP 規范,以獲得全部內容。


進一步查看 JSP
1.2 中的新內容。


擔心 XML 的兼容性嗎? 您可以閱讀規范以及 Molly Holzschlag 的文章 article for developerWorks on getting up to speed,以獲得 XHTML 的詳細信息。


在 W3C Style Center 上獲得樣式文檔的 XML 視圖。


需要知道比提供 JSP 更多功能的 J2EE 方案嗎?它也是開放源代碼的嗎?請閱讀今天的 enhydra。

解放您的思想,看一下 Apache Cocoon,它是使用 XSLT 處理動態目錄的另一個開放源代碼的替代方案。

如果您不介意跳出 Java,模板引擎可以解救您!兩個值得一看的站點是 WebMacro 和 FreeMarker。

作者簡介

Brett McLaughlin 是 Lutris Technologies 公司的 enhydra 戰略家,專門研究分布式系統體系。他是 Java and XML (O'Reilly) 的作者;從事 Java servlet、Enterprise JavaBeans 技術、XML 和企業對企業的應用程序的研究。最近與 Jason Hunter 起創建了 JDOM 項目,此項目為從 Java 應用程序操縱 XML 提供簡單的 API。他還是 Apache Cocoon 項目、EJBoss EJB 服務器的活躍開發人員,并且是 Apache Turbin 項目的創始人之一。可以通過 brett@newInstance.com 與 Brett 聯系。

北斗有巢氏 有巢氏北斗