最近項目用到SiteMesh3,研究學習一段時間后決定寫篇博文來記錄收獲。
SiteMesh
介紹
SiteMesh 是一個網頁布局和修飾的框架,利用它可以將網頁的內容和頁面結構分離,以達到頁面結構共享的目的。
Sitemesh是由一個基於Web頁面布局、裝飾以及與現存Web應用整合的框架。它能幫助我們在由大量頁面構成的項目中創建一致的頁面布局和外觀,如一致的導航條,一致的banner,一致的版權,等等。它不僅僅能處理動態的內容,如jsp,php,asp等產生的內容,它也能處理靜態的內容,如htm的內容,使得它的內容也符合你的頁面結構的要求。甚至於它能將HTML文件象include那樣將該文件作為一個面板的形式嵌入到別的文件中去。所有的這些,都是GOF的Decorator模式的最生動的實現。盡管它是由java語言來實現的,但它能與其他Web應用很好地集成。
下圖是SiteMesh的結構圖

工作原理
SiteMesh是基於Servlet的filter的,即過濾流。它是通過截取response,並進行裝飾后再交付給客戶。
其中涉及到兩個名詞: 裝飾頁面(decorator page)和 被裝飾頁面(Content page), 即 SiteMesh通過對Content Page的裝飾,最終得到頁面布局和外觀一致的頁面,並返回給客戶。
運行SiteMesh3至少需要:
- JDK 1.5
- 一個Servlet 2.5兼容容器
- SiteMesh運行時庫
配置及使用
下載
wiki上的下載鏈接為:http://wiki.sitemesh.org/wiki/display/sitemesh3/Home
GitHub上3.0.1版本下載地址為(含demo):https://github.com/sitemesh/sitemesh3/releases/tag/3.0.1
1、添加maven依賴
pom.xml文件添加以下依賴:
<!--sitemesh--> <dependency> <groupId>org.sitemesh</groupId> <artifactId>sitemesh</artifactId> <version>3.0.1</version> </dependency>
- 1
- 2
- 3
- 4
- 5
- 6
2、web.xml中添加SiteMesh過濾器
<web-app> ... <filter> <filter-name>sitemesh</filter-name> <filter-class>org.sitemesh.config.ConfigurableSiteMeshFilter</filter-class> </filter> <filter-mapping> <filter-name>sitemesh</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
3、創建一個“裝飾頁面”(decorator page)
該裝飾頁面包含Web應用程序中常見得布局和樣式,它是一個包含<title>
,<head>
和<body>
元素的模板。它至少要包含:
<HTML> <HEAD> <title> <sitemesh:write property ='title'/> </ title> <sitemesh:write property ='head'/> </HEAD> <BODY> <sitemesh:write property ='body'/> </BODY> </HTML>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
標簽<sitemesh:write property='...'/>
將會被SiteMesh重寫,用來包含從“被裝飾頁面”(content page)中提取到的值。可以從被裝飾頁面”(content page)中提取更多的屬性,並且可以自定義規則 。
在WEB應用程序中創建/decorator.html,其中包含:
<html> <head> <title>SiteMesh example: <sitemesh:write property='title'>Title goes here</sitemesh:write></title> <style type='text/css'> body { font-family: arial, sans-serif; background-color: #ffffcc; } h1, h2, h3, h4 { text-align: center; background-color: #ccffcc; border-top: 1px solid #66ff66; } .disclaimer { text-align: center; border-top: 1px solid #cccccc; margin-top: 40px; color: #666666; font-size: smaller; } </style> <sitemesh:write property='head'/> </head> <body> <h1 class='title'>SiteMesh example site: <sitemesh:write property='title'>Title goes here</sitemesh:write></h1> <sitemesh:write property='body'>Body goes here. Blah blah blah.</sitemesh:write> <div class='disclaimer'>Site disclaimer. This is an example.</div> <div class='navigation'> <b>Examples:</b> [<a href="./">Static example</a>] [<a href="demo.jsp">Dynamic example</a>] </div> </body> </html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
在這個例子中,裝飾頁面是一個靜態的.html文件,但是如果你希望用動態頁面,那么可以使用諸如JSP,FreeMarker等技術。
4、創建一個“被裝飾頁面”(content page)
<html> <head> <title>Hello World</title> </head> <body> <p>Well hello there, fine world.</p> <p>And so concludes this <b>SiteMesh</b> example.</p> <h2>How it works</h2> <ul> <li>This page (<code>/index.html</code>) contains vanilla HTML content.</li> <li>SiteMesh is configured (in <code>/WEB-INF/web.xml</code>) to apply a decorator to all paths (<code>/*</code>).</li> <li>The decorator (<code>/decorator.html</code>) contains the common look and feel that is applied to the site.</li> </ul> </body> </html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
像裝飾頁面一樣,被裝飾頁面可以是靜態文件,也可以是由Servlet引擎動態生成(例如JSP)。
5、配置
SiteMesh配置支持兩種方法 : XML或Java。
5.1、XML方式
在工程的 /WEB-INF/sitemesh3.xml中添加以下設置:
<sitemesh> <mapping path="/*" decorator="/decorator.html"/> </sitemesh>
- 1
- 2
- 3
5.1、Java方式
要使用Java的配置方式,自定義的SitMesh過濾器需要繼承org.sitemesh.config.ConfigurableSiteMeshFilter
並重寫applyCustomConfiguration(SiteMeshFilterBuilder builder)
方法。
具體如下:
package com.wangxiaoan1234; import org.sitemesh.builder.SiteMeshFilterBuilder; import org.sitemesh.config.ConfigurableSiteMeshFilter; public class MySiteMeshFilter extends ConfigurableSiteMeshFilter { @Override protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) { builder.addDecoratorPath("/*", "/decorator.html"); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
既然使用Java配置方式,就不再需要sitemesh3.xml文件,但是在web.xml中要使用自己重寫的SiteMesh過濾器。
即web.xml的設置改成如下所示:
<filter> <filter-name>sitemesh</filter-name> <filter-class>com.wangxiaoan1234.MySiteMeshFilter</filter-class> </filter> <filter-mapping> <filter-name>sitemesh</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
6、查看效果
本地查看內容頁面.html效果如下:
通過SiteMesh3裝飾后訪問效果如下:
查看該效果頁面源代碼如下:
<html> <head> <title>SiteMesh example: Hello World (Dynamic)</title> <style type='text/css'> body { font-family: arial, sans-serif; background-color: #ffffcc; } h1, h2, h3, h4 { text-align: center; background-color: #ccffcc; border-top: 1px solid #66ff66; } .disclaimer { text-align: center; border-top: 1px solid #cccccc; margin-top: 40px; color: #666666; font-size: smaller; } </style> <style type='text/css'> .date { font-weight: bold; padding: 10px; font-size: larger; } </style> </head> <body> <h1 class='title'>SiteMesh example site: Hello World (Dynamic)</h1> <p>This page demonstrates that dynamic content can be decorated in the same way as static content.</p> <p>This is a simple JSP that shows the date and time on the server is now:</p> <div class='date'>Tue Aug 15 14:25:41 CST 2017</div> <p>Of course, with SiteMesh you are not limited to JSP. Because it's a Servlet Filter, both content and decorators can be generated by any technology in your ServletEngine, including: static files, JSP, Velocity, FreeMarker, JSF, MVC frameworks, JRuby.... you get the point.</p> <div class='disclaimer'>Site disclaimer. This is an example.</div> <div class='navigation'> <b>Examples:</b> [<a href="./">Static example</a>] [<a href="demo.jsp">Dynamic example</a>] </div> </body> </html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
7、高級配置
7.1、XML形式配置
sitemesh3.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?> <sitemesh> <!--默認情況下,sitemesh 只對 HTTP 響應頭中 Content-Type 為 text/html 的類型進行攔截和裝飾,我們可以添加更多的 mime 類型--> <mime-type>text/html</mime-type> <mime-type>application/vnd.wap.xhtml+xml</mime-type> <mime-type>application/xhtml+xml</mime-type> <!-- 默認裝飾器,當下面的路徑都不匹配時,啟用該裝飾器進行裝飾 --> <mapping decorator="/default-decorator.html"/> <!--不同的匹配路徑采用不同的裝飾頁面--> <mapping path="/admin/*" decorator="/another-decorator.html"/> <mapping path="/*.special.jsp" decorator="/special-decorator.html"/> <!--一個匹配路徑同時采用不同的裝飾頁面--> <mapping> <path>/articles/*</path> <decorator>/decorators/article.html</decorator> <decorator>/decorators/two-page-layout.html</decorator> <decorator>/decorators/common.html</decorator> </mapping> <!-- 滿足該匹配路徑將不被裝飾 --> <mapping path="/login.htm" exclue="true" /> <!-- 自定義標簽 --> <content-processor> <tag-rule-bundle class="com.something.CssCompressingBundle" /> <tag-rule-bundle class="com.something.LinkRewritingBundle"/> </content-processor> </sitemesh>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
7.2、Java形式配置
對應Java配置如下(同理還是在web.xml中引用自己的SiteMesh過濾器):
package com.wangxiaoan1234; import org.sitemesh.builder.SiteMeshFilterBuilder; import org.sitemesh.config.ConfigurableSiteMeshFilter; public class MySiteMeshFilter extends ConfigurableSiteMeshFilter { @Override protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) { //默認裝飾器,當下面的路徑都不匹配時,啟用該裝飾器進行裝飾 builder.addDecoratorPath("/*", "/decorator.html") //添加更多的 mime 類型 .setMimeTypes("text / html","application / xhtml + xml","application / vnd.wap.xhtml + xml") //不同匹配路徑采用不同的裝飾頁面 .addDecoratorPath("/admin/*", "/another-decorator.html") .addDecoratorPath("/*.special.jsp", "/special-decorator.html") //一個匹配路徑同時采用不同的裝飾頁面 .addDecoratorPaths("/articles/*", "/decorators/article.html", "/decoratos/two-page-layout.html", "/decorators/common.html") //滿足該匹配路徑將不被裝飾 .addExcludedPath("/javadoc/*") //添加自定義標簽 .addTagRuleBundle(new CssTagRuleBundle()); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
其中自定義標簽類格式如下:
package com.wangxiaoan1234; import org.sitemesh.SiteMeshContext; import org.sitemesh.content.ContentProperty; import org.sitemesh.content.tagrules.TagRuleBundle; import org.sitemesh.content.tagrules.html.ExportTagToContentRule; import org.sitemesh.tagprocessor.State; /** * 自定義標簽 */ public class CssTagRuleBundle implements TagRuleBundle { @Override public void install(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) { defaultState.addRule("my-css", new ExportTagToContentRule(siteMeshContext, contentProperty.getChild("my-css"), false)); defaultState.addRule("my-footer", new ExportTagToContentRule(siteMeshContext, contentProperty.getChild("my-footer"), false)); } @Override public void cleanUp(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) { } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
在web.xml中還可以指定請求來源:
<filter> <filter-name>sitemesh</filter-name> <filter-class>com.wangxiaoan1234.MySiteMeshFilter</filter-class> </filter> <filter-mapping> <filter-name>sitemesh</filter-name> <url-pattern>/*</url-pattern> <dispatcher>FORWARD</dispatcher> <dispatcher>REQUEST</dispatcher> </filter-mapping>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
<dispatcher>
這個元素有四個可能的值:即REQUEST
、FORWARD
、INCLUDE
和ERROR
,這個元素使得filter將會作用於直接從客戶端過來的request,通過forward過來的request,通過include過來的request和通過<error-page>
過來的request。如果沒有指定任何<dispatcher>
元素,默認值是REQUEST
。
自定義標簽的使用:
裝飾頁面(decorator):
<html> <head> <title>SiteMesh example: <sitemesh:write property='title'>Title goes here</sitemesh:write></title> <style> <sitemesh:write property='my-css'/> </style> <sitemesh:write property='head'/> </head> <body> <div> <p>pppppppppppppppppppppp</p> </div> <siteMesh:write property='my-footer'/> </body> </html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
內容頁面(content):
<html> <head> <title>Hello World</title> <my-css> div p { color : red; } </my-css> </head> <body> <p>Well hello there, fine world.</p> <p>And so concludes this <b>SiteMesh</b> example.</p> <my-footer> <div style="text-align: center"> ©wangxiaoan1234.com </div> </my-footer> </body> </html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
效果:
效果頁面源碼:
<html> <head> <title>SiteMesh example: Hello World</title> <style> div p { color : red; } </style> </head> <body> <div> <p>pppppppppppppppppppppp</p> </div> <div style="text-align: center"> ©wangxiaoan1234.com </div> </body> </html>