最近在读《Struts2权威指南》(李刚著),这本书写得非常好,对我学习Struts2帮助很大。在学习这本书的过程中,我自己做了些笔记和例子,下面是关于在Struts2中如何使用SiteMesh插件:
通过使用SiteMesh插件,就可以在Struts2应用中使用SiteMesh装饰器页面来统一应用程序所有页面的显示风格。实际上,在Struts2中使用SiteMesh非常简单,因为Struts2将所有的值都保存在Stack Context或ValueStack中,因此在SiteMesh页面中使用Struts2的标准标签即可。
1 安装SiteMesh插件
与整合其他框架类似,Struts2与SiteMesh框架的整合也使用了插件方式进行管理,因此为了在Struts2中使用SiteMesh的页面装饰,必须安装SiteMesh插件。安装SiteMesh插件非常简单,将Struts2下的struts2-sitemesh-plugin-2.0.6.jar文件复制到Web应用的根路径下,即可完成SiteMesh插件的安装。
正如前面看到的,为了整合SiteMesh框架必须在web.xml文件中配置SiteMesh的核心过滤器,让该核心过滤器来过滤所有的用户请求。但我们知道,Struts2的所有值是保存在Stack Context或者ValueStack中的,默认情况是,某个过滤器一旦访问了该Stack Context或ValueStack后,里面对应的值将会被清除掉,如果先使用Struts2的FilterDispatcher来过滤用户请求,则SiteMesh的过滤器将无法取得Stack Context或者ValueStack中的数据。
为了解决整个问题,Struts2提供了ActionContextCleanUp类。在Struts2的架构中,标准的过滤器链(filter-chain)一般以 ActionContextCleanUp 开始,后面跟着其他需要的过滤器,最后,由 FilterDispatcher来处理请求,FilterDispatcher通常是将请求传递给ActionMapper。
ActionContextCleanUp 的一个重要作用是整合SiteMesh页面装饰器,它通知FilterDispatcher在正确的时间清楚ActionContext中的请求数据。
注意:如果需要在SiteMesh的修饰器页面中访问ActionContext,ActionContextCleanUp 过滤器必须放在过滤器链的起点。
ActionContextCleanUp过滤器用来与FilterDispatcher协同工作来整合SiteMesh,通常,我们会把把ActionContextUp过滤器排在第一位,似乎将FilterDispatcher排在第二位是较好解决方案。
但问题是:ActionContextCleanUp过滤器只能保证在FilterDispatcher之前先不清除Stack Context和ValueStack中的值。如果将SiteMesh过滤器排在FilterDispatcher之后,这会导致SiteMesh过滤器无法访问到Stack Context和ValueStack中的值。
因此,为了让SiteMesh过滤器和FilterDispatcher都可访问到Stack Context和ValueStack中的值,且FilterDispatcher可以在合适时机清除Stack Context和ValueStack中的值,应该使用如下的过滤器顺序:
(1)ActionContextCleanUp过滤器。
(2)SiteMesh核心过滤器。
(3)FilterDispatcher过滤器。
为此,在web.xml配置文件中使用如下三个过滤器,且过滤器的排列顺序也不能改变。
<!-- 定义ActionContextCleanUp过滤器 -->
<filter>
<filter-name>struts-cleanup</filter-name>
<filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
</filter>
<!-- 定义SiteMesh的核心过滤器 -->
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
<!-- 定义Struts2的核心过滤器 -->
<filter>
<filter-name>struts</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<!-- 定义过滤器链 -->
<!-- 排在第一位的过滤器是:ActionContextCleanUp过滤器。 -->
<filter-mapping>
<filter-name>struts-cleanup</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 排在第二位的过滤器是:SiteMesh核心过滤器。 -->
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 排在第三位的过滤器是:FilterDispatcher过滤器。 -->
<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
正如前面配置文件看到的,配置文件中定义了三个过滤器,这三个过滤器都会过滤所有的用户请求。这三个过滤器按顺序分别是:ActionContextCleanUp过滤器、SiteMesh核心过滤器和FilterDispatcher过滤器,这也正是前面分析的过滤器排列结果。
2 在Struts2中使用SiteMesh
一旦完成了SiteMesh插件的安装后,在Struts2应用中使用SiteMesh就变得非常简单了。
安装了SiteMesh插件后,在Struts2中使用SiteMesh框架可以按如下步骤进行:
(1)将SiteMesh的二进制JAR文件复制到Web应用的的WEB-INF/lib路径下。
(2)定义装饰器页面。
(3)通过decorators.xml文件来配置装饰器页面。
下面以MyFaces+Struts2+Spring的整合应用为基础,并且使用装饰器来装饰该应用。
实际上,这里所介绍的步骤可以为任何一个Web应用增加统一的页面装饰风格,为一个Web应用增加统一的页面装饰风格按如下步骤进行:
(1)正如前面介绍的,将SiteMesh的二进制文件,也就是sitemesh-2.3.jar文件复制到Web应用的WEB-INF/lib路径下,再将Struts2的SiteMesh插件文件,也就是struts2-sitemesh-plugin-2.0.6.jar文件复制到Web应用的WEB-INF/lib路径下。
(2)修改web.xml文件,增加ActionContextCleanUp过滤器定义和SiteMesh的PageFilter过滤器定义,修改后的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">
<!-- 定义ActionContextCleanUp过滤器 -->
<filter>
<filter-name>struts-cleanup</filter-name>
<filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
</filter>
<!-- 定义SiteMesh的核心过滤器 -->
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
<!-- 定义Struts2的核心过滤器 -->
<filter>
<filter-name>struts</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<!-- 定义过滤器链 -->
<!-- 排在第一位的过滤器是:ActionContextCleanUp过滤器。 -->
<filter-mapping>
<filter-name>struts-cleanup</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 排在第二位的过滤器是:SiteMesh核心过滤器。 -->
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 排在第三位的过滤器是:FilterDispatcher过滤器。 -->
<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 定义一个Listener,该Listener在应用启动时创建Spring容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 定义一个Listener,该Listener在应用启动时加载MyFaces的Context -->
<listener>
<listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
</listener>
<!-- 配置JSF的FacesServlet,让其在应用启动时加载 -->
<servlet>
<servlet-name>faces</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 让FacesServlet拦截所有以*.action结尾的请求 -->
<servlet-mapping>
<servlet-name>faces</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
经过上面的配置,已经增加了SiteMesh的支持。
(3)定义装饰器页面。
(4)增加装饰器定义文件,也就是在Web应用的WEB-INF/路径下下增加decorators.xml。
经过上面四个步骤,在浏览器中访问当前Web应用:struts2sitemesh-jsp,可以看到如图15.10所示的页面