一、sitemesh功能简介
Sitemesh是由一个基于Web页面布局、装饰以及与现存Web应用整合的框架。它能帮助我们在由大量页面构成的项目中创建一致的页面布局和外观,如一致的导航条,一致的banner,一致的版权,等等。
它不仅仅能处理动态的内容,如jsp,php,asp等产生的内容,它也能处理静态的内容,如htm的内容,使得它的内容也符合你的页面结构的要求。甚至于它能将HTML文件象include那样将该文件作为一个面板的形式嵌入到别的文件中去。所有的这些,都是GOF的Decorator模式的最生动的实现。尽管它是由java语言来实现的,但它能与其他Web应用很好地集成。
二、应用实例
以struts-2.3.18.1为例:
1、Eclipse中新建一个Dynamic Web Project,命名为StrutsDemo。
2、将Struts中相关的包放入项目的WebContent\WEB-INF\lib目录(依赖包如下图所示),或者在构建路径中进行相关配置 。
3、在web.xml配置struts和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>
<!-- Struts 配置-->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern><!--拦截所有的请求,也可以选择以下两个url匹配规则-->
<url-pattern>*.action</url-pattern><!--拦截action后缀请求-->
<url-pattern>*.do</url-pattern><!--拦截do后缀请求-->
</filter-mapping>
4、配置struts配置文件struts.xml(本项目路径:resource\struts.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" />
<!--
<constant name="struts.action.extension" value="action" />
<constant name="struts.action.extension" value="do" />
-->
<constant name="struts.action.extension" value="action,do" /><!-- 同时支持*.do, *.action两种后缀名的请求 -->
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<global-results>
<result name="error">/error.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="error"/>
</global-exception-mappings>
<action name="index">
<result type="redirectAction">
<param name="actionName">HelloWorld</param>
<param name="namespace">/example</param>
</result>
</action>
<action name="*" class="demo.presentation.action.BaseAction">
<result>/{1}.jsp</result>
</action>
</package>
<!--如果有其他配置,可在include节点配置
<include file="example.xml"/>
-->
<!-- Add packages here -->
</struts>
example.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="default">
<action name="HelloWorld" class="demo.presentation.action.HelloWorldAction">
<result>/example/HelloWorld.jsp</result>
</action>
<action name="Login_*" method="{1}" class="demo.presentation.action.LoginAction">
<result name="input">/example/Login.jsp</result>
<result type="redirectAction">Menu</result>
<result name="success" type="dispatcher">/example/main.jsp</result>
</action>
<action name="*Test" method="{1}" class="demo.presentation.action.TestAction">
<result>/example/{1}Test.jsp</result>
</action>
<!--以下为找不到对应的action时,调用默认的action,如访问 http://localhost:8080/StrutsDemo/example/Person.action -->
<action name="*" class="demo.presentation.action.BaseAction">
<result>/example/{1}.jsp</result>
</action>
<!-- Add actions here -->
</package>
</struts>
BaseAction.java
package demo.presentation.action;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.opensymphony.xwork2.ActionSupport;
public class BaseAction extends ActionSupport {
private static final long serialVersionUID = 1864699266509075017L;
public static final Log log = LogFactory.getLog(BaseAction.class);
}
5、从struts官方软件包struts-2.3.28.1-all.zip中,将struts2-showcase.war包中WEB-INF下的sitemesh.xml解压出来,放至StrutsDemo下的WebContent\WEB-INF文件夹下。
(sitemesh.xml在struts-2.3.28.1-all.zip中路径:struts-2.3.28.1-all.zip\struts-2.3.28.1\apps\struts2-showcase.war\WEB-INF\sitemesh.xml)
在sitemesh.xml中已经指定了装饰器的配置文件路径
<!-- decorators-file指定了decorators.xml在的位置 -->
<property name="decorators-file" value="/WEB-INF/decorators.xml"/>
6、建立自己的decorators.xml文件,放入WEB-INF文件夹(也可以修改sitemesh.xml文件中的decorators-file节点的值来另外指定位置)下。以下为一示例
<?xml version="1.0" encoding="utf-8"?>
<!-- decorators结点的defaultdir属性指定了模板文件存放的目录 -->
<decorators defaultdir="/decorators">
<!-- Any urls that are excluded will never be decorated by Sitemesh -->
<!-- excludes结点则指定了哪些路径的请求不使用任何模板 -->
<excludes>
<!--如下, index.jsp、以/login/开头、以/decorators/开头的请求路径不使用模板 -->
<pattern>/index.jsp*</pattern>
<pattern>/login/*</pattern>
<pattern>/decorators/*</pattern>
</excludes>
<!-- decorator结点指定了模板的位置和文件名,通过pattern来指定哪些路径引用哪个模板 -->
<decorator name="main" page="main.jsp">
<pattern>/*</pattern>
</decorator>
</decorators>
7、建立模板文件main.jsp,存放入项目WebContent\decorators目录下。内容如下所示:
<%@ 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">
<html>
<head>
<title>
<decorator:title default="默认HTML页面标题" />
</title>
<!-- decorator:head节点中的内容由引用本模板的页面的<head></head>中的内容来替换 -->
<decorator:head />
</head>
<body>
<!-- decorator:body节点的内容将由引用本模板的页面的<body></body>中的内容来替换-->
<decorator:body />
</body>
</html>
8、新建一个JSP文件,如test.jsp,内容如下所示:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test SiteMeshMe</title>
<style type="text/css">
h1{
font-family: 微软雅黑;
font-size:36px;
}
</style>
</head>
<body>
<!-- body start -->
<h1>Test SiteMesh!</h1>
<!-- body end -->
</body>
</html>
9、右键点击StrutsDemo项目,通过Run As\Run On Server启动web服务器。
10、访问http://localhost:8080/StrutsDemo/test.jsp观察页面的变化情况。页面代码变化如下:
三、深入应用——模板页面嵌套使用
1、在decorators目录下加入panel.jsp文件
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %>
<p>
<table width=250 border=0 cellpadding=0 cellspacing=0>
<tr>
<th class="panelTitle">
<!-- 导入被装饰页面的title部分 -->
<decorator:title default="小面板页面"/>
</th>
</tr>
<tr>
<td class="panelBody">
<!-- 导入被装饰页面的body部分 -->
<decorator:body/>
</td>
</tr>
</table>
</p>
2、修改decorators\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">
<html>
<head>
<title>
<decorator:title default="默认HTML页面标题" />
</title>
<!-- decorator:head节点中的内容由引用本模板的页面的<head></head>中的内容来替换 -->
<decorator:head />
</head>
<body>
<!-- 页面中嵌套包含使用其他装饰页面 -->
<page:applyDecorator page="/decorators/header.jsp" name="panel"/>
<!-- decorator:body节点的内容将由引用本模板的页面的<body></body>中的内容来替换-->
<decorator:body />
<!-- 页面中嵌套包含使用其他装饰页面 -->
<page:applyDecorator page="/decorators/footer.jsp" name="panel"/>
</body>
</html>
3、修改decorators.xml文件
<?xml version="1.0" encoding="utf-8"?>
<!-- decorators结点的defaultdir属性指定了模板文件存放的目录 -->
<decorators defaultdir="/decorators">
<!-- Any urls that are excluded will never be decorated by Sitemesh -->
<!-- excludes结点则指定了哪些路径的请求不使用任何模板 -->
<excludes>
<!--如下, /index.jsp和凡是以/login/开头的请求路径一律不使用模板; -->
<pattern>/index.jsp*</pattern>
<pattern>/login/*</pattern>
<pattern>/decorators/*</pattern>
</excludes>
<!-- decorator结点指定了模板的位置和文件名,通过pattern来指定哪些路径引用哪个模板 -->
<decorator name="main" page="main.jsp">
<pattern>/*</pattern>
</decorator>
<!-- 定义一个装饰器,但该装饰器默认不装饰任何页面 -->
<decorator name="panel" page="panel.jsp"/>
</decorators>
4、添加decorators\header.jsp文件
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>header file
</title>
</head>
<body id="page-home">
<h1>Header</h1>
<hr>
</body>
</html>
5、添加decorators\footer.jsp文件
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>footer file
</title>
</head>
<body id="page-home">
<hr>
<h1>footer</h1>
</body>
</html>
6、执行http://localhost:8080/StrutsDemo/test.action(本文struts.xml配置环境下,test.action或者test.jsp都能正确访问到页面/test.jsp)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>
Test SiteMeshMe
</title>
<!-- decorator:head节点中的内容由引用本模板的页面的<head></head>中的内容来替换 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style type="text/css">
h1{font-family: 微软雅黑;font-size:36px;}
</style>
</head>
<body>
<!-- 页面中嵌套包含使用其他装饰页面 -->
<p>
<table width=250 border=0 cellpadding=0 cellspacing=0>
<tr>
<th class="panelTitle">
<!-- 导入被装饰页面的title部分 -->
header file
</th>
</tr>
<tr>
<td class="panelBody">
<!-- 导入被装饰页面的body部分 -->
<h1>Header</h1>
<hr>
</td>
</tr>
</table>
</p>
<!-- decorator:body节点的内容将由引用本模板的页面的<body></body>中的内容来替换-->
<!-- body start -->
<h1>Test SiteMesh!</h1>
<!-- body end -->
<!-- 页面中嵌套包含使用其他装饰页面 -->
<p>
<table width=250 border=0 cellpadding=0 cellspacing=0>
<tr>
<th class="panelTitle">
<!-- 导入被装饰页面的title部分 -->
footer file
</th>
</tr>
<tr>
<td class="panelBody">
<!-- 导入被装饰页面的body部分 -->
<hr>
<h1>footer</h1>
</td>
</tr>
</table>
</p>
</body>
</html>
7、最终效果