sitemesh是opensymphony團隊開發的j2ee應用框架之一,旨在提高頁面的可維護性和復用性。opensymphony的另一個廣為人知的框架為webwork是用作web層的表示框架。他們都是開源的,可以在www.sf.net下找到。
應用于以下大項目的例子:http://opensource.thoughtworks.com/projects/sitemesh.html
簡介: | ||||||||||
sitemesh應用Decorator模式,用filter截取request和response,把頁面組件head,content,banner結合為一個完整的視圖。通常我們都是用include標簽在每個jsp頁面中來不斷的包含各種header, stylesheet, scripts and footer,現在,在sitemesh的幫助下,我們可以開心的刪掉他們了。如下圖,你想輕松的達到復合視圖模式,那末看完本文吧。
|
||||||||||
hello sitemesh: | ||||||||||
最后訪問index.jsp,將生成如下頁面:
而且,所有的頁面也會如同index.jsp一樣,被sitemesh的filter使用裝飾模式修改成如上圖般模樣,卻不用再使用include標簽。 |
裝飾器 decorator概念 | ||||||
建立可復用的web應用程序,一個通用的方法是建立一個分層系統,如同下面一個普通的web應用:
可糟糕的是前端的頁面邏輯很難被復用,當你在每一個頁面中用數之不盡的include來復用公共的header, stylesheet, scripts,footer時,一個問題出現了-重復的代碼,每個頁面必須用copy來復用頁面結構,而當你需要創意性的改變頁面結構時,災難就愛上了你。 sitemesh通過filter截取request和response,并給原始的頁面加入一定的裝飾(可能為header,footer...),然后把結果返回給客戶端,并且被裝飾的原始頁面并不知道sitemesh的裝飾,這也就達到了脫耦的目的。 據說即將新出臺的Portlet規范會幫助我們標準的實現比這些更多更cool的想法,但可憐的我還不懂它到底是一個什末東東,有興趣的人可以研究
|
||||||
讓我們看看怎樣配置環境 | ||||||
除了要copy到WEB-INF/lib中的sitemesh.jar, copy到WEB-INF中的sitemesh-decorator.tld,sitemesh-page.tld文件外,還有2個文件要建立到WEB-INF/:
sitemesh.xml 可以設置2種信息:Page Parsers :負責讀取stream的數據到一個Page對象中以被SiteMesh解析和操作。(不太常用,默認即可) Decorator Mappers : 不同的裝飾器種類,我發現2種比較有用都列在下面。一種通用的mapper,可以指定裝飾器的配置文件名,另一種可打印的裝飾器,可以允許你當用http://localhost/aaa/a.html?printable=true方式訪問時給出原始頁面以供打印(免得把header,footer等的花哨的圖片也搭上) 范例:
decorators.xml :定義構成復合視圖的所有頁面構件的描述(主要結構頁面,header,footer...),如下例:
|
||||||
最重要的是寫出裝飾器本身(也就是那些要復用頁面,和結構頁面)。 | ||||||
其實,重要的工作就是制作裝飾器頁面本身(也就是包含結構和規則的頁面),然后把他們描述到decorators.xml中。
讓我們來先看一看最簡單的用法:其實最常用也最簡單的用法就是我們的hello例子,面對如此眾多的技術,我想只要達到功能點到為止即可,沒必要去研究太深(除非您有更深的需求)。
我們在裝飾器頁面只用了2個標簽: <decorator:title default="裝飾器頁面..." /> : 把請求的原始頁面的title內容插入到<title></title>中間。 <decorator:body /> : 把請求的原始頁面的body內的全部內容插入到相應位置。 然后我們在decorator.xml中加入以下描述即可: <decorator name="main" page="main.jsp"> 這樣,請求的所有頁面都會被重新處理,并按照main.jsp的格式重新展現在你面前。
|
||||||
讓我們看看更多的用法。(抄襲sitemesh文檔) | ||||||
以下列著全部標簽:
插入原始頁面(被包裝頁面)的head標簽中的內容(不包括head標簽本身)。 <decorator:body />插入原始頁面(被包裝頁面)的body標簽中的內容。 <decorator:title [ default="..." ] /> 插入原始頁面(被包裝頁面)的title標簽中的內容,還可以添加一個缺省值。 例: /_decorator/main.jsp中 (裝飾器頁面): <title><decorator:title default="卻省title-hello" /> - 附加標題</title> /aaa.jsp中 (原始頁面):<title>aaa頁面</title> 訪問/aaa.jsp的結果:<title>aaa頁面 - 附加標題</title> <decorator:getProperty property="..." [ default="..." ] [ writeEntireProperty="..." ]/> 在標簽處插入原始頁面(被包裝頁面)的原有的標簽的屬性中的內容,還可以添加一個缺省值。 sitemesh文檔中的例子很好理解: 注意, <decorator:usePage id="..." /> 例:可用<decorator:usePage id="page" /> :<%=
<page:applyDecorator name="..." [ page="..." title="..." ] > 應用包裝器到指定的頁面上,一般用于被包裝頁面中主動應用包裝器。這個標簽有點不好理解,我們來看一個例子: 包裝器頁面 /_decorators/panel.jsp:<p><decorator:title /></p> ... <p><decorator:body /></p> 最后會是什末結果呢?除了/page.jsp會被默認的包裝頁面包裝上header,footer外,page.jsp頁面中還內嵌了date.jsp頁面,并且此date.jsp頁面還會被panel.jsp包裝為一個title加body的有2段的頁面,第1段是date.jsp的title,第2段是date.jsp的body內容。 另外,page:applyDecorator中包含的page:param標簽所聲明的屬性值還可以在包裝頁面中用decorator:getProperty標簽訪問到。 |
可打印的界面裝飾 | |
前面說過有1種可打印的裝飾器,可以允許你當用http://localhost/aaa/a.html?printable=true方式訪問時,應用其他的裝飾器(自己指定),給出原始頁面以供打印(免得把header,footer等的花哨的圖片也搭上)。
讓我們來看一看怎樣實現他: 1.首先在WEB-INFO/sitemesh.xml中設置: 2.在WEB-INFO/decorators.xml中定義相應的printable裝飾器 3.最后編寫printable裝飾器/decorators/printable.jsp
這樣就可以讓一個原始頁面通過?printable=true開關來切換不同的裝飾器頁面。
|
中文問題 |
由于sitemesh內部所使用的缺省字符集為iso-8859-1,直接使用會產生亂碼,我們可以通過以下方法糾正之:
|
總結:使用sitemesh最通常的途徑: |
1.配置好環境, 2.在WEB-INFO/decroators.xml中描述你將建立的包裝器。 3.開發在decroators.xml中描述的包裝器,最好存放在/_decorators目錄下 4.ok ,可以看看辛勤的成果了 : |
:sitemesh,一個不錯的tiles替代方案,比tiles做的更漂亮優雅。本文是sitemesh官方推薦的入門文檔,本來想自己翻譯的,突然發現有人先行一步了,就轉過來看吧。
以前我通常使用舊式的方法來建立自己的web應用:手工排版,仔細使用每一個字節使其工作在Unicode下,同時使用make文件來適應不同的CPU……
或許現在我們可以換一種方式。
盡管我從沒有感覺到需要使用assembly (CISC or RISC)來建立web應用,但也會偶爾覺得我的開發伙伴的工作相當繁瑣。特別是我發現很多的開發者在痛苦的尋求一種比較好的方式來控制web應用的基本模塊:例如那些頁頭、頁尾、導航欄、打印頁面、手持設備的輕量級頁面,以及其他更多的問題。到了最后,令人驚異的是大部分人都采用了落后的includes和復制粘貼方式。
根據經驗,我可以采用在java.net上開源的servlet 過濾器SiteMeshn來簡單明了并優雅的解決這些問題。作為一種替代新的templating語言(XSLT)或部署您的頁面到新的系統的解決方法,應用SiteMesh可以相當容易處理你的頁面,這一切只需要普通的HTML,JSP,servlet(包括Struts),以及其他常用的技術。
工作原理SiteMesh利用了一種很少人知道的servlet規范實現了一種頁面過濾器。設想一下,現在有一個簡單的jsp頁面用來返回當前的日期和時間。通常這個頁面請求來到應用服務器,頁面被處理,最后處理結果返回到web瀏覽器。SiteMesh作為一個頁面過濾器,在頁面被處理之后,返回web瀏覽器之前,對頁面做了一些附加的操作。這個變化簡單描述為圖一和圖二所示的附加步驟。
圖一:普通頁面處理情況
圖二:SiteMesh對頁面處理情況
現在看一個簡單的例子。
<html>
<head>
<title>Simple Document</title>
</head>
<body>
Hello World! <br />
<%= 1+1 %>
</body>
</html>你會發現這個頁面有一個title和body(類似普通的HTML頁面)。你也會發現一小段JSP代碼——它將會如同你期望的那樣被處理。同時你可以使用任何你想使用的JSP語法和特性來替換這一小段代碼。
現在來看一個簡單的SiteMesh "裝飾(decorator)"頁面。列表2顯示了一個被SiteMesh調用的JSP頁面。
<%@ taglib uri="sitemesh-decorator"
prefix="decorator" %>
<html>
<head>
<title>
My Site - <decorator:title default="Welcome!" />
</title>
<decorator:head />
</head>
<body>
<h1><decorator:title default="Welcome!" /></h1>
<p><decorator:body /></p>
<p><small>
(<a
href="?printable=true">printable version</a>
</small></p>
</body>
</html>查看這個裝飾器(decorator),我們能看到一些有趣的東西。首先,在第一行申明了一個SiteMesh標簽庫。這個標簽庫包含了與原始頁面一起工作時所需的所有東西。你能看到我們使用了兩個SiteMesh的裝飾標簽(declared tags),<decorator:title>和<decorator:body>。不要驚訝于標簽<decorator:title>在原始頁面中顯示<title>標簽中的內容,<decorator:body>中的內容也是如此。我們在這個頁面的HEAD和BODY元素都使用了同一個title標簽。(We're making a few fairly radical changes to the page, including repeating the title both in theHEADelement as well as theBODY. )同時,我們還增加了一個到可打印版本頁面的鏈接。
作為對照,圖三顯示了原始處理頁面,圖四顯示了被修飾過的處理頁面。留意被裝飾頁面在瀏覽器窗口顯示的標題文字和HTML內容。同時也可以看到增加了一個可打印頁面的鏈接——這個我們回頭再說。
圖三:原始未修飾頁面
圖四:被修飾頁面
很明顯,對比起使用include(例如<jsp:include page="foo.jsp" flush="true" />)來說,以這樣的方式使用頁頭、頁尾系統結構要清晰得多。這種方式更易移植、更易理解,同時也鼓勵了JSP頁面不再使用導航或其他類似的表現層代碼。我發現在JSP頁面中使用裝飾器和CSS的組合比標準HTML的標簽更容易去除格式信息。
安裝SiteMesh注意下面的屏幕截圖是基于Windows XP Professional,Tomcat 5.0.19,和Java 2 SDK 1.4.2_03的環境之上的。在這里我假定你的Tomcat已經安裝完畢并且可以正常工作了。你或許會有一些混淆,但我們已經成功地在Tomcat 4.1 和 WebLogic 測試過,同時 SiteMesh 也支持大部分的web應用服務器。
本文描述的SiteMesh 2.0.1可以在下載到。 在java.net 上SiteMesh's 的項目庫中有四個文件可以下載。sitemesh-2.0.1.jar是其核心 JAR 文件,sitemesh-2.0.1-sources.zip的作用正如同其名字所述,sitemesh-example.war則提供了一個復雜的例子用來顯示一些SiteMesh的高級特性。
為了使描述更加簡單,我們從sitemesh-blank.war文件開始。將該WAR文件放入Tomcat 的webapps目錄,WAR包將自動解壓顯示內容(SoSo注:這里的前提是你的tomcat已經開始工作),如圖五所示。
圖五: SiteMesh_blank.WAR解開后的內容
我們花點時間描述一下這些文件的作用。
web.xml首先,WEB-INF/web.xml文件顯示如列表3,這些語句用來安裝SiteMesh 過濾器和標簽庫。如果你決定在一個已有的Web應用中使用SiteMesh,你必須把這些語句添加到你的WEB-INF/web.xml文件中。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>
<!-- Start of SiteMesh stuff -->
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<taglib>
<taglib-uri>sitemesh-page</taglib-uri>
<taglib-location>/WEB-INF/sitemesh-page.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>sitemesh-decorator</taglib-uri>
<taglib-location>/WEB-INF/sitemesh-decorator.tld</taglib-location>
</taglib>
<!-- End of SiteMesh stuff -->
</web-app>注意:這里需要注意一下url-pattern的寫法-- 如果使用的是Tomcat 5(而不是 Tomcat 4 ),需要將默認的*修改如*.jsp的形式。最新的servlet規范不再支持*樣式。
decorators.xmlWEB-INF/decorators.xml文件用來將一個裝飾器名字同一個專門的JSP裝飾文件綁定。作為一個例子,這里將JSP裝飾文件minimal.jsp同一個稱為handheld的裝飾器綁定起來。
<decorators defaultdir="/decorators">
<decorator name="main" page="main.jsp">
<pattern>*</pattern>
</decorator>
<decorator name="panel" page="panel.jsp"/>
<decorator name="printable" page="printable.jsp"/>
</decorators>正如我們在代碼列表里看到的一樣,我們定義了三個裝飾器,他們分別綁定了三個類似的JSP頁面。我們可以看到一個默認裝飾器(main.jsp),它將被默認運用于所有文件。
缺省的,SiteMesh使用下面的邏輯來選擇使用哪一個裝飾器:
這個邏輯在sitemesh-2.0.1.jar包的\com\opensymphony\module\sitemesh\factor\sitemesh-default.xml文件里被描述。你可以針對諸如:客戶端操作系統,web瀏覽器,用戶代理等在WEB-INF\sitemesh.xml文件里,通過一個變量覆蓋這個行為。(You can override this behavior. with a wide variety ofbuilt-in mappersfor things like language, client operating system, web browser/user agent, etc. by creating aWEB-INF\sitemesh.xmlfile. )可以在sitemesh-example.war找到例子。 |
- 頁面是否使用meta裝飾器標簽(meta. decorator tag)特別指定了一個裝飾器?
- 頁面是否是一個框架集(是的話則不應用裝飾器)?
- 頁面是否使用了printable=true參數(是的話則使用打印裝飾器)
- 頁面時候使用裝飾器文件名特別指定了一個裝飾器?
- 頁面是否匹配decorators.xml文件里描述的樣式?
通常第一條規則僅用來確定該裝飾器是否被使用(Conceptually, the first rule that evaluates to true determines the decorator that is used. )在上面的例子中,當出現printable=true參數的時候,裝飾器printable.jsp(規則 #3)替代了main.jsp(規則 #5)。在SiteMesh中,這些規則被描述為mappers。
decorators/*.jsp這三個decorators目錄下的文件是decorators.xml文件中描述的不同裝飾器JSP文件。上面是一個簡單的裝飾器例子,在后面我們將討論更復雜的示例。
sitemesh-2.0.1.jar這是SiteMesh最主要的二進制文件,通常被安裝在WEB-INF/lib目錄下??梢栽?a target="_blank">www.opensymphony.com/sitemesh/api找到這個庫的javadoc。
*.tldSiteMesh使用兩個標簽庫,但大多數人都只需要sitemesh-decorator.tld。你可以在www.opensymphony.com/sitemesh/tags.html找到相應的文檔。我們已經講述了最主要的標簽:head,title和body。在下一章我們來討論剩下的標簽:getProperty。
SiteMesh高級特性SiteMesh的一個重要特性是使用原始HTML的meta標簽(例如<meta. name="foo" c>)從基礎頁面傳遞信息到裝飾器。作為一個例子,下面我們使用一個meta標簽來定義HTML頁面的作者。
<html>
<meta. name="author" c>
<head>
<title>Simple Document</title>
</head>
<body>
Hello World! <br />
<%= 1+1 %>
</body>
</html>我們定義一個“smart”裝飾器來研究meta標簽,如果出現這個標簽,則可以得到一個相應的HTML:
<%@ taglib uri="sitemesh-decorator" prefix="decorator" %>
<decorator:usePage id="myPage" />
<html>
<head>
<title>My Site -
<decorator:title default="Welcome!" />
</title>
<decorator:head />
</head>
<body>
<h1><decorator:title default="Welcome!" /></h1>
<h3>
<a href="mailto:<decorator:getProperty property="meta.author"
default="staff@example.com" />">
<decorator:getProperty property="meta.author"
default="staff@example.com" />
</a></h3><hr />
<decorator:body />
<p><small>
(<a href="?printable=true">printable version</a>
</small>
</p>
</body>
</html>可以看到我們使用了getProperty標簽的一個默認屬性——如果沒有指定author,我們就設定其為staff。如果你決定使用這個模型儲存頁面的meta數據,你或許需要和你的開發伙伴一起來確定將使用什么標簽以及如何使用他們。簡單的,你或許想要使用meta標簽來描述諸如頁面作者及時間戳之類的東西。更復雜一些,你或許會想像XML文件一樣標準化的管理你的站點導航,同時使用meta標簽來通過頁面節點轉到裝飾器。(At the complex end, you may do things like standardize on an XML file to manage your site navigation and use ametatag to pass the page's node to the decorator. )
圖六顯示了應用上面的裝飾器JSP頁面之后生成的結果。
圖六:meta標簽顯示
這些頁面屬性非常強大,并且擁有著很多不同的特性,并不僅止于meta標簽(常用頁面特性列表)。使用SiteMesh一段時間之后,你就會開始思考HTML和JSP作為一種簡單標記語言的機制——接近最原始的HTML——無需操作就可以完整的切換到XML/XSL 或其他模版引擎。
小結綜上所述,SiteMesh 提供了一個強大、易用、易結合的機制來使用頁面模版??梢韵胂?,它將會有很廣泛的用戶群。例如,你可以定義一個裝飾器針對不同的瀏覽器輸出額外的頁面調試信息(和特定web瀏覽器結合之后將產生一個特別的功能,你可以強制指定使用某一種用戶代理)。你也可以定義一個裝飾器產生stripped-down XML輸出,用來進行簡單的自動化測試。你甚至可以使用裝飾器從其他頁面提取內容,例如輸出到一些簡單的門戶容器。
從sitemesh-blank.war入手比較容易,但我建議學習sitemesh-example.war以獲取更多的特性和思想。
不論你如何使用SiteMesh,我都發現它將大量的代碼從表現層中移到我的裝飾器中,而無需學習一種新的編程語言或是模版系統。
對了,作為最后的補充,如果你仍然對組合建立web頁面感興趣,可以查看home.worldonline.dk/viksoe/asmil.htm。
文章引用自:http://blog.51766.com/comments/zy/Weblog/1143682180134