你还在不断地include 公用css,公用js,公用的页头,页尾吗?还在这样重复劳动嘛,那就让sitemesh让我们偷懒吧.
1.Sitemesh简介
Sitemesh是由一个基于Web页面布局、装饰以及与现存Web应用整合的框架。它能帮助我们在由大量页面构成的项目中创建一致的页面布局和外观,
如一致的导航条,一致的banner,一致的版权,等等。它是运用Decorator模式的生动的实现页面的装饰.
2.Decorator
Sitemesh运用了Decorator模式.先来了解下Decorator模式的运行机制.
Decorator定义:
动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活.
为什么使用Decorator?
我们通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的.
我们有一个只输出的body的BodyPrinter,如果我们要加一个页头,那么我们新一个Class,叫HeadClass,继承BodyPrinter,在新Class中加上页头.如果再要加一个页尾,那我们要一个新的Class来继承HeadClass.那还要加页尾呢,再继承地?再加再继承?那就会每一个不同的组合都会形成一种Class.系统会不会复杂了呢?那我们就用Decorato模式搞定.
public class TestDecorator {
//抽象类,每个装饰类都要继承它.也可以用interface
private abstract class Component{
public abstract void print();
}
//输出body.最原始的被装饰对象
private class BodyPrinter extends Component{
@Override
public void print() {
System.out.println("it is body!");
}
}
//装饰上header
private class HeaderPrinter extends Component{
private Component component;
public HeaderPrinter(Component com){
this.component=com;
}
@Override
public void print() {
System.out.println("it is head");
component.print();
}
}
//装饰上footer
private class FooterPrinter extends Component{
private Component component;
public FooterPrinter(Component com){
this.component=com;
}
@Override
public void print() {
component.print();
System.out.println("it is foot");
}
}
/**
* @param args
*/
public void Test() {
//以这样的方式装修对象,想怎么样装饰就怎么样装饰,灵活多变
Component b = new HeaderPrinter(new FooterPrinter(new BodyPrinter()));
b.print();
Component p = new HeaderPrinter(new HeaderPrinter(new BodyPrinter()));
p.print();
}
public static void main(String[] args){
TestDecorator t= new TestDecorator();
t.Test();
}
}
sitemesh的修饰机制就是运用了Decorator模式.其主要体现在DecoratorMapper上.要我们来看看.
3.sitemesh实现的效果
4.sitemesh 装饰流程
filter:和配置相应的url进入filter,进行装饰
pageParse: 当struts返回页面时,pageParse对页面解析成对象Page.page中的含有head,title,body,等属性
Page:struts返回页面的另一种表面形式
DecoratorMapper:确定什么样的方式来装饰页面,多种DecoratorMapper运用Decorator模式来动态装饰.
Decorator:确定以什么方式来装饰后,就开始装饰了.
View:装饰完了.
5.相应的配置文件:
web.xml:
<?xml version="1.0" encoding="UTF-8"?> <!-- 如果在Decorators.xml中配置的装饰页面中,要取得struts的ActionContext的值时,要配置这个filter.看其原代码, 在request中设置了一个计数值.如果值为零了就会清除actionContext --> <filter> <filter-name>strutscleanup</filter-name> <filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp </filter-class> </filter> <!-- freemarker 装饰页面用freemarkerPageFilter;jsp,html页面用PageFilter--> <filter> <filter-name>sitemesh</filter-name> <!-- <filter-class>org.apache.struts2.sitemesh.FreeMarkerPageFilter</filter-class> --> <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>strutscleanup</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping> <filter-mapping> <filter-name>sitemesh</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping> <filter-mapping> <filter-name>struts</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping> <!-- 如果Struts的result Type是freemarker的,要在freemaker页面中运用jsp标签,struts标签,就要配置下一个servlet --> <servlet> <servlet-name>JspSupportServlet</servlet-name> <servlet-class>org.apache.struts2.views.JspSupportServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet>
Sitemesh.xml:
<?xml version="1.0" encoding="UTF-8"?> <!-- 如果有请求不用sitemesh来装饰,就就来配置这个哦.excludes相应的url--> <property name="decorators-file" value="/WEB-INF/decorators.xml" /> <excludes file="${decorators-file}" /> <!-- 从struts返回的页面解析到page对象--> <page-parsers> <parser default="true" class="com.opensymphony.module.sitemesh.parser.DefaultPageParser" /> <parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" /> </page-parsers> <!-- sitemesh的核心.选择什么样来装饰页面.sitemesh启动的时候,会预先加载.会从下往上加载,由Decorator模式我们知道,下面的是上面的父类,所以在装饰的时候,会从下面的mapper往上装饰 --> <decorator-mappers> <!--通过参数来决定用什么装饰器,如果有参数,那个最下面的mapper就失效--> <mapper class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper"> <param name="decorator" value="printable" /> <param name="parameter.name" value="printable" /> <param name="parameter.value" value="true" /> </mapper> <!--根据语言会在原模板文件名上加了"-en","-zh",从而改变模板的文件名.当然可能会出现"-ie-zh",这样的形式--> <mapper class="com.opensymphony.module.sitemesh.mapper.LanguageDecoratorMapper"> <param name="match.en" value="en" /> <param name="match.zh" value="zh" /> </mapper> <!--根据浏览器类型在原模板文件名上加上"-ie","-zh", --> <mapper class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper"> <param name="match.MSIE" value="ie" /> <param name="match.Mozilla" value="ns" /> <param name="match.Opera" value="opera" /> <param name="match.Lynx" value="lynx" /> </mapper> <mapper class="com.opensymphony.module.sitemesh.mapper.RobotDecoratorMapper"> <param name="decorator" value="robot" /> </mapper> <!--通过参数来决定用什么装饰器,如果有参数,那个最下面的mapper就失效--> <mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper"> <param name="decorator.parameter" value="decorator" /> <param name="parameter.name" value="confirm" /> <param name="parameter.value" value="true" /> </mapper> <mapper class="com.opensymphony.module.sitemesh.mapper.FileDecoratorMapper"> </mapper> <!-- 不同的url不同的装饰页面--> <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper"> <param name="config" value="/WEB-INF/decorators.xml" /> </mapper> </decorator-mappers>
Decorators.xml:
<excludes> <pattern>/exclude/exclude.do</pattern> <pattern>/example/exclude.do</pattern> </excludes> <decorator name="main" page="main.jsp"> <pattern>/example/*.do</pattern> </decorator>
6注意点:
Decorator 模式 运用在DecoratorMapper,注意mapper的顺序,下面是的上面的父亲
在模板中运用ActionContext 内容
模板如果用freemarker,filter 作一个相应的修改FreemarkerFilter
模板是运用的缓存
有请求不用sitemesh,exclude
7:sitemesh和freemarker结合
1.web.xml中修改为freemarkerFilter
2.strtus.xml中action的result type="freemarker"
3.freemaker个人觉得不错的特点.
速度好.robbin也说过"freemarker性能绝对没问题.其实view就不知道了"
关于freemarker的${name},这样的形式,如果name为空就会出现黄黄的错误提示.个人觉得这个的出错提示,可以保证在view中展现的饱满度,而不会出现空信息的情况.
freemaker中引用宏,宏是一个可以把页面结构做成函数的样式,重复利用.
usermacro.ftl:
<#macro greet mes="greet"> <font size="2">${mes}</font> <#nested> </#macro>
my.ftl:
<#include "/example/usermacro.ftl" > <#assign ss=JspTaglibs["/WEB-INF/tld/struts-tags.tld"] /> <html> <head> <title>this is title</title> this is head </head> <body> <h2> <@greet>this is nested</@greet><br> <@ss.property value="message"/> </h2> </body> </html>