1.安装sitemesh插件
与整合其他框架类似,struts2与sitemesh框架的整合也使用了插件方式进行管理 。将struts2-sitemesh-plugin-2.0.6.jar文件复制到WEB-INF/lib下,为了整合sitemesh框架,必须在web.xml中配置sitemesh过滤器,让该核心过滤器来过滤所有的用户请求。但我们知道,struts2的所有值一旦访问该stack context或ValueStack后,里面对应的数值将会被清除掉,如果先使用了struts2的FilterDispather来过滤用户请求,则sitemesh的过滤器将无法取得Stack context或者ValueStack中的数据
为了解决这个问题,struts2提供了ActionContextCleanUp类,在struts2的架构中,标准的过滤器一般以ActionContextCleanUp开始,后面跟着其他需要的过滤器,最后,由FilterDispatcher来处理请求,FilterDispatcher通常是将请求传递给ActionMapper
ActionContextCleanUp的一个重要作用是整合sitemesh页面装饰器,它通知FilterDispatcher在正确的时间清除ActionContext中的请求数据,所以正确的排序如下:
(1)ActionContextCleanUp过滤器
(2)SiteMesh核心过滤器
(3)FilterDispatcher过滤器
web.xml
<?
xml version="1.0" encoding="GBK"
?>
<
web-app
id
="jsf"
version
="2.4"
xmlns
="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
>
<!--
��struts2�ܹ��У����Ĺ�����tһ����ActionContextCleanUp��ʼ���������������Ҫ�Ĺ����������FilterDispatcher��������
-->
<
filter
>
<
filter-name
>
struts-cleanup
</
filter-name
>
<
filter-class
>
org.apache.struts2.dispatcher.ActionContextCleanUp
</
filter-class
>
</
filter
>
<
filter
>
<
filter-name
>
sitemesh
</
filter-name
>
<
filter-class
>
com.opensymphony.module.sitemesh.filter.PageFilter
</
filter-class
>
</
filter
>
<
filter
>
<
filter-name
>
struts
</
filter-name
>
<
filter-class
>
org.apache.struts2.dispatcher.FilterDispatcher
</
filter-class
>
</
filter
>

