|
在這種情況下,怎樣讓你的應(yīng)用系統(tǒng)從外觀和感受(look and feel)上保持一致呢?一種辦案就是采用J2EE技術(shù)全部重寫,然后選用一種框架,比如Struts-Tiles,但這種辦案的開發(fā)成本太高,不太現(xiàn)實(shí)。另一種可選方案是在你的應(yīng)用系統(tǒng)的各個(gè)部分采用相同的Look and Feel。但這種方案會(huì)使維護(hù)站點(diǎn)變成噩夢(mèng),因?yàn)槊慨?dāng)一個(gè)應(yīng)用系統(tǒng)里面的Look and Feel需要改變的時(shí)候,你就需要讓系統(tǒng)里的其他web應(yīng)用保持同樣的改變。 大多數(shù)用于解決這種商務(wù)需求的可用框架都有一個(gè)共同的缺點(diǎn),他們不是平臺(tái)相關(guān)就是框架相關(guān)。當(dāng)你決定采用Tiles作為struts修飾器的時(shí)候,需要?jiǎng)?chuàng)建tiles定義文件tiles-defs.xml,然后在struts-config.xml里面聲明forwards,引用這些tiles以修飾原始的JSP。 最簡(jiǎn)單的一種可能的解決方案是,全部采用純html方式來生成你的web應(yīng)用,每一個(gè)html頁面都不需要知道自己將會(huì)被如何修飾,而是在外部采用某種機(jī)制來選擇合適的修飾器修飾它們。這就是SiteMesh的功能。 SiteMesh是基于Java、J2EE和XML的開源框架,依賴于從Servlet 2.3版本里引入的新功能——過濾器(Filters) 安裝和設(shè)置 按照以往的經(jīng)驗(yàn),學(xué)習(xí)任何新技術(shù)或新框架最好的辦法,就是使用它來創(chuàng)建一個(gè)簡(jiǎn)單的應(yīng)用程序。所以,我們將使用SiteMesh來創(chuàng)建一個(gè)簡(jiǎn)單的Struts應(yīng)用程序。我們的應(yīng)用程序包括三個(gè)頁面: •一個(gè)登錄頁面 •一個(gè)幫助頁面,包括頁頭和頁腳 •一個(gè)主頁面,包括頁頭、頁腳和頁邊菜單 下面是創(chuàng)建這個(gè)簡(jiǎn)單web應(yīng)用程序的步驟: 1.SiteMesh基于過濾器,所以我們需要把SiteMesh過濾器通知給我們的web應(yīng)用程序。在web.xml文件里加入如下幾行:
這幾行是告訴web容器,所有對(duì)web應(yīng)用的請(qǐng)求都會(huì)經(jīng)由PageFilter“過濾”一下。PageFilter是sitemesh-2.1.jar里的一個(gè)類,你可以從http://www./sitemesh/download.html下載該jar包。 2.在WEB-INF目錄下生成一個(gè)decorators.xml文件,內(nèi)容如下:
decorators.xml文件用來在你的應(yīng)用程序里定義修飾器(decorators)。在這個(gè)文件里,每個(gè)<decorator>元素定義一個(gè)修飾器,name指定修飾器名,page指定修飾器所使用的JSP頁面。<pattern>子元素指定這些修飾器如何應(yīng)用到實(shí)際的頁面上去。 在我們的示例web應(yīng)用里,定義了兩個(gè)修飾器:追加頁頭和頁腳的headerfooter.jsp和追加頁邊菜單的sidemenu.jsp。我們想修飾help頁面追加頁頭和頁腳,所以我們追加了一個(gè)/help.jsp路徑子元素給headerfooter.jsp修飾器。 3.在WebContent/decorators目錄下創(chuàng)建headerfooter.jsp:
一個(gè)SiteMesh修飾器其實(shí)就是一個(gè)使用SiteMesh自定義標(biāo)簽的JSP頁面。在我們的web應(yīng)用里,當(dāng)用戶請(qǐng)求help頁面的時(shí)候,SiteMesh會(huì)攔截這個(gè)請(qǐng)求,然后再把它發(fā)送給web應(yīng)用。而當(dāng)應(yīng)用返回響應(yīng)的時(shí)候,SiteMesh會(huì)結(jié)合headerfooter.jsp文件解析這個(gè)響應(yīng),遇到<decorator:head/>就插入響應(yīng)文件的<head>,遇到<decorator:body/>就插入響應(yīng)文件的<body>。最后,被headerfooter.jsp修飾過的文件會(huì)被返回給客戶端。 4.在WebContent目錄下創(chuàng)建help.jsp:
這是一個(gè)在web應(yīng)用里很常見的help頁面。 5.在瀏覽器里請(qǐng)求help.jsp頁面,測(cè)試SiteMesh安裝是否正常。瀏覽器將會(huì)返回一個(gè)包含頁頭和頁腳的help頁面。 SiteMesh架構(gòu) SiteMesh架構(gòu)基于PageFilter——一個(gè)Servlet過濾器。容器接收到頁面請(qǐng)求時(shí),會(huì)把請(qǐng)求傳遞給PageFilter,PageFilter收集應(yīng)用程序的響應(yīng)細(xì)節(jié),生成自定義的響應(yīng)對(duì)象,然后連同請(qǐng)求一起傳遞給web應(yīng)用程序。web應(yīng)用程序把響應(yīng)資源寫入到自定義響應(yīng)對(duì)象里,再返回給PageFilter。 1.解析階段 當(dāng)控制返回給PageFilter的時(shí)候,它會(huì)檢查web應(yīng)用生成響應(yīng)的內(nèi)容類型(content type),然后基于響應(yīng)類型,生成不同的解析器來解析響應(yīng)。比如,如果應(yīng)用返回text/html類型的內(nèi)容,SiteMesh會(huì)生成一個(gè)FastPageParser實(shí)例,并把web應(yīng)用生成的頁面?zhèn)鬟f給它。FastPageParser會(huì)解析這個(gè)頁面,提取出這個(gè)頁面的header、footer、title 等內(nèi)容。 2.修飾階段 解析結(jié)束后,SiteMesh開始修飾頁面。這一階段分成兩部分: a.決定如何修飾 SiteMesh有一個(gè)概念,叫做修飾器映射,實(shí)現(xiàn)這個(gè)概念的接口是DecoratorMapper(有init()和getDecorator()方法)。映射器在sitemesh.xml里聲明。在sitemesh.xml文件里,每一個(gè)映射器都是它上一個(gè)映射器的父映射。當(dāng)SiteMesh需要一個(gè)修飾器來修飾頁面的時(shí)候,會(huì)在sitemesh.xml里查找映射器,生成找到的第一個(gè)映射器的實(shí)例并調(diào)用getDecorator()方法,在這個(gè)方法里嘗試查找針對(duì)那個(gè)頁面的修飾器。如果找到了就返回;否則,調(diào)用父映射器的getDecorator()方法,反復(fù)進(jìn)行這個(gè)過程,直到找到正確的修飾器。 b.應(yīng)用修飾 找到修飾器后,SiteMesh會(huì)把請(qǐng)求分發(fā)給它。修飾器JSP頁面會(huì)訪問在前階段里解析出來的頁面信息。使用各種SiteMesh自定義標(biāo)簽來提取頁面信息不同的部分(比如header、footer和title)并把它們插入到輸出文件合適的位置上去。 你可以在sitemesh.xml文件里自定義使用哪個(gè)頁面解析器來解析指定的內(nèi)容類型或者使用哪種修飾器映射方案,比如:
在這個(gè)列表里,<property name="decorators-file">指定了用于定義修飾器的文件。<page-parsers>定義了SiteMesh可以處理的內(nèi)容類型。每一個(gè)<parser>子元素指定哪一個(gè)解析器解析哪一種特定的內(nèi)容類型。在我們的示例sitemesh.xml文件里,我們告訴SiteMesh使用FastPageParser解析text/html類型的內(nèi)容。默認(rèn)地,SiteMesh只可以處理HTML,但我們可以創(chuàng)建自己的解析器來處理其他的內(nèi)容類型。 <decorator-mappers>子元素定義了映射方案,SiteMesh使用這個(gè)映射方案來查找修飾指定頁面的修飾器。你可以使用<param>子元素來配置每一個(gè)映射器。SiteMesh會(huì)把這些配置信息包裝成java.util.Properties對(duì)象傳遞給映射器的init()方法。 區(qū)域相關(guān)的修飾器 在我們的示例sitemesh.xml文件里,有下面幾行標(biāo)簽:
當(dāng)查找一個(gè)應(yīng)用于頁面的修飾器時(shí),SiteMesh會(huì)首先讀取請(qǐng)求頭部的Accept-Language信息。如果匹配en區(qū)域,SiteMesh會(huì)在修飾器JSP文件名末尾追加-en。在我們的例子里,如果請(qǐng)求定義了修飾器headerfooter.jsp的help.jsp頁面,并且使用的是區(qū)域是英國(guó),SiteMesh會(huì)首先查找并應(yīng)用headerfooter-en.jsp修飾器,如果找不到再去應(yīng)用headerfooter.jsp。 瀏覽器相關(guān)的修飾器 可以使用AgentDecoratorMapper來保證瀏覽器的兼容性:
這意味著當(dāng)SiteMesh查找一個(gè)修飾器來修飾頁面的時(shí)候,會(huì)首先提取出請(qǐng)求頭部的User-Agent信息。如果是IE,就加上-ie到修飾器的文件名末尾,并查找和應(yīng)用這個(gè)修飾器。如果找不到這樣的修飾器,則繼續(xù)應(yīng)用headerfooter.jsp。 高級(jí)SiteMesh SiteMesh提供映射器,讓每一個(gè)頁面參與到尋找自己修飾器的過程中去。 PrintableDecoratorMapper 大多數(shù)的web站點(diǎn)都提供了一個(gè)獲得可打印版本頁面的功能。所謂可打印版本,一般是指去除了頁頭、頁尾和頁邊菜單,并使用了另一套樣式表的頁面。在SiteMesh里,我們可以使用PrintableDecoratorMapper來提供這個(gè)功能。要使用這個(gè)映射器,需要在sitemesh.xml里追加如下幾行:
傳遞給PrintableDecoratorMapper的三個(gè)配置參數(shù)會(huì)被包裝成java.util.Properties對(duì)象傳遞給init()方法。 •decorator 用來生成可打印版本頁面的修飾器名。 •parameter.name 用來通知SiteMesh我們需要一個(gè)可打印版本的請(qǐng)求參數(shù)名。比如在我們的例子里,通過在查詢字符串里追加printable=true參數(shù)傳遞 •parameter.value 設(shè)置可打印參數(shù)為何值時(shí)SiteMesh提供可打印版本的頁面。 PageDecoratorMapper 頁面可以通過定義META屬性來重載指定修飾自己的修飾器名。 要使用這個(gè)映射器,需要在sitemesh.xml文件里加入如下幾行:
PageDecoratorMapper可以獲取一個(gè)參數(shù)列表。在我們的例子里,提供了一個(gè)參數(shù)名,指定了通過META屬性來取得修飾器名。所以如果我們希望使用test修飾器來修飾頁面,則在該頁頭部加入: <META name="decorator" content="test"> PageDecoratorMapper提供了一種靜態(tài)的方法來讓頁面選擇自己想要使用的修飾器。另外,頁面還可以通過使用ParameterDecoratorMapper在運(yùn)行時(shí)指定要使用的修飾器。 ParameterDecoratorMapper 要使用ParameterDecoratorMapper,在sitemesh.xml里追加如下幾行:
三個(gè)參數(shù)的意義分別如下: •decorator.parameter 指定修飾器所使用的請(qǐng)求參數(shù)名。 •parameter.name 確定使用請(qǐng)求修飾器的確認(rèn)參數(shù)名。 •parameter.value 確定使用請(qǐng)求修飾器的確認(rèn)參數(shù)值。 比如,如果你想使用test修飾器來修飾help.jsp,可以像下面這樣訪問help.jsp help.jsp?decorator=test&confirm=true 除了以上這些映射器以外,SiteMesh還提供了更多有用的映射器,比如: •FrameSetDecoratorMapper 當(dāng)頁面是Frame的時(shí)候使用。 •CookieDecoratorMapper 可以通過cookie來指定想要使用的修飾器。 •RobotDecoratorMapper 當(dāng)請(qǐng)求者被確人為robot的時(shí)候使用指定的修飾器。你可以手動(dòng)的在請(qǐng)求頭部追加robot關(guān)鍵字,或者通過修飾器來做。 Velocity 和 Freemarker 修飾器 SiteMesh并沒有限制你只能修飾JSP頁面。你可以自由的選擇想要修飾的對(duì)象,比如Velocity或者Freemarker。Velocity和Freemarker是一種可被用于生成web頁面的模板語言。這些語言比JSP更加的簡(jiǎn)單易用,但在可編程性方面不如JSP靈活。 SiteMesh通過兩個(gè)servlet支持這兩種模板語言,這兩個(gè)servlet也被定義在SiteMesh.jar文件里。我們可以像這樣在web.xml里聲明這兩個(gè)servlet:
當(dāng)然,我們還需要在lib文件夾里引入freemarker.jar、velocity-dep.jar和velocity-tools-view.jar。這些jar文件已經(jīng)包含在SiteMesh的發(fā)布包里了。下面讓我們修改第一個(gè)示例應(yīng)用,使用Velocity和Freemarker修飾器來取代JSP。在我們第一個(gè)示例應(yīng)用里定義了兩個(gè)修飾器:headerfooter和sidemenu。下面我們創(chuàng)建一個(gè)headerfooter.dec:
在這個(gè)頁面里,我們使用Freemarker模板來請(qǐng)求header、footer和title,而不是使用JSP自定義標(biāo)簽,但頁面布局是一樣的。當(dāng)容器接收到一個(gè).dec擴(kuò)展名的頁面請(qǐng)求時(shí),會(huì)把這個(gè)請(qǐng)求傳遞給FreemarkerDecoratorServlet,后者將會(huì)調(diào)用FreemarkerDecorator修飾生成的HTML頁面。我們使用$Advanced SiteMesh模板來訪問應(yīng)用生成的web頁面的title,${head}訪問head,${body}訪問body。Freemarker提供了非常豐富的模板,想深入研究的話可以參考http://www./jw-01-2001/jw-0119-freemarker.html。 相似的,在decorators目錄下創(chuàng)建sidemenu.vm文件,這是Velocity修飾器文件:
使用$title模板取代<decorator:title/>,使用$head和$body Velocity模板來取代相應(yīng)的JSP自定義標(biāo)簽。 結(jié)論 基于過濾器的SiteMesh是一個(gè)非常靈活和簡(jiǎn)單易用的修飾器框架。但它還是存在著一些問題。首先,從Servlet 2.3版本才開始支持過濾器,所以一些早期版本的應(yīng)用服務(wù)器無法支持SiteMesh。在使用SiteMesh之前請(qǐng)先檢查一下您想使用的應(yīng)用服務(wù)器是否支持過濾器。 另外,過濾器只有在使用瀏覽器請(qǐng)求一個(gè)頁面的時(shí)候才能生效。所以,如果你通過瀏覽器訪問home.jsp,它將被修飾,但如果你使用Servlet的RequestDispatcher.include()或者forward()來控制home.jsp,修飾器就不起作用了。但是不用擔(dān)心,從Servlet 2.4版本開始,你可以配置過濾器適用的環(huán)境,包括forward和include的情況下都可以使用了。 |
|
|