SiteMesh 是opensymphony开源组织下一款优秀的Java组件,一般用于页面模板装饰,以减少重复的视图代码为目的。
SiteMesh目前最新版本2.4.1,对HTML页面支持良好,不支持WML页面的装饰。
集成SiteMesh到web application较为简单,在这里假设读者熟悉SiteMesh用于HTML的装饰,如果读者不太了解SiteMesh的用法,请查阅官方相关文档。下面简单列出SiteMesh的使用步骤:
一、SiteMesh用法
1.1 web.xml文件配置过滤器
<!--sitemesh filter-->
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
1.2 配置sitemesh.xml文件
<sitemesh>
<property name="decorators-file" value="/WEB-INF/decorators.xml"/>
<excludes file="${decorators-file}"/>
<page-parsers>
<parser default="true" class="com.opensymphony.module.sitemesh.parser.HTMLPageParser"/>
<parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.HTMLPageParser"/>
<parser content-type="text/html;charset=UTF-8" class="com.opensymphony.module.sitemesh.parser.HTMLPageParser"/>
</page-parsers>
<decorator-mappers>
<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
<param name="property.1" value="meta.decorator" />
<param name="property.2" value="decorator" />
</mapper>
<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
<param name="config" value="${decorators-file}"/>
</mapper>
</decorator-mappers>
</sitemesh>
1.3 decorators.xml 文件
<decorators defaultdir="/view/decorators"> <excludes> <pattern>/resources/*</pattern> </excludes> <decorator name="system" page="system.jsp"/> <decorator name="background" page="background.jsp"/> <decorator name="wml" page="wml.jsp"/> </decorators>
1.4 具体装饰模板
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator"%>
<%@ page pageEncoding="utf-8" %>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<link rel="stylesheet" type="text/css" media="all" href="styles/default/theme.css" />
<script language="javascript" src="scripts/jquery/jquery-min.js"></script>
<decorator:head/>
<title><decorator:title/>|title test</title>
</head>
<body
<decorator:getProperty property="body.id" writeEntireProperty="true"/>
<decorator:getProperty property="body.class" writeEntireProperty="true"/>>
<jsp:include page="/view/common/messages.jsp"/>
<decorator:body/>
<jsp:include page="/view/html/common/footer.jsp"/>
</body>
</html>
1.5 视图页面
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<%@ page language="java" pageEncoding="UTF-8" contentType="text/html;charset=utf-8" %>
<%@ include file="/view/common/taglibs.jsp" %>
<%@ page import="org.apache.shiro.SecurityUtils" %>
<html>
<head>
<meta name="decorator" content="system"/>
<title>bye!</title>
</head>
<body>
XXXXXXXXXXXXXXXX
</body>
</html>
以上是SiteMesh针对HTML页面的用法,下面扩展SiteMesh以实现对WML页面的支持
2扩展SiteMesh以实现对WML页面的支持
2.1 实现com.opensymphony.module.sitemesh.PageParser
package com.wearereading.frameworks.sitemesh.wml;
import java.io.IOException;
import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.PageParser;
import com.opensymphony.module.sitemesh.html.HTMLProcessor;
import com.opensymphony.module.sitemesh.html.State;
import com.opensymphony.module.sitemesh.html.rules.HeadExtractingRule;
import com.opensymphony.module.sitemesh.html.rules.MetaTagRule;
import com.opensymphony.module.sitemesh.html.rules.TitleExtractingRule;
import com.opensymphony.module.sitemesh.html.util.CharArray;
/**
* WML页面解析
* @author Aspen
*
*/
public class WMLPageParser implements PageParser {
public Page parse(char[] data) throws IOException {
CharArray head = new CharArray(64);
CharArray card = new CharArray(4096); //cards TODO 暂只支持一个CARD
TokenizedWMLPage page = new TokenizedWMLPage(data, card, head);
HTMLProcessor processor = new HTMLProcessor(data, card);
State wml = processor.defaultState();
// Core rules for SiteMesh to be functional.
wml.addRule(new HeadExtractingRule(head)); // contents of <head>
wml.addRule(new CardTagRule(page, card)); // contents of <card>
wml.addRule(new TitleExtractingRule(page)); // the <title>
wml.addRule(new MetaTagRule(page)); // all <meta> tags
processor.process();
return page;
}
}
package com.wearereading.frameworks.sitemesh.wml;
import com.opensymphony.module.sitemesh.html.BasicRule;
import com.opensymphony.module.sitemesh.html.Tag;
import com.opensymphony.module.sitemesh.html.rules.PageBuilder;
import com.opensymphony.module.sitemesh.html.util.CharArray;
/**
*
* @author Aspen
*
*/
public class CardTagRule extends BasicRule{
private final PageBuilder page;
private final CharArray card;
public CardTagRule(PageBuilder page, CharArray card) {
super("card");
this.page = page;
this.card = card;
}
public void process(Tag tag) {
if (tag.getType() == Tag.OPEN || tag.getType() == Tag.EMPTY) {
for (int i = 0; i < tag.getAttributeCount(); i++) {
page.addProperty("card." + tag.getAttributeName(i), tag.getAttributeValue(i));
}
card.clear();
} else {
context.pushBuffer(new CharArray(64));
}
}
}
2.2 扩展com.opensymphony.module.sitemesh.Page
package com.wearereading.frameworks.sitemesh.wml;
import java.io.IOException;
import java.io.Writer;
import com.opensymphony.module.sitemesh.Page;
/**
* WML page
* @author Aspen
*
*/
public interface WMLPage extends Page{
/**
* Write the contents of the <code><head></code> tag.
*/
void writeHead(Writer out) throws IOException;
/**
* Convenience method to return the contents of the <code><head></code> tag as a String.
*/
String getHead();
}
package com.wearereading.frameworks.sitemesh.wml;
import java.io.IOException;
import java.io.Writer;
import com.opensymphony.module.sitemesh.parser.AbstractPage;
/**
*
* @author Aspen
*
*/
public abstract class AbstractWMLPage extends AbstractPage implements WMLPage {
public abstract void writeHead(Writer out) throws IOException;
}
package com.wearereading.frameworks.sitemesh.wml;
import java.io.IOException;
import java.io.Writer;
import com.opensymphony.module.sitemesh.html.rules.PageBuilder;
import com.opensymphony.module.sitemesh.html.util.CharArray;
/**
*
* @author Aspen
*
*/
public class TokenizedWMLPage extends AbstractWMLPage implements PageBuilder {
private CharArray[] cards;
private CharArray head;
public TokenizedWMLPage(char[] original, CharArray[] cards, CharArray head) {
this.pageData = original;
this.cards = cards;
this.head = head;
addProperty("title", "");
}
public TokenizedWMLPage(char[] original, CharArray card, CharArray head){
this(original,new CharArray[]{card},head );
}
public void writeHead(Writer out) throws IOException {
out.write(head.toString());
}
public void writeBody(Writer out) throws IOException {
for( int i=0;i<cards.length;i++)
out.write(cards[i].toString());
}
public String getHead() {
return head.toString();
}
public String getBody() {
StringBuffer body = new StringBuffer();
for( int i=0;i<cards.length;i++)
body.append(cards[i].toString());
return body.toString();
}
public String getPage() {
return new String(pageData);
}
}
2.3 CARD标签
package com.wearereading.frameworks.sitemesh.wml;
import com.opensymphony.module.sitemesh.taglib.AbstractTag;
/**
*
* @author Aspen
*
*/
public class CardTag extends AbstractTag {
private static final long serialVersionUID = 1L;
public final int doEndTag() {
try {
getPage().writeBody(getOut());
}
catch (Exception e) {
trace(e);
}
return EVAL_PAGE;
}
}
2.4 扩展SiteMesh 过滤器
package com.wearereading.frameworks.sitemesh.wml;
import javax.servlet.FilterConfig;
import com.opensymphony.module.sitemesh.Config;
import com.opensymphony.module.sitemesh.Factory;
import com.opensymphony.sitemesh.ContentProcessor;
import com.opensymphony.sitemesh.webapp.SiteMeshFilter;
import com.opensymphony.sitemesh.webapp.SiteMeshWebAppContext;
/**
* 扩展支持WML
* @author Aspen
*
*/
public class WMLSupportedSiteMeshFilter extends SiteMeshFilter{
private FilterConfig filterConfig;
public void init(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
super.init(filterConfig);
}
public void destroy() {
filterConfig = null;
super.destroy();
}
protected ContentProcessor initContentProcessor(SiteMeshWebAppContext webAppContext) {
Factory factory = Factory.getInstance(new Config(filterConfig));
factory.refresh();
return new WMLPageParser2ContentProcessor(factory);
}
}
package com.wearereading.frameworks.sitemesh.wml;
import java.io.IOException;
import com.opensymphony.module.sitemesh.Factory;
import com.opensymphony.module.sitemesh.HTMLPage;
import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.PageParser;
import com.opensymphony.module.sitemesh.filter.HttpContentType;
import com.opensymphony.sitemesh.Content;
import com.opensymphony.sitemesh.SiteMeshContext;
import com.opensymphony.sitemesh.compatability.HTMLPage2Content;
import com.opensymphony.sitemesh.compatability.PageParser2ContentProcessor;
/**
*
* @author Aspen
*
*/
public class WMLPageParser2ContentProcessor extends PageParser2ContentProcessor {
private final Factory factory;
public WMLPageParser2ContentProcessor(Factory factory) {
super(factory);
this.factory=factory;
}
public Content build(char[] data, SiteMeshContext context) throws IOException {
HttpContentType httpContentType = new HttpContentType(context.getContentType());
PageParser pageParser = factory.getPageParser(httpContentType.getType());
Page page = pageParser.parse(data);
if( page instanceof WMLPage)
return new WMLPage2Content((WMLPage) page);
return new HTMLPage2Content((HTMLPage) page);
}
}
package com.wearereading.frameworks.sitemesh.wml;
import java.io.IOException;
import java.io.Writer;
import com.opensymphony.sitemesh.Content;
/**
*
* @author Aspen
*
*/
public class WMLPage2Content implements Content {
private final WMLPage page;
public WMLPage2Content( WMLPage page ){
this.page = page;
}
public void writeOriginal(Writer out) throws IOException {
page.writePage(out);
}
public int originalLength() {
return page.getContentLength();
}
public void writeBody(Writer out) throws IOException {
page.writeBody(out);
}
public void writeHead(Writer out) throws IOException {
page.writeHead(out);
}
public String getTitle() {
return page.getTitle();
}
public String getProperty(String name) {
return page.getProperty(name);
}
public String[] getPropertyKeys() {
return page.getPropertyKeys();
}
public void addProperty(String name, String value) {
page.addProperty(name, value);
}
}
SiteMesh支持装饰HTML和WML的用法
需要上传的附件(sitemesh-2.4.1-wml-0.9.jar),你也可以使用上述源代码。
3.1 web.xml
<!--sitemesh filter--> <filter> <filter-name>sitemesh</filter-name> <filter-class>com.wearereading.frameworks.sitemesh.wml.WMLSupportedSiteMeshFilter</filter-class> </filter> <filter-mapping> <filter-name>sitemesh</filter-name> <url-pattern>/*</url-pattern> <dispatcher>FORWARD</dispatcher> <dispatcher>REQUEST</dispatcher> </filter-mapping>
3.2 sitemesh.xml
<sitemesh> <property name="decorators-file" value="/WEB-INF/decorators.xml"/> <excludes file="${decorators-file}"/> <page-parsers> <parser default="true" class="com.opensymphony.module.sitemesh.parser.HTMLPageParser"/> < parser content-type="text/vnd.wap.wml" class="com.wearereading.frameworks.sitemesh.wml.WMLPageParser"/> <parser content-type="text/vnd.wap.wml;charset=UTF-8" class="com.wearereading.frameworks.sitemesh.wml.WMLPageParser"/> <parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.HTMLPageParser"/> <parser content-type="text/html;charset=UTF-8" class="com.opensymphony.module.sitemesh.parser.HTMLPageParser"/> </page-parsers> <decorator-mappers> <mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper"> <param name="property.1" value="meta.decorator" /> <param name="property.2" value="decorator" /> </mapper> <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper"> <param name="config" value="${decorators-file}"/> </mapper> </decorator-mappers> </sitemesh>
3.3 装饰模板
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <%@ page contentType="text/vnd.wap.wml;charset=UTF-8"%> <%@ taglib uri="http://www.wearereading.com/frameworks/sitemesh/wml/decorator" prefix="wml-decorator"%> <wml> <head> <decorator:head/> <meta name="keyword" content="WAP"/> </head> <card <decorator:getProperty property="card.id" writeEntireProperty="true" /> <decorator:getProperty property="card.title" writeEntireProperty="true"/>> <jsp:include page="/view/wml/common/header.jsp" /> <wml-decorator:card/> <jsp:include page="/view/wml/common/footer.jsp" /> </card> </wml>