一、SiteMesh項目簡介

      OS(OpenSymphony)的SiteMesh是一個用來在JSP中實現頁面布局和裝飾(layout and decoration)
的框架組件,能夠幫助網站開發人員較容易實現頁面中動態內容和靜態裝飾外觀的分離。

       Sitemesh是由一個基于Web頁面布局、裝飾以及與現存Web應用整合的框架。它能幫助我們在由大
量頁面構成的項目中創建一致的頁面布局和外觀,如一致的導航條,一致的banner,一致的版權,等等。
它不僅僅能處理動態的內容,如jsp,php,asp等產生的內容,它也能處理靜態的內容,如htm的內容,
使得它的內容也符合你的頁面結構的要求。甚至于它能將HTML文件象include那樣將該文件作為一個面板
的形式嵌入到別的文件中去。所有的這些,都是GOF的Decorator模式的最生動的實現。盡管它是由java語言來實現的,但它能與其他Web應用很好地集成。

       官方:http://www.opensymphony.com/sitemesh/

       下載地址:http://www.opensymphony.com/sitemesh/download.action 目前的最新版本是Version 2.3

二、為什么要使用SiteMesh?

    
我們的團隊開發J2EE應用的時候,經常會碰到一個比較頭疼的問題:

         
由于Web頁面是由不同的人所開發,所以開發出來的界面通常是千奇百怪,通常讓項目管理人員苦笑不得。

     
而實際上,任何一個項目都會要求界面的統一風格和美觀,既然風格統一,那就說明UI層肯定有很多可以抽出來
共用的靜態或動態部分;如何整合這些通用的靜態或動態UI呢?Apache Tiles框架站了出來很好的解決了這一問題,
再加上他與struts的完美集成,導致大小項目都把他作為UI層的首選框架,

但是

   Tiles確實有著它很多的不足之處,下文我會介紹,本文想說的是,除了Apache Tiles框架,其實我們還有更好的解
決方案,那就是:
SiteMesh;

本文

   
   介紹了一個基于Web頁面的布局、裝飾以及應用整合的框架Sitemesh,它能幫助你為你的應用創建一致的外觀,
很好的取代Apache Tiles;

三、SiteMesh VS Apache Tiles

     用過struts的朋友應該對Apache Tiles的不會陌生,我曾經有一篇文章介紹過struts中tiles框架的組合與繼承
現在怎么看怎么覺得復雜;
      
       從使用角度來看,Tiles似乎是Sitemesh標簽<page:applyDecorator>的一個翻版。其實sitemesh最強的
一個特性是sitemesh將decorator模式用在過濾器上。任何需要被裝飾的頁面都不知道它要被誰裝飾,所以它就
可以用來裝璜來自php、asp
、CGI等產生的頁面了。你可以定義若干個裝飾器,根據參數動態地選擇裝飾器,
產生動態的外觀以滿足你的需求。它也有一套功能強大的屬性體系,它能幫助你構建功能強大而靈活的裝飾器。
相比較而言,在這方面Tiles就遜色許多。

       個人覺得在團隊開發里面,Apache Tiles框架會導致所有人不僅僅要了解并且清楚Apache Tiles的存在,
并且要特別熟悉每一個Tiles layout模板的作用,否則就可能出現用錯模板的情況;除此之外,每個人涉及到
的所有WEB頁面都需要去配置文件里面逐個配置,不僅麻煩出錯的幾率還高;
       而以上所有的不足都是SiteMesh所不存在的;


四、SiteMesh的基本原理

      一個請求到服務器后,如果該請求需要sitemesh裝飾,服務器先解釋被請求的資源,然后根據配置文件
獲得用于該請求的裝飾器,最后用裝飾器裝飾被請求資源,將結果一同返回給客戶端瀏覽器。


五、如何使用SiteMesh

   這里以struts2+spring2+hibernate3構架的系統為例
     1、下載SiteMesh
          下載地址:http://www.opensymphony.com/sitemesh/download.action 目前的最新版本是Version 2.3
      
        2、在工程中引入SiteMesh的必要jar包,和struts2-sitemesh-plugin-2.0.8.jar;
      
       3、修改你的web.xml,在里面加入sitemesh的過濾器,示例代碼如下:
         

<!-- sitemesh配置 -->
    