<
filter-mapping
>
<
filter-name
>
struts-cleanup
</
filter-name
>
<
url-pattern
>
/*
</
url-pattern
>
</
filter-mapping
>
<
filter-mapping
>
<
filter-name
>
sitemesh
</
filter-name
>
<
url-pattern
>
/*
</
url-pattern
>
</
filter-mapping
>
<
filter-mapping
>
<
filter-name
>
struts
</
filter-name
>
<
url-pattern
>
/*
</
url-pattern
>
</
filter-mapping
>

<
listener
>
<
listener-class
>
org.springframework.web.context.ContextLoaderListener
</
listener-class
>
</
listener
>

<
listener
>
<
listener-class
>
org.apache.myfaces.webapp.StartupServletContextListener
</
listener-class
>
</
listener
>
<!--
JavaServer Faces Servlet Configuration, not used directly
-->
<
servlet
>
<
servlet-name
>
faces
</
servlet-name
>
<
servlet-class
>
javax.faces.webapp.FacesServlet
</
servlet-class
>
<
load-on-startup
>
1
</
load-on-startup
>
</
servlet
>

<!--
JavaServer Faces Servlet Mapping, not called directly
-->
<
servlet-mapping
>
<
servlet-name
>
faces
</
servlet-name
>
<
url-pattern
>
*.action
</
url-pattern
>
</
servlet-mapping
>

</
web-app
>
spring配置文件
<?
xml version="1.0" encoding="GBK"
?>
<!--
指定Spring配置文件的Schema信息
-->
<
beans
xmlns
="http://www.springframework.org/schema/beans"
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
>

<
bean
id
="bs"
class
="lee.service.BookService"
/>

</
beans
>

sitemesh装饰配置文件
<?
xml version="1.0" encoding="GBK"
?>

<
decorators
defaultdir
="/decorators"
>
<!--
在excludes元素下指定的页面将不会由SiteMesh来装饰
-->
<
excludes
>
<
pattern
>
/exclude.jsp
</
pattern
>
<
pattern
>
/exclude/*
</
pattern
>
</
excludes
>

<!--
创建一个名为main的装饰器,该装饰器页面为main.jsp,
用于装饰pattern指定的URL的所有页面
-->
<
decorator
name
="main"
page
="main.jsp"
>
<
pattern
>
/*
</
pattern
>
</
decorator
>

<!--
定义一个装饰器,但该装饰器默认不装饰任何页面
-->
<
decorator
name
="panel"
page
="panel.jsp"
/>
</
decorators
>
装饰器decorators/main.jsp
<%
...
@ page contentType="text/html; charset=GBK"
%>

<%
...
@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator"
%>

<%
...
@ taglib uri="http://www.opensymphony.com/sitemesh/page" prefix="page"
%>
<
html
>
<
head
>
<
title
><
decorator:title
default
="SiteMesh的装饰器页"
/></
title
>
<
link
href
="decorators/main.css"
rel
="stylesheet"
type
="text/css"
>
<
decorator:head
/>
</
head
>
<
body
>
<
table
width
="100%"
height
="100%"
>
<
tr
>
<
td
valign
="top"
>
<!--
引入一个页面,临时指定所用的装饰器
-->
<
page:applyDecorator
page
="/book.html"
name
="panel"
/>
<
page:applyDecorator
page
="/link.html"
name
="panel"
/>
</
td
>
<
td
width
="100%"
>
<
table
width
="100%"
height
="100%"
>
<
tr
>
<
td
id
="pageTitle"
>
<
decorator:title
/>
</
td
>
</
tr
>
<
tr
>
<
td
valign
="top"
height
="100%"
>
<
decorator:body
/>
</
td
>
</
tr
>
<
tr
>
<
td
id
="footer"
>
<
b
>
被包含的内容
</
b
><
br
>
SithMesh提供页面装饰支持
</
td
>
</
tr
>
</
table
>
</
td
>
</
tr
>
</
table
>
</
body
>
</
html
>
装饰器decorators/panel.jsp
<%
...
@ page contentType="text/html; charset=GBK"
%>

<%
...
@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator"
%>
<
p
>
<
table
width
=250
border
=0
cellpadding
=0
cellspacing
=0
>
<
tr
>
<
th
class
="panelTitle"
>
<
decorator:title
default
="小面板页面"
/>
</
th
>
</
tr
>
<
tr
>
<
td
class
="panelBody"
>
<
decorator:body
/>
</
td
>
</
tr
>
</
table
>
</
p
>

装饰器样式decorators/main.css
body, td, p {
font: normal x-small verdana, arial, helvetica, sans-serif;
}

.panelTitle {
background-color: #003399;
color:#eeeeee;
font-weight: bold;
border-color: #3366ff #000033 #000033 #3366ff;
border-width: 1;
border-style: solid;
padding: 1;
}

.panelBody {
background-color: #eeeeee;
border-color: black;
border-width: 0 1 1 1;
border-style: solid;
padding: 2;
}

#pageTitle {
background-color: #003399;
color:#eeeeee;
font-weight: bold;
font-size: large;
border-color: #3366ff #000033 #000033 #3366ff;
border-width: 1;
border-style: solid;
padding: 1;
text-align: center;
}

#footer {
background-color:#eeeeee;
font-size: 9pt;
text-align: center;
color: black;
border-color: #666666 #cccccc #cccccc #666666;
border-width: 1;
border-style: solid;
padding: 1;
}

被装饰页面book.html
<
html
>
<
head
>
<
title
>
作者图书
</
title
>
</
head
>
<
body
>
<
center
>
Spring2.0宝典
<
br
>
轻量级J2EE企业应用实战
<
br
>
基于J2EE的Ajax宝典
</
center
>
</
body
>
</
html
>
被装饰页面link.html
<
html
>
<
head
>
<
title
>
友情链接
</
title
>
</
head
>
<
body
>
<
center
>
<
a
href
="http://www.nit-pro.org"
>
NIT-PRO考试中心
</
a
><
br
>
<
a
href
="http://www.oneedu.cn"
>
新东方IT培训中心
</
a
><
br
>
<
a
href
="http://www.oneedu.cn"
>
东方标准人才服务公司
</
a
><
br
>
</
center
>
</
body
>
</
html
>
JSF功能页面list.jsp
<%
...
@ page language="java" contentType="text/html; charset=GBK"
%>

<%
...
@ taglib prefix="f" uri="http://java.sun.com/jsf/core"
%>

<%
...
@ taglib prefix="h" uri="http://java.sun.com/jsf/html"
%>
<
html
>
<
head
>
<
title
>
Struts2+MyFaces+Spring整合
</
title
>
</
head
>
<
body
>
<
f:view
>
<
h3
>
Struts2+MyFaces+Spring整合
</
h3
>
<
h3
>
列出所有图书
</
h3
>
<
h:dataTable
value
="#{action.allBook}"
var
="b"
style
="text-align:center;width:500px"
border
="1"
>
<
h:column
>
<
f:facet
name
="header"
>
<
h:outputText
value
="图书ID"
/>
</
f:facet
>
<
h:outputLink
value
="edit.action"
>
<
f:param
name
="editId"
value
="#{b.id}"
/>
<
h:outputText
value
="#{b.id}"
/>
</
h:outputLink
>
</
h:column
>
<
h:column
>
<
f:facet
name
="header"
>
<
h:outputText
value
="图书名"
/>
</
f:facet
>
<
h:outputText
value
="#{b.name}"
/>
</
h:column
>
<
h:column
>
<
f:facet
name
="header"
>
<
h:outputText
value
="图书简介"
/>
</
f:facet
>
<
h:outputText
value
="#{b.desc}"
/>
</
h:column
>
</
h:dataTable
>
<
p
>
<
h:outputLink
value
="edit.action"
>
<
h:outputText
value
="新增图书"
/>
</
h:outputLink
>
</
p
>
</
f:view
>
</
body
>
</
html
>
JSF功能页面edit.jsp
<%
...
@ page language="java" contentType="text/html; charset=GBK"
%>

<%
...
@ taglib prefix="f" uri="http://java.sun.com/jsf/core"
%>

<%
...
@ taglib prefix="h" uri="http://java.sun.com/jsf/html"
%>
<
html
>
<
head
>
<
title
>
Struts2+MyFaces+Spring整合
</
title
>
</
head
>
<
body
>
<
f:view
>
<
h3
>
Struts2+MyFaces+Spring整合
</
h3
>
<
h3
>
修改/保存图书
</
h3
>
<
h:form
>
<
h:inputHidden
value
="#{action.editId}"
/>
<
h:panelGrid
columns
="3"
>
<
h:outputText
value
="图书ID"
/>
<
h:inputText
id
="id"
size
="5"
value
="#{action.currentBook.id}"
required
="true"
/>
<
h:message
for
="id"
/>
<
h:outputText
value
="图书名:"
/>
<
h:inputText
id
="name"
size
="30"
value
="#{action.currentBook.name}"
required
="true"
>
<
f:validateLength
minimum
="2"
maximum
="100"
/>
</
h:inputText
>
<
h:message
for
="name"
/>
<
h:outputText
value
="图书描述:"
/>
<
h:inputText
id
="desc"
size
="30"
value
="#{action.currentBook.desc}"
required
="true"
>
<
f:validateLength
minimum
="2"
maximum
="100"
/>
</
h:inputText
>
<
h:message
for
="desc"
/>
</
h:panelGrid
>
<
h:commandButton
value
="保存"
action
="#{action.save}"
/>
<
br
/>
</
h:form
>
</
f:view
>
</
body
>
</
html
>
struts.xml
<?
xml version="1.0" encoding="GBK"
?>
<!
DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd"
>

<
struts
>
<
constant
name
="struts.custom.i18n.resources"
value
="messageResource"
/>
<
constant
name
="struts.i18n.encoding"
value
="GBK"
/>

<
package
name
="jsf"
extends
="jsf-default"
>
<
interceptors
>
<
interceptor-stack
name
="jsfFullStack"
>
<
interceptor-ref
name
="params"
/>
<
interceptor-ref
name
="basicStack"
/>
<
interceptor-ref
name
="jsfStack"
/>
</
interceptor-stack
>
</
interceptors
>
<
default-interceptor-ref
name
="jsfFullStack"
/>
</
package
>
<
package
name
="lee"
extends
="jsf"
>
<
action
name
="list"
class
="lee.action.BookAction"
>
<
result
name
="success"
type
="jsf"
/>
</
action
>
<
action
name
="edit"
class
="lee.action.BookAction"
>
<
result
name
="success"
type
="jsf"
/>
<
result
name
="list"
type
="redirect"
>
list.action
</
result
>
</
action
>
</
package
>

</
struts
>
BookService
package
lee.service;

import
java.util.
*
;
import
lee.model.Book;

public
class
BookService

...
{
private Set<Book> bookDb;

public BookService()

...{
bookDb = new HashSet<Book>();
bookDb.add(new Book(1 , "Spring2.0宝典" , "全面介绍了Spring各个知识点"));
bookDb.add(new Book(2 , "轻量级J2EE企业应用实战" , "介绍实际企业的J2EE开发过程"));
}

public Set<Book> getAllBook()

...{
return bookDb;
}

public Book getBookById(int id)

...{
for (Book b : bookDb)

...{
if (b.getId() == id)

...{
return b;
}
}
return null;
}


public void addBook(Book b)

...{
bookDb.add(b);
}
}
Book
package
lee.model;


public
class
Book

...
{
private int id;
private String name;
private String desc;

public Book()

...{
}

public Book(int id , String name ,String desc)

...{
this.id = id;
this.name = name;
this.desc = desc;
}

public void setId(int id)

...{
this.id = id;
}
public int getId()

...{
return this.id;
}

public void setName(String name)

...{
this.name = name;
}
public String getName()

...{
return this.name;
}

public void setDesc(String desc)

...{
this.desc = desc;
}
public String getDesc()

...{
return this.desc;
}

public int hashCode()

...{
return id;
}
public boolean equals(Object target)

...{
if (target instanceof Book)

...{
Book b = (Book)target;
if (b.getId() == this.id)

...{
return true;
}
}
return false;
}
}
BookAction
package lee.action;

import com.opensymphony.xwork2.ActionSupport;

import java.util.*;
import lee.model.Book;
import lee.service.BookService;

public class BookAction extends ActionSupport
{
private Book currentBook;
private int editId;

private BookService bs;
public void setBs(BookService bs)
{
this.bs = bs;
}

public void setCurrentBook(Book currentBook)
{
this.currentBook = currentBook;
}
public Book getCurrentBook()
{
//如果editId请求参数不为空,则currentBook也不为空
if (editId != 0)
{
this.currentBook = bs.getBookById(editId);
}
else if (currentBook == null)
{
currentBook = new Book();
}
return this.currentBook;
}

public void setEditId(int editId)
{
this.editId = editId;
}
public int getEditId()
{
return this.editId;
}

public List
<
Book
>
getAllBook()
{
List
<
Book
>
result = new ArrayList
<
Book
>
();
for (Book b : bs.getAllBook())
{
result.add(b);
}
return result;
}

public String save()
{
bs.addBook(currentBook);
return "list";
}

}
struts.properties
struts.i18n.encoding=gb2312
struts.objectFactory.spring.autoWire=type
如果web应用是test.,则运行
http://localhost:8080/test/list.action 则会出现如下被装饰过的页面
