??xml version="1.0" encoding="utf-8" standalone="yes"?> Q{载)http://www.aygfsteel.com/youxia/archive/2009/02/11/248051.html 在SpringSide 3 中,使用的MVC框架是Struts 2。Struts 2
向对于Struts 1 来说Q具有相当多的优点,有很多h都说Q用qStruts 2之后Q再也不想看Struts
1了。然而,M东西都有它的复杂性,Struts 2也不例外QSpringSide 3做了很多工作来简化Struts 2 的用?br />
?
了,对SpringSide 3中Struts 2的分析就写到q里了。MQ用SpringSide
3Ӟ对于Actionq一块非常简单,如果不设及到CRUD操作Q就l承SimpleActionSupportQ如果涉及到CRUD操作Q就l承
CRUDActionSupportQƈ在getModel()"save()"prepareSave"input()"prepareInput()
{框框中填入适当的代码即可?/p>
]]>
]]>
先来说说Struts 2的特点:
1?
~写Action变得单了QAction变成了简单的POJOQ再也不用和ActionForm、ActionForward打交道了Q返回的时候直?
q回字符串即可。如果要讉KServlet APIQ则直接使用ServletActionContextcȝ静态方法?br />
2、Struts
2提供了插件机Ӟ允许我们自己为它~写插gQ当Ӟ要我自己写是不现实的Q但是面对别人写的琳琅满目的插gQ我一样会昏头。再|上随便一搜,可以发?
40多种Struts 2插g。SpringSide 3选择的CodeBehindQ就是一UStruts 2插gQ它的目的是Z化配|?br />
3、Struts 2提供了拦截器机制Q之所以编写Action的Q务那么简单,靠的都是q些拦截器,比如它们可以自动解析Web表单和URL参数Q把它们注入到Action中?br />
4、Struts 2提供了丰富的taglibQ当Ӟ丰富也代表着我们要化更多的时间去学习?br />
5、Struts 2依然提供了Validator和i18n支持?br />
{等...
下面Q我们来看看SpringSide 3是怎么使用Struts 2的吧。SpringSide 3的主要目标是降低我们使用Struts 2的复杂性,所以,它选择了这些办法:
1、没有用Validator和i18nQ对数据的验证交l了JQueryQ这变成了表现层的Q务,而且JQuery也可以用AJAX从服务器端进行验证。至于i18nQ江南白衣说网站用不上?br />
2、没有用Struts 2的UI标签Q当然也没有用FreeMaker或SiteMesh了?br />
当然Q省掉了一些东西,q掉了我们不少的学习时间。对于Struts 2核心的一些东西,我们看看它是怎么做的Q?br />
1?
使用CodeBehind插g来简化配|。用CodeBehind后,我们可以不用配|result了,它可以根据我们Action的返回D动猜?
q回的视N面,它猜的规则是这LQ返回页面的路径为struts.codebehind.pathPrefix + package
namespace + action name + action returnvalue + .jspQaction
returnvalue为successӞgؓI,为其他时Qgؓ"-" + return type。我们来看看SpringSide
3生成的项目中关于Struts 2的配|文Ӟ
?
中struts.codebehind.pathPrefix讄?#8220;/WEB-INF/jsp/”Qpackage的namespace没有讄Q所
以,如果我们的Action为UserActionQ则q回successӞ׃q回?WEB-INF/jsp/user.jspQ如果返?
inputQ则q回?WEB-INF/jsp/user-input.jsp。这里江南白衣玩了一个狡猾,他把所有的jsp面攑ֈWEB-INF目录
中,别h没有办法直接访问了Q这样就可以化Acegi的配|工作?br />
2、关于拦截器?br />
在上面讲Struts
2的特Ҏ(gu)Q我已经说了Struts
2中拦截器的重要作用,在上面的截图中,package的配|没有做别的什么事Q主要就是配|了拦截器栈。那么拦截器栈是怎么使用的呢Q它是在
ActioncM通过@ParentPackage指定的,如下面的代码Q?br />
下面Q我来具体说一下拦截器有什么作用?br />
例子一、我们知道Struts 2中的Action是和Servlet API解耦的Q那么如果我们要在Action中访问Servlet API怎么办呢Q一U办法就是用ServletActionContextQ如下图Q?br />
另外一U办法,是让我们的Action实现ServletRequestAware接口Q如下代码:
private
HttpServletRequest request;
public
void
setServletRequest(HttpServletRequest request) {
this
.request
=
request;
}
public
String execute()
throws
Exception {
//
do the work using the request
return
Action.SUCCESS;
}
}
例子二?strong>ParametersInterceptor
拦截器会自动解析web表单或URL参数Qƈ把它们注入到Action中。但是很多时候,我们不愿意我们的Actionh太多的属性,因ؓ一大堆?
get、setҎ(gu)看v来太qp,我们希望有一个专门的Model对象来存储这些|而且刚好我们为Hibernate设计的Entitycȝ来做
Model正合适。这Ӟ我们可以让我们的Action实现ModelDriven接口Q让getModel()Ҏ(gu)q回我们的entity对象卛_。这正是SpringSide 3采取的方法,如下囄代码片断Q?br />
q时候,ModelDrivenInterceptor拦截器就会帮助我们把解析的URL参数或表单数据注入到entity的属性中Q而不是Action中?br />
例子三?strong>Preparable 接口联合PrepareInterceptor拦截器一起工作,可以让action在执行execute() Ҏ(gu)前, 执行一个prepare()Ҏ(gu)Q这也正是SpringSide 3的工作方式?br />
3、关于Action
有了上面对CodeBehind的理解和Ҏ(gu)截器栈的理解后,再来理解SpringSide 3中的Action再单不q了QSpringSide 3中Action的承树如下Q?br />
其中ActionSupportcLStruts 2提供的,另外两个cL白衣自己扩展的。其中SimpleActionSupport主要是提供了一些绕qjsp面直接输出字符串的Ҏ(gu)Q不g谈。而CRUDActionSupport比较复杂,如下Q?
/**
* q行CUD操作?以redirect方式重新打开action默认늚result?
*/
public static final String RELOAD = "reload";
/**
* Action函数,默认action函数Q默认指向list函数.
*/
@Override
public String execute() throws Exception {
return list();
}
/**
* Action函数,昄Entity列表.
* return SUCCESS.
*/
public abstract String list() throws Exception;
/**
* Action函数,新增或修改Entity.
* return RELOAD.
*/
public abstract String save() throws Exception;
/**
* Action函数,删除Entity.
* return RELOAD.
*/
public abstract String delete() throws Exception;
/**
* 在save()前执行二ơ绑?
*/
public void prepareSave() throws Exception {
prepareModel();
}
/**
* 在input()前执行二ơ绑?
*/
public void prepareInput() throws Exception {
prepareModel();
}
/**
* 屏蔽公共的二ơ绑?
*/
public void prepare() throws Exception {
}
/**
* {同于prepare()的内部函?
*/
protected abstract void prepareModel() throws Exception;
}
W?
一Q它做了把CRUD操作攑ֈ了同一个Action中的操作Q这样可以少写几个Action。这个工作难度不大,我觉得白衣此举,主要是ؓ了规范CRUD
函数的命名。在Struts
2中,如果我们要访问的不是默认的excuteҎ(gu)Q可以用如/user!save.action的格式,q样讉K的就是UserAction?
saveҎ(gu)?br />
W二Q它实现?strong>ModelDriven接口?strong>Preparable?
口,关于q两个接口,我在前面讲拦截器的时候已l提到过了,所以很Ҏ(gu)理解。我们可以把我们为Hibernate设计的entitycM为ModelQ也
可以把初始化q些entity的工作放到prepareSave()和prepareInput()Ҏ(gu)中,q两个方法将会在save()?
input()Ҏ(gu)执行前自动执行?br />
W三Q它定义了一个静态变量RELOADQ定义这个变量的目的是ؓ了定义一个result的需要。CodeBehind中,大部分的result可以自己猜测Q对于不能猜的Q需要用@Results指定Q如下代码:
]]>
本文是由JRL写作的《J2SEq阶》一书的部分章节整理而成Q《J2SEq阶》正在写作、完善阶Dc?zhn)阅读后,有Q何徏议、批评,?a class="l2" href="mailto:ok_winnerboy@sina.com" target="_blank">和我联系Q或?a ?>http://www.javaresearch.org/forum/thread.jsp?column=376&thread=7576' target='_blank' class='l2'>q儿留言。《J2SEq阶》写作项目组感谢(zhn)阅L文?/u>
在当今这个信息社会,其是随着互联|的出现和普及,Z之间的距L以往M时候都更加接近Q同时交往也更加频J,时下最旉的概念就是地球村Q而我时候只知道我出生的那个乡村。距近Q交往频繁Qh们就不得不考虑如何M各个不同U族、不同区域的Z打交道。对人如此,Ҏ(gu)们的软g亦是如此Q你需要考虑如何让处于世界不同地方的使用者都能够很好C用你的Y件。于是,在每个Y件开始之前,~写者都可能需要考虑q样一个问题——国际化?br />
我们知道Q在Java中可以通过java.util.LocalecL唯一地确定特定语a和国家的l合Q即抽象最l用L使用环境。同时将用户相关的一些信息置于资源包中,通过资源包来动态地获得最l的用户昄。资源包可以p源文件或者资源子cL具体实现?br />
注意Q本文只打算讨论国际化过E中资源包的使用技巧,更多更精彩的内容Q请期待《J2SEq阶》一书?/strong>
资源?/h4>
Q欢q来到Java研究l织|站Q当前时间是Q?u>2003-8-1 16:43:12?/u>
在编写应用程序的时候,需要面对的一个问题是如何来处理与locale相关的一些信息。比如,面上的一些静态文本就希望能够以用户习惯的语言昄。最原始的做法是这些信息硬~码到程序中Q可能是一大串判断语句Q,但是q样将E序代码和易变的locale信息捆绑在一P以后如果需要修改locale信息或者添加其它的locale信息Q你׃得不重新修改代码。而资源包可以帮助你解册个问题,它通过可变的locale信息攑օ资源包中来达C者分ȝ目的。应用程序可以自动地通过当前的locale讄到相应的资源包中取得所要的信息。资源包的概늱gWindows~程人员使用的资源文Ӟrc文gQ?br />
一般来_资源包需要完成两个功能:和具体的localeq行l定以及dlocale相关信息?br />
ResourceBundlec?/h5>
你可以把资源包看作ؓ一个由许多成员Q子c)l成的大家庭Q其中每个成员关联到不同的locale对象Q那它是如何完成兌功能的呢Q?br />
资源包中的每个成员共享一个被UC基名Qbase nameQ的名称Q然后在此基上根据一定的命名规范q行扩展。下面就列出了一些成员的名称Q?br />
LabelResources
LabelResources_de
LabelResources_de_CH
LabelResources_de_CH_UNIX
可见q些子类依据q样的命名规范:baseName_language_country_variantQ其中language{几个变量就是你在构造LocalecL所使用的。而资源包正是通过q个W合命名规范的名U来和localeq行兌的,比如LabelResource_de_CH对应于由d语(deQ和瑞士QCHQ组成的locale对象?br />
当你的应用程序需要查扄定locale对象兌的资源包Ӟ它可以调用ResourceBundle的getBundleҎ(gu)Qƈlocale对象作ؓ参数传入?br />
如果该locale对象匚w的资源包子类找不刎ͼgetBundle试着查找最匚w的一个子cR具体的查找{略是这LQgetBundle使用基名Qlocale对象和缺省的locale来生成一个候选资源包名称序列。如果特定locale对象的语a代码、国家代码和可选变量都是空|则基名是唯一的候选资源包名称。否则的话,具体locale对象Qlanguage1Qcountry1和variant1Q和~省localeQlanguage2Qcountry2和variant2Q将产生如下的序列:
然后QgetBundleҎ(gu)按照产生的序列依ơ查扑配的资源包子cdƈ对结果子cd始化。首先,它将Lcd匚w候选资源包名称的类Q如果找到将创徏该类的一个实例,我们UC为结果资源包。否则,getBundleҎ(gu)寻扑֯应的资源文gQ它通过候选资源包名称来获得资源文件的完整路径Q将其中?#8220;.”替换?#8220;/”Qƈ加上“.properties”后缀Q,如果扑ֈ匚w文gQgetBundleҎ(gu)利用该资源文g来创Z个PropertyResourceBundle实例Q也是最l的l果资源包。与此同ӞgetBundleҎ(gu)会将q些资源包实例缓存v来供以后使用?br />
如果没有扑ֈl果资源包,该方法将抛出MissingResourceException异常。所以ؓ了防止异常的抛出Q一般来说都需要至实C个基名资源包子类?br />
注意Q基名参数必L一个完整的cdUͼ比如LabelResourcesQresource.LabelResources{)Q就相当于你引用一个类旉要指定完整的c\径。但是,Z和以前的版本保持兼容Q在使用PropertyResourceBundles时也允许使用“/”来代?#8220;.”表示路径?/strong>
比如你有以下q些资源cd资源文gQMyResources.classQ?nbsp;MyResources_fr_CH.propertiesQ?nbsp;MyResources_fr_CH.classQ?nbsp;MyResources_fr.propertiesQ?nbsp;MyResources_en.propertiesQ?nbsp;MyResources_es_ES.class。你利用以下的locale讄来调用getBundleҎ(gu)Q你会得到不同的结果资源包Q假讄省locale为Locale(“en”, “UK”)Q,请参考表13.4?br />
?3.4 locale讄与结果资源包
locale讄 l果资源?br />
Locale("fr", "CH") MyResources_fr_CH.class
Locale("fr", "FR") MyResources_fr.properties
Locale("de", "DE") MyResources_en.properties
Locale("en", "US") MyResources_en.properties
Locale("es", "ES") MyResources_es_ES.class
创徏了具体的资源包子cd例以后,需要获得具体的信息。信息在资源包中是以键值对的方式存储的Q表13.5列出的是LabelResources.properties文g的内宏V?br />
?3.5 LabelResources.properties
其中{号左边的字W串表示主键Q它们是唯一的。ؓ了获得主键对应的|你可以调用ResourceBundlecȝgetStringҎ(gu)Qƈ主键作为参数。此外,文g中以“#”号开头的行表C注释行?br />
ListResourceBundle和PropertyResourceBundle子类
抽象cResourceBundleh两个子类QListResourceBundle和PropertyResourceBundleQ它们表C源包子类两种不同的实现方式?br />
PropertyResourceBundle是和资源文g配对使用的,一个属性文件就是一个普通的文本文gQ你只需要ؓ不同的locale讄~写不同名称的资源文件。但是,在资源文件中只能包含字符Ԍ如果需要存储其它类型对象,你可以用ListResourceBundle?br />
ListResourceBundle是将键值对信息保存在类中的列表中,而且你必d现ListResourceBundle的具体子cR?br />
如果ListResourceBundle和PropertyResourceBundle不能够满你的需要,你可以实现自qResourceBundle子类Q你的子cd覆盖两个方法:handleGetObject和getKeys?br />
使用资源文g
使用资源包最单的Ҏ(gu)是利用资源文gQ利用资源文件一般需要以下几个步骤:
1、创Z个缺省的资源文g
Z防止找不到资源文Ӟ你最好实C个缺省的资源文gQ该文g的名UCؓ资源包的基名加上.properties后缀?br />
2、创建所需的资源文?br />
Z准备支持的locale讄~写对应的资源文件?br />
3、设|locale
你必dE序中的某个地方提供locale的设|或者切换功能,或者将其放入配|文件中?br />
4、根据locale讄创徏资源?br />
ResourceBundle resource =
ResourceBundle.getBundle("LabelBundle",currentLocale);
5、通过资源包获取locale相关信息
String value = resource.getString("welcome");
注意Q在使用基名的时候,特别要注意给出完整的cdQ或者\径名Q,比如你的应用E序所在的cd为org.javaresearch.j2seimproved.i18nQ而你的资源文件在你的应用E序下的resource子目录中Q那你的基名应该是org.javaresearch.j2seimproved.i18n.resource.LabelBundleBundle而不是resource.LabelBundleBundle?br />
使用ListResourceBundle
使用ListResourceBundle和用资源文件的步骤基本上一P只不q你需要用ListResourceBundle子类来替换相应的资源文g。比如你的应用程序的基名是LabelBundleQ而且准备支持Locale("en","US")和Locale("zh","CN")Q那你需要提供以下几个Java文gQ注意类名和locale的对应关pR?br />
LabelBundle_en_US.java
LabelBundle_zh_CN.java
LabelBundle.javaQ缺省类Q?br />
代码13.3列出的是LabelBundle_zh_CN.java的源代码Q相对于资源文g?#8220;key = value”的写法,在此文g中你首先利用键值对来初始化一个二l数l,q在getContentsҎ(gu)中返回该数组?br />
代码13.3QLabelBundle_zh_CN.java
创徏完资源类以后Q同样需要设|locale以及Ҏ(gu)locale来创源包。在通过资源包获取具体值的时候,你不能再使用getStringҎ(gu)Q而应该调用getObjectҎ(gu)Q而且׃getObjectҎ(gu)q回一个Object对象Q你q需要进行正的cd转换。其实,Z你的E序通用性,我们在用资源文件的时候你也应该调用getObjectҎ(gu)Q而不是getStringҎ(gu)?br />
关于ListResourceBundle的详l用,可以参考本书所附代码中国际化一节的ListResourceBundleSample.javaE序?br />
MessageFormatc?/h5>
上面我们讲到利用资源文g来分M码和可变的信息。但是在实际q程中,有些信息q不能够完全事先定义好,其中可能会用到运行时的一些结果,最典型例子的就是错误提CZ码,比如提示某个输入必须在一定范围内。利用上面所讲的资源文gq不能够很好地解册个问题,所以Java中引入了MessageFormatcR?br />
MessageFormat提供一U语a无关的方式来l装消息Q它允许你在q行时刻用指定的参数来替换掉消息字符串中的一部分。你可以为MessageFormat定义一个模式,在其中你可以用占位符来表C变化的部分Q比如你有这样一句话Q?br />
(zhn)好Q?u>peachpi
其中斜体带下划线的部分ؓ可变化的Q你需要根据当前时间和不同的登录用h军_最l的昄。我们用占位W来表示q些变化的部分,可以得到下面q个模式Q?br />
(zhn)好Q{0}Q欢q来到Java研究l织|站Q当前时间是Q{1,date} {1,time}?br />
占位W的格式为{ ArgumentIndex , FormatType , FormatStyle }Q详l说明可以参考MessageFormat的API说明文档。这里我们定义了两个占位W,其中的数字对应于传入的参数数l中的烦引,{0}占位W被W一个参数替换,{1}占位W被W二个参数替换,依此cL?br />
最多可以设|?0个占位符Q而且每个占位W可以重复出现多ơ,而且格式可以不同Q比如{1,date}和{1,time}。而通过这些模式定义放C同的资源文g中,p够根据不同的locale讄Q得C同的模式定义Qƈ用参数动态替换占位符?br />
下面我们׃MessageFormatSample.javaE序Q源文g见本书所附代码)ZQ来详细说明其中的每个步骤?br />
1、找出可变的部分Qƈ据此定义模式Q将模式攑օ不同的资源文件中?br />
比如针对上面的模式,定义了下面两个资源文Ӟ
MessagesBundle_en_US.properties
Welcome = Hi, {0}! Welcome to Java Research Organization!
MessagesBundle_zh_CN.properties
Welcome = (zhn)好Q{0}Q欢q来到Java研究l织|站Q?br />
2、创建MessageFormat对象Qƈ讄其locale属性?br />
3、从资源包中得到模式定义Q以及设|参数?br />
4、利用模式定义和参数q行格式化?br />
关于资源包的l织
一般来_你是按照资源的用途来l织资源包的Q比如会把所有的面按钮的信息放入一个名为ButtonResources的资源包中。在实际的应用过E中Q以下几个原则可以帮你决定如何组l资源包Q?br />
1、要易于l护?br />
2、最好不要将所有的信息都放入一个资源包中,因ؓq样资源包蝲入内存时会很耗时?br />
3、最好将一个大的资源包分ؓ几个的资源包,q样可以在用的时候才导入必须的资源,减少内存消耗?
]]>
应用于以下大目的例子:http://opensource.thoughtworks.com/projects/sitemesh.html
介: | ||||||||||
sitemesh应用Decorator模式Q用filter截取request和response,把页面组件head,content,bannerl合Z个完整的视图。通常我们都是用include标签在每个jsp面中来不断的包含各Uheader, stylesheet, scripts and footerQ现在,在sitemesh的帮助下Q我们可以开心的删掉他们了。如下图Q你惌杄辑ֈ复合视图模式Q那末看完本文吧?/font>
|
||||||||||
hello sitemeshQ?/font> | ||||||||||
最后访问index.jspQ将生成如下面Q?/font>
而且Q所有的面也会如同index.jsp一P被sitemesh的filter使用装饰模式修改成如上图般模P却不用再使用include标签?/font> |
装饰?nbsp; decorator概念 | ||||||
建立可复用的web应用E序,一个通用的方法是建立一个分层系l,如同下面一个普通的web应用Q?/font>
可糟p的是前端的面逻辑很难被复用,当你在每一个页面中用数之不的include来复用公qheader, stylesheet, scriptsQfooterӞ一个问题出C-重复的代码,每个面必须用copy来复用页面结构,而当你需要创意性的改变面l构ӞNq上了你?/font> sitemesh通过filter截取request和responseQƈl原始的面加入一定的装饰(可能为header,footer...)Q然后把l果q回l客LQƈ且被装饰的原始页面ƈ不知道sitemesh的装饎ͼq也pCp的目的?/font> 据说卛_新出台的Portlet规范会帮助我们标准的实现比这些更多更cool的想法,但可怜的我还不懂它到底是一个什末东东,有兴的人可以研I?br /> jetspeedQ或JSR (Java Specification Request) 168,但我想sitemesh如此单,我们不妨先用着?/font>
|
||||||
让我们看看怎样配置环境 | ||||||
除了要copy到WEB-INF/lib中的sitemesh.jar, copy到WEB-INF中的sitemesh-decorator.tld,sitemesh-page.tld文g外,q有2个文件要建立到WEB-INF/Q?/font>
sitemesh.xml 可以讄2U信?Page Parsers Q负责读取stream的数据到一个Page对象中以被SiteMesh解析和操作?不太常用Q默认即? Decorator Mappers : 不同的装饰器U类Q我发现2U比较有用都列在下面。一U通用的mapper,可以指定装饰器的配置文g名,另一U可打印的装饰器Q可以允怽当用http://localhost/aaa/a.html?printable=true方式讉K时给出原始页面以供打?免得把header,footer{的花哨的图片也搭上) 范例Q?/strong>
decorators.xml Q定义构成复合视囄所有页面构件的描述(主要l构面Qheader,footer...)Q如下例Q?/font>
|
||||||
最重要的是写出装饰器本w?也就是那些要复用面Q和l构面)?/font> | ||||||
其实Q重要的工作是制作装饰器页面本w?也就是包含结构和规则的页?Q然后把他们描述到decorators.xml中?/font>
让我们来先看一看最单的用法Q其实最常用也最单的用法是我们的hello例子Q面对如此众多的技术,我想只要辑ֈ功能点到为止卛_Q没必要ȝI太?除非(zhn)有更深的需??/font>
我们在装饰器面只用?个标{: <decorator:title default="装饰器页?.." /> Q?把请求的原始面的title内容插入?lt;title></title>中间?/font> <decorator:body /> Q?把请求的原始面的body内的全部内容插入到相应位|?/font> 然后我们在decorator.xml中加入以下描q即可: <decorator name="main" page="main.jsp"> q样Q请求的所有页面都会被重新处理Qƈ按照main.jsp的格式重新展现在你面前?/font>
|
||||||
让我们看看更多的用法?抄袭sitemesh文档) | ||||||
以下列着全部标签Q?/font>
插入原始面(被包装页?的head标签中的内容(不包括head标签本n)?/font> <decorator:body />插入原始面(被包装页?的body标签中的内容?/font> <decorator:title [ default="..." ] /> 插入原始面(被包装页??a name="decorator:title">title标签中的内容Q还可以d一个缺省倹{?/font> 例: /_decorator/main.jsp?Q装饰器面Q? <title><decorator:title default="却省title-hello" /> - 附加标题</title> /aaa.jsp?(原始面)Q?lt;title>aaa面</title> 讉K/aaa.jsp的结果:<title>aaa面 - 附加标题</title> <decorator:getProperty property="..." [ default="..." ] [ writeEntireProperty="..." ]/> 在标{֤插入原始面(被包装页?的原有的标签的属?/font>中的内容Q还可以d一个缺省倹{?/font> sitemesh文档中的例子很好理解Q?/font> 注意Q?/strong> <decorator:usePage id="..." /> 例:可用<decorator:usePage id="page" /> Q?/strong><%= 应用包装器到指定的页面上Q一般用于被包装面中主动应用包装器。这个标{有点不好理解,我们来看一个例子: 包装器页?/_decorators/panel.jspQ?lt;p><decorator:title /></p> ... <p><decorator:body /></p> 最后会是什末结果呢Q除?page.jsp会被默认的包装页面包装上header,footer外,page.jsp面中还内嵌了date.jsp面Qƈ且此date.jsp面q会被panel.jsp包装Z个title加body的有2D늚面Q第1D|date.jsp的titleQ第2D|date.jsp的body内容?/font> 另外Q?a name="page:applyDecorator">page:applyDecorator中包含的page:param标签所声明的属性D可以在包装页面中?/font>decorator:getProperty标签讉K到? |
可打印的界面装饰 | |
前面说过?U可打印的装饰器Q可以允怽当用http://localhost/aaa/a.html?printable=true方式讉KӞ应用其他的装饰器(自己指定)Q给出原始页面以供打?免得把header,footer{的花哨的图片也搭上)?/font>
让我们来看一看怎样实现他: 1.首先在WEB-INFO/sitemesh.xml中设|: 2.在WEB-INFO/decorators.xml中定义相应的printable装饰?br /> <decorator name="printable" page="printable.jsp"/> 3.最后编写printable装饰?decorators/printable.jsp
q样可以让一个原始页面通过?printable=true开x切换不同的装饰器面?/font>
|
中文问题 |
׃sitemesh内部所使用的缺省字W集为iso-8859-1Q直接用会产生qQ我们可以通过以下Ҏ(gu)U正之:
|
ȝQ用sitemesh最通常的途径Q?/font> |
1.配置好环境, 2.在WEB-INFO/decroators.xml中描qC徏立的包装器?/font> 3.开发在decroators.xml中描q的包装器,最好存攑֜/_decorators目录?/font> 4.ok Q可以看看辛勤的成果?: |
Q?a onclick="javascript:tagshow(event, 'sitemesh');" href="javascript:;" target="_self">sitemeshQ一个不错的tiles替代Ҏ(gu)Q比tiles做的更漂亮优雅。本文是sitemesh官方推荐的入门文档,本来惌q译的Q突然发现有人先行一步了Q就转过来看吧?br />
以前我通常使用旧式的方法来建立自己?a onclick="javascript:tagshow(event, 'web');" href="javascript:;" target="_self">web应用Q手工排版,仔细使用每一个字节其工作在Unicode下,同时使用make文g来适应不同的CPU……
或许现在我们可以换一U方式?br />
管我从没有感觉到需要用assembly (CISC or RISC)来徏立web应用Q但也会偶尔觉得我的开发伙伴的工作相当J琐。特别是我发现很多的开发者在痛苦的寻求一U比较好的方式来控制web应用的基本模块:例如那些头、页、导航栏、打印页面、手持设备的轻量U页面,以及其他更多的问题。到了最后,令h惊异的是大部分h都采用了落后的includes和复制粘贴方式?br />
Ҏ(gu)l验Q我可以采用?u>java.net?a onclick="javascript:tagshow(event, '%E5%BC%80%E6%BA%90');" href="javascript:;" target="_self">开?/strong>的servlet qo?a target="_blank">SiteMeshn来简单明了ƈ优雅的解册些问题。作ZU替代新的templating语言QXSLTQ或部v(zhn)的面到新的系l的解决Ҏ(gu)Q应用SiteMesh可以相当Ҏ(gu)处理你的面Q这一切只需要普通的HTMLQJSPQservlet(包括Struts)Q以及其他常用的技术?br />
工作原理SiteMesh利用了一U很h知道的servlet规范实现了一U页面过滤器。设想一下,现在有一个简单的jsp面用来q回当前的日期和旉。通常q个面h来到应用服务器,面被处理,最后处理结果返回到web览器。SiteMesh作ؓ一个页面过滤器Q在面被处理之后,q回web览器之前,寚w面做了一些附加的操作。这个变化简单描qCؓ图一和图二所C的附加步骤?br />
图一Q普通页面处理情?/em>
图二QSiteMesh寚w面处理情?/em>
现在看一个简单的例子?br />
<html>
<head>
<title>Simple Document</title>
</head>
<body>
Hello World! <br />
<%= 1+1 %>
</body>
</html>你会发现q个面有一个title和bodyQ类似普通的HTML面Q。你也会发现一段JSP代码——它?yu)会如同你期望的那样被处理。同时你可以使用M你想使用的JSP语法和特性来替换q一段代码?br />
现在来看一个简单的SiteMesh "装饰QdecoratorQ?面。列?昄了一个被SiteMesh调用的JSP面?br />
<%@ taglib uri="sitemesh-decorator"
prefix="decorator" %>
<html>
<head>
<title>
My Site - <decorator:title default="Welcome!" />
</title>
<decorator:head />
</head>
<body>
<h1><decorator:title default="Welcome!" /></h1>
<p><decorator:body /></p>
<p><small>
(<a
href="?printable=true">printable version</a>
</small></p>
</body>
</html>查看q个装饰器(decoratorQ,我们能看C些有的东西。首先,在第一行申明了一个SiteMesh标签库。这个标{ֺ包含了与原始面一起工作时所需的所有东ѝ你能看到我们用了两个SiteMesh的装饰标{(declared tagsQ,<decorator:body>。不要惊讶于标签<decorator:title>?/font>原始面中显C?font face="Courier New"><title>标签中的内容Q?font face="新宋?><decorator:body>中的内容也是如此。我们在q个面的HEAD和BODY元素都用了同一个title标签。(We're making a few fairly radical changes to the page, including repeating the title both in theBODY. Q同Ӟ我们q增加了一个到可打印版本页面的链接?br />
作ؓ对照Q图三显CZ原始处理面Q图四显CZ被修饰过的处理页面。留意被装饰面在浏览器H口昄的标题文字和HTML内容。同时也可以看到增加了一个可打印面的链接——这个我们回头再说?br />
图三Q原始未修饰面
囑֛Q被修饰面
很明显,Ҏ(gu)起用includeQ例?font face="Courier New"><jsp:include page="foo.jsp" flush="true" />Q来_以这L方式使用头、页l结构要清晰得多。这U方式更易移植、更易理解,同时也鼓׃JSP面不再使用D或其他类似的表现层代码。我发现在JSP面中用装饰器和CSS的组合比标准HTML的标{更Ҏ(gu)去除格式信息?br />
安装SiteMesh注意下面的屏q截图是ZWindows XP ProfessionalQ?a target="_blank">Tomcat 5.0.19Q和Java 2 SDK 1.4.2_03的环境之上的。在q里我假定你的Tomcat已经安装完毕q且可以正常工作了。你或许会有一些淆,但我们已l成功地在Tomcat 4.1 ?WebLogic 试q,同时 SiteMesh 也支持大部分的web应用服务器?br />
本文描述的SiteMesh 2.0.1可以?a target="_blank">下蝲到?在java.net 上SiteMesh's ?a onclick="javascript:tagshow(event, '%E9%A1%B9%E7%9B%AE');" href="javascript:;" target="_self">目库中有四个文件可以下载?em>sitemesh-2.0.1.jar是其核心 JAR 文gQ?em>sitemesh-2.0.1-sources.zip的作用正如同其名字所qͼsitemesh-example.war则提供了一个复杂的例子用来昄一些SiteMesh的高U特性?br />
Z使描q更加简单,我们?a target="_blank">sitemesh-blank.war文g开始。将该WAR文g攑օTomcat ?em>webapps目录QWAR包将自动解压昄内容QSoSo注:q里的前提是你的tomcat已经开始工作)Q如图五所C?br />
图五Q?SiteMesh_blank.WAR解开后的内容
我们q旉描述一下这些文件的作用?br />
web.xml首先Q?em>WEB-INF/web.xml文g昄如列?Q这些语句用来安装SiteMesh qo器和标签库。如果你军_在一个已有的Web应用中用SiteMeshQ你必须把这些语句添加到你的WEB-INF/web.xml文g中?br />
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<!-- Start of SiteMesh stuff -->
<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>*.jsp</url-pattern>
</filter-mapping>
<taglib>
<taglib-uri>sitemesh-page</taglib-uri>
<taglib-location>/WEB-INF/sitemesh-page.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>sitemesh-decorator</taglib-uri>
<taglib-location>/WEB-INF/sitemesh-decorator.tld</taglib-location>
</taglib>
<!-- End of SiteMesh stuff -->
</web-app>注意Q这里需要注意一?font face="新宋?>url-pattern的写?- 如果使用的是Tomcat 5Q而不?Tomcat 4 Q,需要将默认?修改?.jsp的Ş式。最新的servlet规范不再支持*样式?br />
decorators.xmlWEB-INF/decorators.xml文g用来一个装饰器名字同一个专门的JSP装饰文gl定。作Z个例子,q里JSP装饰文gminimal.jsp同一个称为handheld的装饰器l定h?br />
<decorators defaultdir="/decorators">
<decorator name="main" page="main.jsp">
<pattern>*</pattern>
</decorator>
<decorator name="panel" page="panel.jsp"/>
<decorator name="printable" page="printable.jsp"/>
</decorators>正如我们在代码列表里看到的一P我们定义了三个装饰器Q他们分别绑定了三个cM的JSP面。我们可以看C个默认装饰器Qmain.jspQ,它将被默认运用于所有文件?br />
~省的,SiteMesh使用下面的逻辑来选择使用哪一个装饰器Q?
q个逻辑?em>sitemesh-2.0.1.jar包的\com\opensymphony\module\sitemesh\factor\sitemesh-default.xml文g里被描述。你可以针对诸如Q客L操作pȝQweb览器,用户代理{在WEB-INF\sitemesh.xml文g里,通过一个变量覆盖这个行为?You can override this behavior. with a wide variety ofbuilt-in mappersfor things like language, client operating system, web browser/user agent, etc. by creating aWEB-INF\sitemesh.xmlfile. Q可以在sitemesh-example.war扑ֈ例子?br /> |
通常W一条规则仅用来定该装饰器是否被用(Conceptually, the first rule that evaluates to true determines the decorator that is used. Q在上面的例子中Q当出现printable.jspQ规?#3Q替代了www.opensymphony.com/sitemesh/api扑ֈq个库的javadoc?br />
*.tldSiteMesh使用两个标签库,但大多数人都只需?em>sitemesh-decorator.tld。你可以?a target="_blank">www.opensymphony.com/sitemesh/tags.html扑ֈ相应的文档。我们已l讲qC最主要的标{:headQtitle和body。在下一章我们来讨论剩下的标{:getProperty?br />
SiteMesh高Ҏ(gu)SiteMesh的一个重要特性是使用原始HTML的meta标签Q例?font face="Courier New"><meta. name="foo" c>Q从基础面传递信息到装饰器。作Z个例子,下面我们使用一个meta标签来定义HTML面的作者?br />
<html>
<meta. name="author" c>
<head>
<title>Simple Document</title>
</head>
<body>
Hello World! <br />
<%= 1+1 %>
</body>
</html>我们定义一?#8220;smart”装饰器来研究meta标签Q如果出现这个标{,则可以得C个相应的HTMLQ?br />
<%@ taglib uri="sitemesh-decorator" prefix="decorator" %>
<decorator:usePage id="myPage" />
<html>
<head>
<title>My Site -
<decorator:title default="Welcome!" />
</title>
<decorator:head />
</head>
<body>
<h1><decorator:title default="Welcome!" /></h1>
<h3>
<a href="mailto:<decorator:getProperty property="meta.author"
default="staff@example.com" />">
<decorator:getProperty property="meta.author"
default="staff@example.com" />
</a></h3><hr />
<decorator:body />
<p><small>
(<a href="?printable=true">printable version</a>
</small>
</p>
</body>
</html>可以看到我们使用?font face="Courier New">getProperty标签的一个默认属性——如果没有指定authorQ我们就讑֮其ؓstaff。如果你军_使用q个模型储存面的meta数据Q你或许需要和你的开发伙伴一h定用什么标{以及如何用他们。简单的Q你或许惌使用meta标签来描q诸如页面作者及旉戳之cȝ东西。更复杂一些,你或怼惛_XML文g一h准化的管理你的站点导航,同时使用meta标签来通过面节点转到装饰器。(At the complex end, you may do things like standardize on an XML file to manage your site navigation and use a
囑օQmeta标签昄
q些面属性非常强大,q且拥有着很多不同的特性,q不仅止于meta标签Q?a target="_blank">常用面Ҏ(gu)列?/font>Q。用SiteMesh一D|间之后,你就会开始思考HTML和JSP作ؓ一U简单标记语a的机制——接q最原始的HTML——无需操作可以完整的切换到XML/XSL 或其他模版引擎?br />
结lg所qͼSiteMesh 提供了一个强大、易用、易l合的机制来使用面模版。可以想象,它将会有很广泛的用户。例如,你可以定义一个装饰器针对不同的浏览器输出额外的页面调试信息(和特定web览器结合之后将产生一个特别的功能Q你可以强制指定使用某一U用户代理)。你也可以定义一个装饰器产生stripped-down XML输出Q用来进行简单的自动化测试。你甚至可以使用装饰器从其他面提取内容Q例如输出到一些简单的门户容器?br />
?em>sitemesh-blank.war入手比较Ҏ(gu)Q但我徏议学?em>sitemesh-example.war以获取更多的Ҏ(gu)和思想?br />
不论你如何用SiteMeshQ我都发现它?yu)大量的代码从表现层中移到我的装饰器中,而无需学习一U新的编E语a或是模版pȝ?br />
对了Q作为最后的补充Q如果你仍然对组合徏立web面感兴,可以查看home.worldonline.dk/viksoe/asmil.htm?br />
文章引用自:http://blog.51766.com/comments/zy/Weblog/1143682180134