<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>/*</url-pattern>
    
</filter-mapping>

 

      

         注意過濾器的位置:應該在struts2的org.apache.struts2.dispatcher.FilterDispatcher過濾器之前org.apache.struts2.dispatcher.ActionContextCleanUp過濾器之后,否則會有問題;

       4、在下載的SiteMesh包中找到sitemesh.xml,(\sitemesh-2.3\src\example-webapp\WEB-INF目錄下就有)

         將其拷貝到/WEB-INF目錄下;

       5、在sitemesh.xml文件中有一個property結點(如下),該結點指定了decorators.xml在工程中的位置,讓sitemesh.xml能找到他;
按照此路徑新建decorators.xml文件,當然這個路徑你可以任意改變,只要property結點的value值與其匹配就行;

 


<property name="decorators-file" value="/WEB-INF/sitemesh/decorators.xml"/>

 

    
      6、在WebRoot目錄下新建decorators目錄,并在該目錄下新建一個模板jsp,根據具體項目風格編輯該模板,
如下示例:我的模板:main.jsp

 

<%@ page language="java" pageEncoding="UTF-8"%>
<%@taglib prefix="decorator"
     uri
="http://www.opensymphony.com/sitemesh/decorator"%>
<%@taglib prefix="page" uri="http://www.opensymphony.com/sitemesh/page"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<%
     response.setHeader(
"Pragma", "no-cache");
     response.setHeader(
"Cache-Control", "no-cache");
     response.setDateHeader(
"Expires", 0);
%>
<html>
    
<head>
        
<title><decorator:title default="kangxm test" />
        
</title>
        
<!-- 頁面Head由引用模板的子頁面來替換 -->
        
<decorator:head />
    
</head>
    
<body id="page-home">
        
<div id="page-total">
            
<div id="page-header">
                
<table width="100%" border="0" cellspacing="0" cellpadding="0">
                    
<tr>
                        
<td>
                            
<div class="topFunc">
                                 我的賬戶
                                 |
                                 退出
                            
</div>
                        
</td>
                    
</tr>
                
</table>
            
</div>
        
</div>
        
<!-- end header -->
        
<!--   Menu Tag begin -->
        
<div id="page-menu" style="margin-top: 8px; margin-bottom: 8px;">
            
<div>
                 這里放菜單
            
</div>
        
</div>
        
<!--   Menu Tag end -->
        
<div id="page-content" class="clearfix">
            
<center>
                
<table width="100%" border="0" cellpadding="0" cellspacing="0">
                    
<tr>
                        
<td>
                            
<decorator:body /><!-- 這里的內容由引用模板的子頁面來替換 -->
                        
</td>
                    
</tr>
                
</table>
            
</center>
        
</div>
        
<!-- end content -->
        
<div id="page-footer" class="clearfix">

             這里放頁面底部
            
<!-- end footer -->
        
</div>
        
<!-- end page -->
    
</body>
</html>

 


這就是個簡單的模板,頁面的頭和腳都由模板里的靜態HTML決定了,主頁面區域用的是<decorator:body />標簽;
也就是說凡是能進入過濾器的請求生成的頁面都會默認加上模板上的頭和腳,然后頁面自身的內容將自動放到<decorator:body />標簽所在位置;

<decorator:title default="Welcome to test sitemesh!" />:讀取被裝飾頁面的標題,并給出了默認標題。
<decorator:head />:讀取被裝飾頁面的<head>中的內容;
<decorator:body />:讀取被裝飾頁面的<body>中的內容;

      7、說到這里大家就要想了,那如果某個特殊的需求請求路徑在過濾器的范圍內,但又不想使用模板怎么辦?
你總不能這么不講道理吧!
         大家放心吧,SiteMesh早就考慮到這一點了,上面第5步說道的decorators.xml這個時候就起到作用了!
        
下面是我的decorators.xml:

 

<?xml version="1.0" encoding="ISO-8859-1"?>
<decorators defaultdir="/decorators">
    
<!-- Any urls that are excluded will never be decorated by Sitemesh -->
    
<excludes>
        
<pattern>/index.jsp*</pattern>
          <pattern>/login/*</pattern>
    
</excludes>
    
<decorator name="main" page="main.jsp">
        
<pattern>/*</pattern>
    
</decorator>
</decorators>

 


decorators.xml有兩個主要的結點:
       decorator結點指定了模板的位置和文件名,通過pattern來指定哪些路徑引用哪個模板
       excludes結點則指定了哪些路徑的請求不使用任何模板

如上面代碼,/index.jsp和凡是以/login/開頭的請求路徑一律不使用模板;

另外還有一點要注意的是:decorators結點的defaultdir屬性指定了模板文件存放的目錄;

六、實戰感受

      剛剛做完一個用到sitemesh的項目,跟以前用tiles框架相比,最大的感受就是簡單,系統設計階段
就把模板文件和sitemesh框架搭好了!哪些頁面使用框架哪些不使用,全部都通過UI Demo很快就定義出來了;
在接下來的開發中所有成員幾乎感受不到sitemesh的存在,各自僅僅關心自己的模塊功能實現;

七、總結

    使用sitemesh給我們帶來的是不僅僅是頁面結構問題,它的出現讓我們有更多的時間去關注底層業務
邏輯,而不是整個頁面的風格和結構。它讓我們擺脫了大量用include方式復用頁面尷尬局面,也避免了tiles
框架在團隊開發中的復雜度,它還提供了很大的靈活性以及給我們提供了整合異構Web系統頁面的一種方案。