sitemesh notes

sitemesh 是一个布局管理插件,用于 Java Web 工程,由 webwork2 团队开发,目前稳定版本是2.4.2,诞生于2009-04-16,有多年没有更新了,可见还是蛮稳定的。sitemesh3 在2015年发布。sitemesh 官网是:http://wiki.sitemesh.org/wiki/display/sitemesh/Home

sitemesh 是装饰器模式(Decorator Pattern)的一个实现,它的工作原理借用官网的图说明如下:

1. 浏览器发出请求

2. 服务端用模板对目标页面进行装饰

3. 返回用户装饰後的页面

sitemesh workflow

(来源:http://wiki.sitemesh.org/wiki/display/sitemesh/Start+Using+SiteMesh+in+10+Minutes)

sitemesh 可以单独使用,也可以作为 Struts 2 的插件使用,但它们的配置方式是不一样的,特别是在和 Struts 2 集成时,需要修改 Struts 2 的过滤器设置。以下分别叙述。

单独使用

单独使用 sitemesh, 可以使用2.4.2,也可以使用3系列的 alpha 版本,以下都会描述。

1. 添加依赖

为项目加入相应 jar 包,可以直接在官网下载,如果使用 maven.

sitemesh2 相应配置是:

<dependency>
     <groupId>opensymphony</groupId>
     <artifactId>sitemesh</artifactId>
     <version>2.4.2</version>
</dependency>

sitemesh3 相应的配置是:

<!-- https://mvnrepository.com/artifact/org.sitemesh/sitemesh -->
<dependency>
    <groupId>org.sitemesh</groupId>
    <artifactId>sitemesh</artifactId>
    <version>3.0.1</version>
</dependency>

2. 添加过滤器

在 WEB-INF/web.xml 中修改,

sitemesh2:

<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>
</filter-mapping>

sitemesh3:

<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>

3. 设置 Decorator 规则

sitemesh2:

在 WEB-INF 下新增 decorators.xml 文件,示例内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<decorators defaultdir="/jsp/decorator"> 
     <excludes>
          <pattern>/jsp/decorator/*</pattern>
     </excludes>
    <decorator name="main" page="decorator.jsp"> 
        <pattern>/jsp/sys/*</pattern> 
        <pattern>/jsp/tada/*</pattern> 
        <pattern>/tada/*</pattern> 
        <pattern>/sys/*</pattern> 
    </decorator> 
</decorators>

sitemesh3:

在 WEB-INF 下新增 sitemesh3.xml 文件,示例内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<sitemesh>
  <mapping path="/*" decorator="/jsp/decorator/decorator.jsp"/>
  <mapping path="/index.jsp" exclue="true"/>
  <mapping path="/jsp/sys/register.jsp" exclue="true"/>
</sitemesh>

以上两个版本的 decorator 配置文件,都能望文生义,不再解释。

4. Decorator 页面

Decorator 页面通过标签标识要装饰的内容。

sitemesh2 用 <decorator: xxx /> 的方式:

<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<%
     String path = request.getContextPath();
     String basePath = request.getScheme() + "://"
               + request.getServerName() + ":" + request.getServerPort()
               + path + "/";
%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>PIS: <decorator:title /> </title>
<link rel="shortcut icon" href="<%=path%>/favicon.ico" />
<link rel="icon" type="image/gif" href="<%=path%>/animated_favicon1.gif" />
<link href="<%=path%>/css/layout.css" rel="stylesheet" type="text/css" />
<decorator:head/>
</head>
<body>
     <div id="container">
          <div id="top"><%@ include file="top.jsp"%></div>
          <div id="menu"><%@ include file="menu.jsp"%></div>
          <div id="mainContent">
               <div id="sidebar"><%@ include file="left.jsp"%></div>
               <div id="content">
                    <decorator:body />
               </div>
          </div>
          <div id="bottom"><%@ include file="bottom.jsp"%></div>
     </div>
</body>
</html>

sitemeth3 用 <sitemesh:write property='xxx' /> 的方式:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<%
     String path = request.getContextPath();
     String basePath = request.getScheme() + "://"
               + request.getServerName() + ":" + request.getServerPort()
               + path + "/";
%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>PIS: <sitemesh:write property='title' /></title>
<link rel="shortcut icon" href="<%=path%>/favicon.ico" />
<link rel="icon" type="image/gif" href="<%=path%>/animated_favicon1.gif" />
<link href="<%=path%>/css/layout.css" rel="stylesheet" type="text/css" />
<sitemesh:write property='head' />
</head>
<body>
     <div id="container">
          <div id="top"><%@ include file="top.jsp"%></div>
          <div id="menu"><%@ include file="menu.jsp"%></div>
          <div id="mainContent">
               <div id="sidebar"><%@ include file="left.jsp"%></div>
               <div id="content">
                    <sitemesh:write property='body' />
               </div>
          </div>
          <div id="bottom"><%@ include file="bottom.jsp"%></div>
     </div>
</body>
</html>

与 Struts 2 集成

sitemesh 一般以插件方式与 Struts 2 集成,被集成的版本,依赖 Struts 2 的版本,据我观察,目前 Struts 2.16.3 集成的是 sitemesh 2.4.2

1. 【pom.xml dependency】

<dependency>
    <groupId>org.apache.struts</groupId>
    <artifactId>struts2-core</artifactId>
    <version>${struts2.version}</version>
</dependency>

2. 【web.xml filters】

    <filter>
        <filter-name>struts2-prepare</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2-prepare</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <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>
    </filter-mapping>    
    
    <filter>
        <filter-name>struts2-execute</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2-execute</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <listener>
        <listener-class>org.apache.struts2.dispatcher.ng.listener.StrutsListener</listener-class>
    </listener>

参考:

http://struts.apache.org/release/2.3.x/docs/sitemesh-plugin.html

http://struts.apache.org/release/2.3.x/struts2-core/apidocs/index.html?org/apache/struts2/dispatcher/ng/filter/StrutsPrepareAndExecuteFilter.html

这里需要特别注意,Struts 2 的 filter 分成了两个:

  • org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter
  • org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter

并将 sitemesh 的 filter 放置在它们之间。sitemesh 的 filter 所用的类也和前述单独使用的情况不同。

而通常,Struts 2 配置一个 filter 就够了:

  • org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

如果集成 sitemesh 不这样配置 filter,将出现严重的问题:用于装饰的页面中 Struts 2 标签不能使用,并将报500错误。