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>
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>
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>
标签`<sitemesh:write property='...'/>`将会被 SiteMesh 重写,用来包含从『被装饰页面』(content page)中提取到的值。可以从被装饰页面(content page)中提取更多的属性,并且可以自定义规则 。
在WEB应用程序中创建`/decorator.html`,其中包含:
```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>
在这个例子中,装饰页面是一个静态的.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>
像装饰页面一样,被装饰页面可以是静态文件,也可以是由 Servlet 引擎动态生成(例如JSP)。
5、配置
SiteMesh 配置支持两种方法 : XML 或 Java。
5.1、XML方式
在工程的 /WEB-INF/sitemesh3.xml中添加以下设置:
<sitemesh>
<mapping path="/*" decorator="/decorator.html"/>
</sitemesh>
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](https://my.oschina.net/u/1162528)
protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
builder.addDecoratorPath("/*", "/decorator.html");
}
}
既然使用 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>
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>
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>
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](https://my.oschina.net/u/1162528)
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());
}
}
其中自定义标签类格式如下:
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](https://my.oschina.net/u/1162528)
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](https://my.oschina.net/u/1162528)
public void cleanUp(State defaultState, ContentProperty contentProperty, SiteMeshContext siteMeshContext) {
}
}
在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>
<dispatcher>这个元素有四个可能的值:即 REQUEST、FORWARD、INCLUDE 和 ERROR,这个元素使得 filter 将会作用于直接从客户端过来的request,通过 forward 过来的 request,通过 include 过来的 request 和通过<error-page>过来的 request。如果没有指定任何K元素,默认值是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>
内容页面(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>
效果:
效果页面源码:
<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>