﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-　　　　　　　　　　　　　礼物 ^_^ -文章分类-struts2.0</title><link>http://www.blogjava.net/libin2722/category/26765.html</link><description>虚其心，可解天下之问；专其心，可治天下之学；静其心，可悟天下之理；恒其心，可成天下之业。</description><language>zh-cn</language><lastBuildDate>Sat, 08 Aug 2009 06:00:47 GMT</lastBuildDate><pubDate>Sat, 08 Aug 2009 06:00:47 GMT</pubDate><ttl>60</ttl><item><title>Troubleshooting guide migrating from Struts 2.0.x to 2.1.x</title><link>http://www.blogjava.net/libin2722/articles/289119.html</link><dc:creator>礼物</dc:creator><author>礼物</author><pubDate>Thu, 30 Jul 2009 06:44:00 GMT</pubDate><guid>http://www.blogjava.net/libin2722/articles/289119.html</guid><wfw:comment>http://www.blogjava.net/libin2722/comments/289119.html</wfw:comment><comments>http://www.blogjava.net/libin2722/articles/289119.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/libin2722/comments/commentRss/289119.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/libin2722/services/trackbacks/289119.html</trackback:ping><description><![CDATA[Error convertoring HTML to XHTML: System.ArgumentException: Cannot have ']]&gt;' inside an XML CDATA block.
   at System.Xml.XmlTextWriter.WriteCData(String text)
   at System.Xml.XmlWriter.WriteNode(XmlReader reader, Boolean defattr)
   at FreeTextBoxControls.Support.Formatter.HtmlToXhtml(String input)<img src ="http://www.blogjava.net/libin2722/aggbug/289119.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/libin2722/" target="_blank">礼物</a> 2009-07-30 14:44 <a href="http://www.blogjava.net/libin2722/articles/289119.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts2 Convention plugin</title><link>http://www.blogjava.net/libin2722/articles/256525.html</link><dc:creator>礼物</dc:creator><author>礼物</author><pubDate>Tue, 24 Feb 2009 14:48:00 GMT</pubDate><guid>http://www.blogjava.net/libin2722/articles/256525.html</guid><wfw:comment>http://www.blogjava.net/libin2722/comments/256525.html</wfw:comment><comments>http://www.blogjava.net/libin2722/articles/256525.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/libin2722/comments/commentRss/256525.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/libin2722/services/trackbacks/256525.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; Convention Plugin原文：http://cwiki.apache.org/WW/convention-plugin.html翻译：石太祥（ealpha@gmail.com&nbsp;&nbsp; http://www.lalfa.com ）&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs...&nbsp;&nbsp;<a href='http://www.blogjava.net/libin2722/articles/256525.html'>阅读全文</a><img src ="http://www.blogjava.net/libin2722/aggbug/256525.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/libin2722/" target="_blank">礼物</a> 2009-02-24 22:48 <a href="http://www.blogjava.net/libin2722/articles/256525.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转载)SpringSide 3 中的 Struts 2</title><link>http://www.blogjava.net/libin2722/articles/256485.html</link><dc:creator>礼物</dc:creator><author>礼物</author><pubDate>Tue, 24 Feb 2009 09:45:00 GMT</pubDate><guid>http://www.blogjava.net/libin2722/articles/256485.html</guid><wfw:comment>http://www.blogjava.net/libin2722/comments/256485.html</wfw:comment><comments>http://www.blogjava.net/libin2722/articles/256485.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/libin2722/comments/commentRss/256485.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/libin2722/services/trackbacks/256485.html</trackback:ping><description><![CDATA[<div>
<p>（转载）http://www.blogjava.net/youxia/archive/2009/02/11/248051.html</p>
<p><br />
</p>
<p>在SpringSide 3 中，使用的MVC框架是Struts 2。Struts 2
向对于Struts 1 来说，具有相当多的优点，有很多人都说，用过Struts 2之后，再也不想看Struts
1了。然而，任何东西都有它的复杂性，Struts 2也不例外，SpringSide 3做了很多工作来简化Struts 2 的使用。<br />
<br />
先来说说Struts 2的特点：<br />
1、
编写Action变得简单了，Action变成了简单的POJO，再也不用和ActionForm、ActionForward打交道了，返回的时候直接
返回字符串即可。如果要访问Servlet API，则直接使用ServletActionContext类的静态方法。<br />
2、Struts
2提供了插件机制，允许我们自己为它编写插件，当然，要我自己写是不现实的，但是面对别人写的琳琅满目的插件，我一样会昏头。再网上随便一搜，就可以发现
40多种Struts 2插件。SpringSide 3选择的CodeBehind，就是一种Struts 2插件，它的目的是为了简化配置。<br />
3、Struts 2提供了拦截器机制，之所以编写Action的任务那么简单，靠的都是这些拦截器，比如它们可以自动解析Web表单和URL参数，把它们注入到Action中。<br />
4、Struts 2提供了丰富的taglib，当然，丰富也代表着我们要化更多的时间去学习。<br />
5、Struts 2依然提供了Validator和i18n支持。<br />
等等...<br />
<br />
下面，我们来看看SpringSide 3是怎么使用Struts 2的吧。SpringSide 3的主要目标是降低我们使用Struts 2的复杂性，所以，它选择了这些办法：<br />
1、没有使用Validator和i18n，对数据的验证交给了JQuery，这变成了表现层的任务，而且JQuery也可以使用AJAX从服务器端进行验证。至于i18n，江南白衣说小网站用不上。<br />
2、没有使用Struts 2的UI标签，当然也就没有使用FreeMaker或SiteMesh了。<br />
<br />
当然，省掉了一些东西，就省掉了我们不少的学习时间。对于Struts 2核心的一些东西，我们看看它是怎么做的：<br />
<br />
1、
使用CodeBehind插件来简化配置。使用CodeBehind后，我们就可以不用配置result了，它可以根据我们Action的返回值自动猜测
返回的视图页面，它猜测的规则是这样的：返回页面的路径为struts.codebehind.pathPrefix + package
namespace + action name + action returnvalue&nbsp;+&nbsp;.jsp，action
returnvalue为success时，值为空，为其他时，值为"-" + return type。我们来看看SpringSide
3生成的项目中关于Struts 2的配置文件：<br />
<img alt="001.PNG" src="../../images/blogjava_net/youxia/SpringSide15/001.PNG" border="0" width="736" height="431" /><br />
其
中struts.codebehind.pathPrefix设置为&#8220;/WEB-INF/jsp/&#8221;，package的namespace没有设置，所
以，如果我们的Action为UserAction，则返回success时，就会返回到/WEB-INF/jsp/user.jsp，如果返回
input，则返回到/WEB-INF/jsp/user-input.jsp。这里江南白衣玩了一个狡猾，他把所有的jsp页面放到WEB-INF目录
中，别人就没有办法直接访问了，这样就可以简化Acegi的配置工作。<br />
<br />
2、关于拦截器栈<br />
在上面讲Struts
2的特点时，我已经说了Struts
2中拦截器的重要作用，在上面的截图中，package的配置没有做别的什么事，主要就是配置了拦截器栈。那么拦截器栈是怎么使用的呢？它是在
Action类中通过@ParentPackage指定的，如下面的代码：<br />
<img alt="002.PNG" src="../../images/blogjava_net/youxia/SpringSide15/002.PNG" border="0" width="523" height="320" /><br />
<br />
下面，我来具体说一下拦截器有什么作用。<br />
&nbsp;例子一、我们知道Struts 2中的Action是和Servlet API解耦的，那么如果我们要在Action中访问Servlet API怎么办呢？一种办法就是使用ServletActionContext，如下图：<br />
<img alt="003.PNG" src="../../images/blogjava_net/youxia/SpringSide15/003.PNG" border="0" width="567" height="100" /><br />
另外一种办法，就是让我们的Action实现<strong>ServletRequestAware</strong>接口，如下代码：</p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;">
<span style="color: #0000ff;">public</span>
&nbsp;
<span style="color: #0000ff;">class</span>
<span style="color: #000000;">&nbsp;MyAction&nbsp;</span>
<span style="color: #0000ff;">implements</span>
<span style="color: #000000;">&nbsp;ServletRequestAware&nbsp;{<br />
&nbsp;&nbsp;&nbsp;</span>
<span style="color: #0000ff;">private</span>
<span style="color: #000000;">&nbsp;HttpServletRequest&nbsp;request;<br />
&nbsp;&nbsp;&nbsp;</span>
<span style="color: #0000ff;">public</span>
&nbsp;
<span style="color: #0000ff;">void</span>
<span style="color: #000000;">&nbsp;setServletRequest(HttpServletRequest&nbsp;request)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #0000ff;">this</span>
<span style="color: #000000;">.request&nbsp;</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">&nbsp;request;<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;</span>
<span style="color: #0000ff;">public</span>
<span style="color: #000000;">&nbsp;String&nbsp;execute()&nbsp;</span>
<span style="color: #0000ff;">throws</span>
<span style="color: #000000;">&nbsp;Exception&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #008000;">//</span>
<span style="color: #008000;">&nbsp;do&nbsp;the&nbsp;work&nbsp;using&nbsp;the&nbsp;request</span>
<span style="color: #008000;">
<br />
</span>
<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span style="color: #0000ff;">return</span>
<span style="color: #000000;">&nbsp;Action.SUCCESS;<br />
&nbsp;&nbsp;&nbsp;}<br />
}</span>
</div>
这时候，<strong>ServletConfigInterceptor</strong> 拦截器就会把request对象注入到我们的Action中。<br />
<br />
例子二、<strong>ParametersInterceptor</strong>
拦截器会自动解析web表单或URL参数，并把它们注入到Action中。但是很多时候，我们不愿意我们的Action具有太多的属性，因为一大堆的
get、set方法看起来太乱糟糟，我们希望有一个专门的Model对象来存储这些值，而且刚好我们为Hibernate设计的Entity类用来做
Model正合适。这时，我们可以让我们的Action实现<strong>ModelDriven</strong>接口，让getModel()方法返回我们的entity对象即可。这正是SpringSide 3采取的方法，如下图的代码片断：<br />
<img alt="004.PNG" src="../../images/blogjava_net/youxia/SpringSide15/004.PNG" border="0" width="322" height="200" /><br />
这时候，<strong>ModelDrivenInterceptor</strong>拦截器就会帮助我们把解析的URL参数或表单数据注入到entity的属性中，而不是Action中。<br />
<br />
例子三、<strong>Preparable</strong> 接口联合<strong>PrepareInterceptor</strong>拦截器一起工作，可以让action在执行execute() 方法前， 执行一个prepare()方法，这也正是SpringSide 3的工作方式。<br />
<br />
3、关于Action<br />
有了上面对CodeBehind的理解和对拦截器栈的理解后，再来理解SpringSide 3中的Action就再简单不过了，SpringSide 3中Action的继承树如下：<br />
<img alt="005.PNG" src="../../images/blogjava_net/youxia/SpringSide15/005.PNG" border="0" width="268" height="127" /><br />
<br />
其中ActionSupport类是Struts 2提供的，另外两个类是白衣自己扩展的。其中SimpleActionSupport主要是提供了一些绕过jsp页面直接输出字符串的方法，不值一谈。而CRUDActionSupport就比较复杂，如下：
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: #eeeeee;"><span style="color: #0000ff;">public</span>&nbsp;<span style="color: #0000ff;">abstract</span>&nbsp;<span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;CRUDActionSupport</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;</span>&nbsp;<span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;SimpleActionSupport&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;ModelDriven</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">,&nbsp;Preparable&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;进行CUD操作后,以redirect方式重新打开action默认页的result名.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span>&nbsp;<span style="color: #0000ff;">static</span>&nbsp;<span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;String&nbsp;RELOAD&nbsp;</span><span style="color: #000000;">=</span>&nbsp;<span style="color: #000000;">"</span><span style="color: #000000;">reload</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Action函数,默认action函数，默认指向list函数.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;String&nbsp;execute()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;list();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Action函数,显示Entity列表.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;return&nbsp;SUCCESS.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span>&nbsp;<span style="color: #0000ff;">abstract</span><span style="color: #000000;">&nbsp;String&nbsp;list()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Action函数,新增或修改Entity.&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;return&nbsp;RELOAD.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span>&nbsp;<span style="color: #0000ff;">abstract</span><span style="color: #000000;">&nbsp;String&nbsp;save()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Action函数,删除Entity.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;return&nbsp;RELOAD.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span>&nbsp;<span style="color: #0000ff;">abstract</span><span style="color: #000000;">&nbsp;String&nbsp;delete()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;在save()前执行二次绑定.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span>&nbsp;<span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;prepareSave()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prepareModel();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;在input()前执行二次绑定.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span>&nbsp;<span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;prepareInput()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prepareModel();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;屏蔽公共的二次绑定.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span>&nbsp;<span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;prepare()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;等同于prepare()的内部函数.&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">protected</span>&nbsp;<span style="color: #0000ff;">abstract</span>&nbsp;<span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;prepareModel()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception;<br />
}</span></div>
<p><br />
第
一，它做了把CRUD操作放到了同一个Action中的操作，这样可以少写几个Action。这个工作难度不大，我觉得白衣此举，主要是为了规范CRUD
函数的命名。在Struts
2中，如果我们要访问的不是默认的excute方法，可以使用如/user!save.action的格式，这样访问的就是UserAction的
save方法。<br />
第二，它实现了<strong>ModelDriven</strong>接口和<strong>Preparable</strong>接
口，关于这两个接口，我在前面讲拦截器的时候已经提到过了，所以很容易理解。我们可以把我们为Hibernate设计的entity类作为Model，也
可以把初始化这些entity的工作放到prepareSave()和prepareInput()方法中，这两个方法将会在save()和
input()方法执行前自动执行。<br />
第三，它定义了一个静态变量RELOAD，定义这个变量的目的是为了定义一个result的需要。CodeBehind中，大部分的result可以自己猜测，对于不能猜测的，需要使用@Results指定，如下代码：<br />
<img alt="006.PNG" src="../../images/blogjava_net/youxia/SpringSide15/006.PNG" border="0" width="925" height="74" /></p>
<p>&nbsp;好
了，对SpringSide 3中Struts 2的分析就写到这里了。总之，使用SpringSide
3时，对于Action这一块非常简单，如果不设及到CRUD操作，就继承SimpleActionSupport，如果涉及到CRUD操作，就继承
CRUDActionSupport，并在getModel()"save()"prepareSave"input()"prepareInput()
等框框中填入适当的代码即可。</p>
</div>
<img src ="http://www.blogjava.net/libin2722/aggbug/256485.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/libin2722/" target="_blank">礼物</a> 2009-02-24 17:45 <a href="http://www.blogjava.net/libin2722/articles/256485.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts 2中实现文件下载（修正中文问题）</title><link>http://www.blogjava.net/libin2722/articles/247014.html</link><dc:creator>礼物</dc:creator><author>礼物</author><pubDate>Thu, 18 Dec 2008 00:43:00 GMT</pubDate><guid>http://www.blogjava.net/libin2722/articles/247014.html</guid><wfw:comment>http://www.blogjava.net/libin2722/comments/247014.html</wfw:comment><comments>http://www.blogjava.net/libin2722/articles/247014.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/libin2722/comments/commentRss/247014.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/libin2722/services/trackbacks/247014.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: v":* {behavior:url(#default#VML);}o":* {behavior:url(#default#VML);}w":* {behavior:url(#default#VML);}.shape {behavior:url(#default#VML);}Normal07.8 磅02falsefalsefalseMicro...&nbsp;&nbsp;<a href='http://www.blogjava.net/libin2722/articles/247014.html'>阅读全文</a><img src ="http://www.blogjava.net/libin2722/aggbug/247014.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/libin2722/" target="_blank">礼物</a> 2008-12-18 08:43 <a href="http://www.blogjava.net/libin2722/articles/247014.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java 国际化-资源文件的使用 (i18n)</title><link>http://www.blogjava.net/libin2722/articles/207836.html</link><dc:creator>礼物</dc:creator><author>礼物</author><pubDate>Sat, 14 Jun 2008 03:01:00 GMT</pubDate><guid>http://www.blogjava.net/libin2722/articles/207836.html</guid><wfw:comment>http://www.blogjava.net/libin2722/comments/207836.html</wfw:comment><comments>http://www.blogjava.net/libin2722/articles/207836.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/libin2722/comments/commentRss/207836.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/libin2722/services/trackbacks/207836.html</trackback:ping><description><![CDATA[<h3>Java国际化——资源包的使用</h3>
<br />
<u>本文是由JR主持写作的《J2SE进阶》一书的部分章节整理而成，《J2SE进阶》正在写作、完善阶段。您阅读后，有任何建议、批评，请<a class="l2" href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#111;&#107;&#95;&#119;&#105;&#110;&#110;&#101;&#114;&#98;&#111;&#121;&#64;&#115;&#105;&#110;&#97;&#46;&#99;&#111;&#109;" target="_blank">和我联系</a>，或在<a href="http://www.chinaitpower.com/A200507/2005-07-24/&nbsp;%3Ca%20href=%22http://www.javaresearch.org/forum/thread.jsp?column=376&amp;thread=7576"  ?>http://www.javaresearch.org/forum/thread.jsp?column=376&amp;thread=7576'</a> target='_blank' class='l2'&gt;这儿留言</a>。《J2SE进阶》写作项目组感谢您阅读本文。</u><br />
<br />
在当今这个信息社会，尤其是随着互联网的出现和普及，人们之间的距离比以往任何时候都更加接近，同时交往也更加频繁，时下最时髦的概念就是地球村，而我小时候只知道我出生的那个小乡村。距离近，交往频繁，人们就不得不考虑如何去与各个不同种族、不同区域的人们打交道。对人如此，对我们的软件亦是如此，你需要考虑如何让处于世界不同地方的使用者都能够很好地使用你的软件。于是，在每个软件开始之前，编写者都可能需要考虑这样一个问题——国际化。<br />
<br />
我们知道，在Java中可以通过java.util.Locale类来唯一地确定特定语言和国家的组合，即抽象最终用户的使用环境。同时将用户相关的一些信息置于资源包中，通过资源包来动态地获得最终的用户显示。资源包可以由资源文件或者资源子类来具体实现。<br />
<strong><br />
注意：本文只打算讨论国际化过程中资源包的使用技巧，更多更精彩的内容，请期待《J2SE进阶》一书。</strong><br />
<br />
<h4>资源包</h4>
<br />
在编写应用程序的时候，需要面对的一个问题是如何来处理与locale相关的一些信息。比如，页面上的一些静态文本就希望能够以用户习惯的语言显示。最原始的做法是将这些信息硬编码到程序中（可能是一大串判断语句），但是这样就将程序代码和易变的locale信息捆绑在一起，以后如果需要修改locale信息或者添加其它的locale信息，你就不得不重新修改代码。而资源包可以帮助你解决这个问题，它通过将可变的locale信息放入资源包中来达到两者分离的目的。应用程序可以自动地通过当前的locale设置到相应的资源包中取得所要的信息。资源包的概念类似于Windows编程人员使用的资源文件（rc文件）。<br />
<br />
一般来说，资源包需要完成两个功能：和具体的locale进行绑定以及读取locale相关信息。<br />
<br />
<h5>ResourceBundle类</h5>
<br />
你可以把资源包看作为一个由许多成员（子类）组成的大家庭，其中每个成员关联到不同的locale对象，那它是如何完成关联功能的呢？<br />
<br />
资源包中的每个成员共享一个被称作基名（base&nbsp;name）的名称，然后在此基础上根据一定的命名规范进行扩展。下面就列出了一些成员的名称：<br />
&nbsp;&nbsp;&nbsp;&nbsp;LabelResources<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LabelResources_de<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LabelResources_de_CH<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LabelResources_de_CH_UNIX<br />
可见这些子类依据这样的命名规范：baseName_language_country_variant，其中language等几个变量就是你在构造Locale类时所使用的。而资源包正是通过这个符合命名规范的名称来和locale进行关联的，比如LabelResource_de_CH就对应于由德语（de）和瑞士（CH）组成的locale对象。<br />
<br />
当你的应用程序需要查找特定locale对象关联的资源包时，它可以调用ResourceBundle的getBundle方法，并将locale对象作为参数传入。<br />
<div class="codeStyle">
<ol>
    <li>
    <li><font color="#ff0000">Locale</font>&nbsp;currentLocale&nbsp;=&nbsp;<strong><font color="#0000ff">new</font></strong>&nbsp;<font color="#ff0000">Locale</font>(<font color="#ff33ff">"de"</font>,&nbsp;<font color="#ff33ff">"CH"</font>,&nbsp;<font color="#ff33ff">"UNIX"</font>);
    <li><font color="#ff0000">ResourceBundle</font>&nbsp;myResources&nbsp;=
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ff0000">ResourceBundle</font>.getBundle(<font color="#ff33ff">"LabelResources"</font>,&nbsp;currentLocale); </li>
</ol>
</div>
<br />
如果该locale对象匹配的资源包子类找不到，getBundle将试着查找最匹配的一个子类。具体的查找策略是这样的：getBundle使用基名，locale对象和缺省的locale来生成一个候选资源包名称序列。如果特定locale对象的语言代码、国家代码和可选变量都是空值，则基名是唯一的候选资源包名称。否则的话，具体locale对象（language1，country1和variant1）和缺省locale（language2，country2和variant2）将产生如下的序列：<br />
<ul><br />
    <li>baseName&nbsp;+&nbsp;"_"&nbsp;+&nbsp;language1&nbsp;+&nbsp;"_"&nbsp;+&nbsp;country1&nbsp;+&nbsp;"_"&nbsp;+&nbsp;variant1<br />
    <li>baseName&nbsp;+&nbsp;"_"&nbsp;+&nbsp;language1&nbsp;+&nbsp;"_"&nbsp;+&nbsp;country1&nbsp;<br />
    <li>baseName&nbsp;+&nbsp;"_"&nbsp;+&nbsp;language1&nbsp;<br />
    <li>baseName&nbsp;+&nbsp;"_"&nbsp;+&nbsp;language2&nbsp;+&nbsp;"_"&nbsp;+&nbsp;country2&nbsp;+&nbsp;"_"&nbsp;+&nbsp;variant2&nbsp;<br />
    <li>baseName&nbsp;+&nbsp;"_"&nbsp;+&nbsp;language2&nbsp;+&nbsp;"_"&nbsp;+&nbsp;country2&nbsp;<br />
    <li>baseName&nbsp;+&nbsp;"_"&nbsp;+&nbsp;language2&nbsp;<br />
    <li>baseName&nbsp;<br />
    </li>
</ul>
<br />
然后，getBundle方法按照产生的序列依次查找匹配的资源包子类并对结果子类初始化。首先，它将寻找类名匹配候选资源包名称的类，如果找到将创建该类的一个实例，我们称之为结果资源包。否则，getBundle方法将寻找对应的资源文件，它通过候选资源包名称来获得资源文件的完整路径（将其中的&#8220;.&#8221;替换为&#8220;/&#8221;，并加上&#8220;.properties&#8221;后缀），如果找到匹配文件，getBundle方法将利用该资源文件来创建一个PropertyResourceBundle实例，也就是最终的结果资源包。与此同时，getBundle方法会将这些资源包实例缓存起来供以后使用。<br />
<br />
如果没有找到结果资源包，该方法将抛出MissingResourceException异常。所以为了防止异常的抛出，一般来说都需要至少实现一个基名资源包子类。<br />
<br />
<strong>注意：基名参数必须是一个完整的类名称（比如LabelResources，resource.LabelResources等），就相当于你引用一个类时需要指定完整的类路径。但是，为了和以前的版本保持兼容，在使用PropertyResourceBundles时也允许使用&#8220;/&#8221;来代替&#8220;.&#8221;表示路径。</strong><br />
<br />
比如你有以下这些资源类和资源文件：MyResources.class，&nbsp;MyResources_fr_CH.properties，&nbsp;MyResources_fr_CH.class，&nbsp;MyResources_fr.properties，&nbsp;MyResources_en.properties，&nbsp;MyResources_es_ES.class。你利用以下的locale设置来调用getBundle方法，你将会得到不同的结果资源包（假设缺省locale为Locale(&#8220;en&#8221;,&nbsp;&#8220;UK&#8221;)），请参考表13.4。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;表13.4&nbsp;locale设置与结果资源包<br />
locale设置&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;结果资源包<br />
Locale("fr",&nbsp;"CH")&nbsp;&nbsp;&nbsp;&nbsp;MyResources_fr_CH.class<br />
Locale("fr",&nbsp;"FR")&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyResources_fr.properties<br />
Locale("de",&nbsp;"DE")&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyResources_en.properties<br />
Locale("en",&nbsp;"US")&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyResources_en.properties<br />
Locale("es",&nbsp;"ES")&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyResources_es_ES.class<br />
<br />
创建了具体的资源包子类实例以后，就需要获得具体的信息。信息在资源包中是以键值对的方式存储的，表13.5列出的是LabelResources.properties文件的内容。<br />
<br />
表13.5&nbsp;LabelResources.properties<br />
<div class="codeStyle">
<ol>
    <li>
    <li>#&nbsp;This&nbsp;is&nbsp;LabelResources.properties&nbsp;file
    <li>greetings&nbsp;=&nbsp;您好！
    <li>farewell&nbsp;=&nbsp;再见。
    <li>inquiry&nbsp;=&nbsp;您好吗？ </li>
</ol>
</div>
<br />
其中等号左边的字符串表示主键，它们是唯一的。为了获得主键对应的值，你可以调用ResourceBundle类的getString方法，并将主键作为参数。此外，文件中以&#8220;#&#8221;号开头的行表示注释行。<br />
<br />
<h5>ListResourceBundle和PropertyResourceBundle子类</h5>
<br />
抽象类ResourceBundle具有两个子类：ListResourceBundle和PropertyResourceBundle，它们表示资源包子类两种不同的实现方式。<br />
<br />
PropertyResourceBundle是和资源文件配对使用的，一个属性文件就是一个普通的文本文件，你只需要为不同的locale设置编写不同名称的资源文件。但是，在资源文件中只能包含字符串，如果需要存储其它类型对象，你可以使用ListResourceBundle。<br />
<br />
ListResourceBundle是将键值对信息保存在类中的列表中，而且你必须实现ListResourceBundle的具体子类。<br />
<br />
如果ListResourceBundle和PropertyResourceBundle不能够满足你的需要，你可以实现自己的ResourceBundle子类，你的子类必须覆盖两个方法：handleGetObject和getKeys。<br />
<br />
<h5>使用资源文件</h5>
<br />
使用资源包最简单的方法就是利用资源文件，利用资源文件一般需要以下几个步骤：<br />
1、创建一个缺省的资源文件<br />
为了防止找不到资源文件，你最好实现一个缺省的资源文件，该文件的名称为资源包的基名加上.properties后缀。<br />
2、创建所需的资源文件<br />
为你准备支持的locale设置编写对应的资源文件。<br />
3、设置locale<br />
你必须在程序中的某个地方提供locale的设置或者切换功能，或者将其放入配置文件中。<br />
4、根据locale设置创建资源包<br />
ResourceBundle&nbsp;resource&nbsp;=<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ResourceBundle.getBundle("LabelBundle",currentLocale);<br />
5、通过资源包获取locale相关信息<br />
String&nbsp;value&nbsp;=&nbsp;resource.getString("welcome");<br />
<br />
<strong>注意：在使用基名的时候，特别要注意给出完整的类名（或者路径名），比如你的应用程序所在的类包为org.javaresearch.j2seimproved.i18n，而你的资源文件在你的应用程序下的resource子目录中，那你的基名就应该是org.javaresearch.j2seimproved.i18n.resource.LabelBundleBundle而不是resource.LabelBundleBundle。<br />
</strong><br />
<br />
<h5>使用ListResourceBundle</h5>
<br />
使用ListResourceBundle和使用资源文件的步骤基本上一样，只不过你需要用ListResourceBundle子类来替换相应的资源文件。比如你的应用程序的基名是LabelBundle，而且准备支持Locale("en","US")和Locale("zh","CN")，那你需要提供以下几个Java文件，注意类名和locale的对应关系。<br />
LabelBundle_en_US.java<br />
LabelBundle_zh_CN.java<br />
LabelBundle.java（缺省类）<br />
<br />
代码13.3列出的是LabelBundle_zh_CN.java的源代码，相对于资源文件中&#8220;key&nbsp;=&nbsp;value&#8221;的写法，在此文件中你首先利用键值对来初始化一个二维数组，并在getContents方法中返回该数组。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
代码13.3：LabelBundle_zh_CN.java<br />
<div class="codeStyle">
<ol>
    <li>
    <li><strong><font color="#0000ff">package</font></strong>&nbsp;org.javaresearch.j2seimproved.i18n;<strong><font color="#0000ff">import</font></strong>&nbsp;
    <li>
    <li>java.util.<strong><a href="http://www.chinaitpower.com/source/jdk142/java/util/ListResourceBundle.java.html" target="_blank"><font class="classLink"><u>ListResourceBundle</u></font></a></strong>;
    <li>
    <li><strong><font color="#0000ff">public</font></strong>&nbsp;<strong><font color="#0000ff">class</font></strong>&nbsp;LabelBundle_zh_CN&nbsp;<strong><font color="#0000ff">extends</font></strong>&nbsp;<font color="#ff0000">ListResourceBundle</font>&nbsp;{&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;<strong><font color="#0000ff">public</font></strong>&nbsp;<strong><a href="http://www.chinaitpower.com/source/jdk142/java/lang/Object.java.html" target="_blank"><font class="classLink"><u>Object</u></font></a></strong>[][]&nbsp;getContents()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;<strong><font color="#0000ff">return</font></strong>&nbsp;contents;&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;
    <li>
    <li>&nbsp;&nbsp;<strong><font color="#0000ff">private</font></strong>&nbsp;<strong><a href="http://www.chinaitpower.com/source/jdk142/java/lang/Object.java.html" target="_blank"><font class="classLink"><u>Object</u></font></a></strong>[][]&nbsp;contents&nbsp;=&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;{<font color="#ff33ff">"title"</font>,&nbsp;<font color="#ff33ff">"称谓"</font>},&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;{<font color="#ff33ff">"surname"</font>,&nbsp;<font color="#ff33ff">"姓"</font>},&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;&nbsp;&nbsp;{<font color="#ff33ff">"firstname"</font>,&nbsp;<font color="#ff33ff">"名"</font>},&nbsp;&nbsp;&nbsp;
    <li>&nbsp;&nbsp;};
    <li>} </li>
</ol>
</div>
<br />
<br />
创建完资源类以后，同样需要设置locale以及根据locale来创建资源包。在通过资源包获取具体值的时候，你不能再使用getString方法，而应该调用getObject方法，而且由于getObject方法返回一个Object对象，你还需要进行正确的类型转换。其实，为了你的程序通用性，我们建议在使用资源文件的时候你也应该调用getObject方法，而不是getString方法。<br />
<div class="codeStyle">
<ol>
    <li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;<strong><a href="http://www.chinaitpower.com/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></strong>&nbsp;title&nbsp;=&nbsp;(<strong><a href="http://www.chinaitpower.com/source/jdk142/java/lang/String.java.html" target="_blank"><font class="classLink"><u>String</u></font></a></strong>)resource.getObject(<font color="#ff33ff">"title"</font>); </li>
</ol>
</div>
<br />
关于ListResourceBundle的详细使用，可以参考本书所附代码中国际化一节的ListResourceBundleSample.java程序。<br />
<br />
<h5>MessageFormat类</h5>
<br />
上面我们讲到利用资源文件来分离代码和可变的信息。但是在实际过程中，有些信息并不能够完全事先定义好，其中可能会用到运行时的一些结果，最典型例子的就是错误提示代码，比如提示某个输入必须在一定范围内。利用上面所讲的资源文件并不能够很好地解决这个问题，所以Java中引入了MessageFormat类。<br />
<br />
MessageFormat提供一种语言无关的方式来组装消息，它允许你在运行时刻用指定的参数来替换掉消息字符串中的一部分。你可以为MessageFormat定义一个模式，在其中你可以用占位符来表示变化的部分，比如你有这样一句话：<br />
<br />
您好，<u>peachpi</u>！欢迎来到Java研究组织网站！当前时间是：<u>2003-8-1&nbsp;16:43:12。</u><br />
<br />
其中斜体带下划线的部分为可变化的，你需要根据当前时间和不同的登录用户来决定最终的显示。我们用占位符来表示这些变化的部分，可以得到下面这个模式：<br />
<br />
您好，{0}！欢迎来到Java研究组织网站！当前时间是：{1,date}&nbsp;{1,time}。<br />
<br />
占位符的格式为{&nbsp;ArgumentIndex&nbsp;,&nbsp;FormatType&nbsp;,&nbsp;FormatStyle&nbsp;}，详细说明可以参考MessageFormat的API说明文档。这里我们定义了两个占位符，其中的数字对应于传入的参数数组中的索引，{0}占位符被第一个参数替换，{1}占位符被第二个参数替换，依此类推。<br />
最多可以设置10个占位符，而且每个占位符可以重复出现多次，而且格式可以不同，比如{1,date}和{1,time}。而通过将这些模式定义放到不同的资源文件中，就能够根据不同的locale设置，得到不同的模式定义，并用参数动态替换占位符。<br />
<br />
下面我们就以MessageFormatSample.java程序（源文件见本书所附代码）为例，来详细说明其中的每个步骤。<br />
1、找出可变的部分，并据此定义模式，将模式放入不同的资源文件中。<br />
比如针对上面的模式，定义了下面两个资源文件：<br />
MessagesBundle_en_US.properties<br />
Welcome&nbsp;=&nbsp;Hi,&nbsp;{0}!&nbsp;Welcome&nbsp;to&nbsp;Java&nbsp;Research&nbsp;Organization!<br />
MessagesBundle_zh_CN.properties<br />
Welcome&nbsp;=&nbsp;您好，{0}！欢迎来到Java研究组织网站！<br />
<br />
2、创建MessageFormat对象，并设置其locale属性。<br />
<div class="codeStyle">
<ol>
    <li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ff0000">MessageFormat</font>&nbsp;formatter&nbsp;=&nbsp;<strong><font color="#0000ff">new</font></strong>&nbsp;<font color="#ff0000">MessageFormat</font>(<font color="#ff33ff">""</font>);
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;formatter.setLocale(currentLocale); </li>
</ol>
</div>
<br />
3、从资源包中得到模式定义，以及设置参数。<br />
<div class="codeStyle">
<ol>
    <li>
    <li>messages&nbsp;=&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ff0000">ResourceBundle</font>.getBundle(
    <li>&nbsp;&nbsp;<font color="#ff33ff">"org.javaresearch.j2seimproved.i18n.resource.MessagesBundle"</font>,currentLocale);
    <li><strong><a href="http://www.chinaitpower.com/source/jdk142/java/lang/Object.java.html" target="_blank"><font class="classLink"><u>Object</u></font></a></strong>[]&nbsp;testArgs&nbsp;=&nbsp;{<font color="#ff33ff">"peachpi"</font>,<strong><font color="#0000ff">new</font></strong>&nbsp;<font color="#ff0000">Date</font>()}; </li>
</ol>
</div>
<br />
4、利用模式定义和参数进行格式化。<br />
<div class="codeStyle">
<ol>
    <li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><a href="http://www.chinaitpower.com/source/jdk142/java/lang/System.java.html" target="_blank"><font class="classLink"><u>System</u></font></a></strong>.out.println(formatter.format(messages.getString(<font color="#ff33ff">"welcome"</font>),testArgs)); </li>
</ol>
</div>
<br />
<br />
<h5>关于资源包的组织</h5>
<br />
一般来说，你是按照资源的用途来组织资源包的，比如会把所有的页面按钮的信息放入一个名为ButtonResources的资源包中。在实际的应用过程中，以下几个原则可以帮你决定如何组织资源包：<br />
1、要易于维护。<br />
2、最好不要将所有的信息都放入一个资源包中，因为这样资源包载入内存时将会很耗时。<br />
3、最好将一个大的资源包分为几个小的资源包，这样可以在使用的时候才导入必须的资源，减少内存消耗。
<img src ="http://www.blogjava.net/libin2722/aggbug/207836.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/libin2722/" target="_blank">礼物</a> 2008-06-14 11:01 <a href="http://www.blogjava.net/libin2722/articles/207836.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>sitemesh 学习文档</title><link>http://www.blogjava.net/libin2722/articles/164593.html</link><dc:creator>礼物</dc:creator><author>礼物</author><pubDate>Sun, 02 Dec 2007 01:44:00 GMT</pubDate><guid>http://www.blogjava.net/libin2722/articles/164593.html</guid><wfw:comment>http://www.blogjava.net/libin2722/comments/164593.html</wfw:comment><comments>http://www.blogjava.net/libin2722/articles/164593.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/libin2722/comments/commentRss/164593.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/libin2722/services/trackbacks/164593.html</trackback:ping><description><![CDATA[<p><font size="2"><strong>sitemesh是opensymphony团队开发的j2ee应用框架之一，旨在提高页面的可维护性和复用性。opensymphony的另一个广为人知的框架为webwork是用作web层的表示框架。他们都是开源的，可以在www.sf.net下找到。</strong></font></p>
<p><font size="2"><strong>应用于以下大项目的例子：http://opensource.thoughtworks.com/projects/sitemesh.html</strong></font></p>
<ul>
    <li><a href="http://www.jboss.org/">www.jboss.org</a>
    <li><a href="http://www.theserverside.com/">www.theserverside.com</a>
    <li><a href="http://www.opensymphony.com/">www.opensymphony.com</a>
    <li><a href="http://www.atlassian.com/">www.atlassian.com</a> </li>
</ul>
<p>
<table style="border-collapse: collapse" bordercolor="#000000" height="1" cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td width="100%" bgcolor="#000080" height="19"><font color="#ffffff" size="2">简介：</font> </td>
        </tr>
        <tr>
            <td width="100%" height="63"><font size="2">sitemesh应用Decorator模式，用filter截取request和response,把页面组件head,content,banner结合为一个完整的视图。通常我们都是用include标签在每个jsp页面中来不断的包含各种header, stylesheet, scripts and footer，现在，在sitemesh的帮助下，我们可以开心的删掉他们了。如下图，你想轻松的达到复合视图模式，那末看完本文吧。</font>
            <p><img height="495" alt="" src="http://docs.huihoo.com/java/sitemesh/index_example-diagram.gif" width="704" /></p>
            <p>　</p>
            </td>
        </tr>
        <tr>
            <td width="100%" bgcolor="#000080" height="19"><font color="#ffffff" size="2">hello sitemesh：</font> </td>
        </tr>
        <tr>
            <td width="100%" height="15">
            <ol>
                <li><font size="2">在WEB-INF/web.xml中copy以下filter的定义:</font>
                <table style="border-collapse: collapse" bordercolor="#000000" height="1" cellspacing="0" cellpadding="0" width="80%" border="1">
                    <tbody>
                        <tr>
                            <td width="100%" bgcolor="#efefef">
                            <pre class="codeblock">&lt;filter&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-class&gt;com.opensymphony.module.sitemesh.filter.PageFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;taglib&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;taglib-uri&gt;sitemesh-decorator&lt;/taglib-uri&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;taglib-location&gt;/WEB-INF/sitemesh-decorator.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;taglib-uri&gt;sitemesh-page&lt;/taglib-uri&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;taglib-location&gt;/WEB-INF/sitemesh-page.tld&lt;/taglib-location&gt;&lt;/taglib&gt;</pre>
                            </td>
                        </tr>
                    </tbody>
                </table>
                <font size="2"><br />
                </font>
                <li><font size="2">copy所需jar和dtd文件至相应目录，访问<a href="http://opensymphony.sourceforge.net/">opensymphony.sourceforge.net</a>的cvs以获取sitemesh最新版本。</font>
                <table width="80%" border="0">
                    <tbody>
                        <tr>
                            <td width="35%"><font size="2">sitemesh.jar</font></td>
                            <td width="65%"><font size="2">WEB-INF/lib</font> </td>
                        </tr>
                        <tr>
                            <td width="35%"><font size="2">sitemesh-decorator.tld</font></td>
                            <td width="65%"><font size="2">WEB-INF</font> </td>
                        </tr>
                        <tr>
                            <td width="35%"><font size="2">sitemesh-page.tld</font></td>
                            <td width="65%"><font size="2">WEB-INF</font> </td>
                        </tr>
                    </tbody>
                </table>
                <font size="2"><br />
                </font>
                <li><font size="2">建立</font><font size="2">WEB-INF/</font><font size="2">decorators.xml描述各装饰器页面(可仿照sitemesh例子)。</font>
                <table style="border-collapse: collapse" bordercolor="#000000" height="1" cellspacing="0" cellpadding="0" width="80%" bgcolor="#efefef" border="1">
                    <tbody>
                        <tr>
                            <td width="100%">
                            <pre><font size="2">&lt;decorators defaultdir="/_decorators"&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;decorator name="main" page="main.jsp"&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;pattern&gt;*&lt;/pattern&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/decorator&gt;&lt;/decorators&gt;</font></pre>
                            </td>
                        </tr>
                    </tbody>
                </table>
                <p><font size="2"><br />
                <br />
                </font></p>
                <li><font size="2">建立装饰器页面 /_decorators/main.jsp<br />
                </font>
                <table style="border-collapse: collapse" bordercolor="#000000" height="1" cellspacing="0" cellpadding="0" width="80%" bgcolor="#efefef" border="1">
                    <tbody>
                        <tr>
                            <td width="100%">
                            <pre><font size="2">&lt;%@ page contentType="text/html; charset=GBK"%&gt;&lt;%@ taglib uri="sitemesh-decorator" prefix="decorator" %&gt;&lt;html&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;head&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;title&gt;&lt;decorator:title default="装饰器页面..." /&gt;&lt;/title&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;decorator:head /&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/head&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;body&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sitemesh的例子&lt;hr&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;decorator:body /&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;hr&gt;chen56@msn.com&nbsp;&nbsp;&nbsp;&nbsp; &lt;/body&gt;&lt;/html&gt;</font></pre>
                            </td>
                        </tr>
                    </tbody>
                </table>
                <p><font size="2"><br />
                </font></p>
                <li><font size="2">建立一个的被装饰页面 /index.jsp(内容页面)</font>
                <table style="border-collapse: collapse" bordercolor="#000000" height="1" cellspacing="0" cellpadding="0" width="80%" bgcolor="#efefef" border="1">
                    <tbody>
                        <tr>
                            <td width="100%">
                            <pre><font size="2">&lt;%@ page contentType="text/html; charset=GBK"%&gt;&lt;html&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;head&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;title&gt;Agent Test&lt;/title&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/head&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;body&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;本页只有一句，就是本句.&lt;/p&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/body&gt;&lt;/html&gt;</font></pre>
                            </td>
                        </tr>
                    </tbody>
                </table>
                </li>
            </ol>
            <p><font size="2">最后访问index.jsp，将生成如下页面：</font> </p>
            <p><font size="2"><img height="363" alt="" src="http://docs.huihoo.com/java/sitemesh/index_sitemesh.jpg" width="411" border="0" /></font> </p>
            <p><font size="2">而且，所有的页面也会如同index.jsp一样，被sitemesh的filter使用装饰模式修改成如上图般模样，却不用再使用include标签。</font></p>
            </td>
        </tr>
    </tbody>
</table>
<table style="border-collapse: collapse" bordercolor="#000000" height="1" cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td width="100%" bgcolor="#000080" height="19"><strong><font color="#ffffff" size="2">装饰器&nbsp;&nbsp;&nbsp;&nbsp; decorator概念</font></strong> </td>
        </tr>
        <tr>
            <td width="100%" height="63"><font size="2">建立可复用的web应用程序,一个通用的方法是建立一个分层系统，如同下面一个普通的web应用：</font>
            <ul>
                <li><font size="2">前端，front-end:JSP和Servlets，或jakarta的velocity</font>
                <li><font size="2">控制层框架 Controller ： (Struts/Webwork)</font>
                <li><font size="2">业务逻辑 Business ：主要业务逻辑</font>
                <li>
                <p><font size="2">持久化框架 ：hibernate/jdo</font></p>
                </li>
            </ul>
            <p><font size="2">可糟糕的是前端的页面逻辑很难被复用，当你在每一个页面中用数之不尽的include来复用公共的header, stylesheet, scripts，footer时，一个问题出现了-重复的代码，每个页面必须用copy来复用页面结构，而当你需要创意性的改变页面结构时，灾难就爱上了你。</font></p>
            <p><font size="2">sitemesh通过filter截取request和response，并给原始的页面加入一定的装饰(可能为header,footer...)，然后把结果返回给客户端，并且被装饰的原始页面并不知道sitemesh的装饰，这也就达到了脱耦的目的。</font></p>
            <p><font size="2">据说即将新出台的Portlet规范会帮助我们标准的实现比这些更多更cool的想法，但可怜的我还不懂它到底是一个什末东东，有兴趣的人可以研究<br />
            <a href="http://jakarta.apache.org/jetspeed">jetspeed</a>，或<a href="http://www.jcp.org/en/jsr/detail?id=168">JSR (Java Specification Request) 168</a>,但我想sitemesh如此简单，我们不妨先用着。</font></p>
            <p>　</p>
            </td>
        </tr>
        <tr>
            <td width="100%" bgcolor="#000080" height="19"><strong><font color="#ffffff" size="2">让我们看看怎样配置环境</font> </strong></td>
        </tr>
        <tr>
            <td width="100%" height="15"><font size="2">除了要copy到WEB-INF/lib中的sitemesh.jar, </font><font size="2">copy到WEB-INF中的sitemesh-decorator.tld,sitemesh-page.tld文件外，还有2个文件要建立到WEB-INF/：</font>
            <ul>
                <li><font size="2">sitemesh.xml (可选)&nbsp;&nbsp;</font>
                <li><font size="2">decorators.xml </font></li>
            </ul>
            <h2><font size="2">sitemesh.xml 可以设置2种信息:</font></h2>
            <p><font size="2"><strong>Page Parsers</strong> ：负责读取stream的数据到一个Page对象中以被SiteMesh解析和操作。(不太常用，默认即可)</font></p>
            <p><font size="2"><strong>Decorator Mappers</strong> : 不同的装饰器种类，我发现2种比较有用都列在下面。一种通用的mapper,可以指定装饰器的配置文件名，另一种可打印的装饰器，可以允许你当用http://localhost/aaa/a.html?printable=true方式访问时给出原始页面以供打印(免得把header,footer等的花哨的图片也搭上)<br />
            <br />
            <em>(但一般不用建立它，默认设置足够了：com/opensymphony/module/sitemesh/factory/sitemesh-default.xml）：</em></font> </p>
            <p><font size="2"><strong>范例：</strong></font> </p>
            <table style="border-collapse: collapse" height="1" cellspacing="0" cellpadding="0" width="100%" bgcolor="#e3e3e3" border="1">
                <tbody>
                    <tr>
                        <td width="100%"><code><font face="新宋体" size="2">&lt;sitemesh&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp; &lt;page-parsers&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;parser default="true" class="com.opensymphony.module.sitemesh.parser.DefaultPageParser" /&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" /&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;parser content-type="text/html;charset=ISO-8859-1" class="com.opensymphony.module.sitemesh.parser.FastPageParser" /&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp; &lt;/page-parsers&gt;<br />
                        <br />
                        &nbsp;&nbsp;&nbsp;&nbsp; &lt;decorator-mappers&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper"&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="config" value="/WEB-INF/decorators.xml" /&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/mapper&gt;<br />
                        </font></code><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;mapper class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper"&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="decorator" value="printable" /&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="parameter.name" value="printable" /&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="parameter.value" value="true" /&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/mapper&gt;<code><br />
                        <font face="新宋体">&nbsp;&nbsp;</font></code></font><code><font face="新宋体" size="2">&lt;/decorator-mappers&gt;<br />
                        &lt;/sitemesh&gt; </font></code></td>
                    </tr>
                </tbody>
            </table>
            <p><font size="2"><strong>decorators.xml</strong> ：定义构成复合视图的所有页面构件的描述(主要结构页面，header,footer...)，如下例：</font></p>
            <table style="border-collapse: collapse" height="1" cellspacing="0" cellpadding="0" width="100%" bgcolor="#e3e3e3" border="1">
                <tbody>
                    <tr>
                        <td width="100%"><font size="2">&lt;decorators defaultdir="/_decorators"&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp; &lt;decorator name="main" page="main.jsp"&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;pattern&gt;*&lt;/pattern&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp; &lt;/decorator&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp; &lt;decorator name="printable" page="printable.jsp" role="customer" webapp="aaa" /&gt;<br />
                        &lt;/decorators&gt;</font></td>
                    </tr>
                </tbody>
            </table>
            <p><font size="2"></font></p>
            <ul>
                <li><font size="2">defaultdir: 包含装饰器页面的目录</font>
                <li><font size="2">page : 页面文件名</font>
                <li><font size="2">name : 别名</font>
                <li><font size="2">role : 角色，用于安全</font>
                <li><font size="2">webapp : 可以另外指定此文件存放目录</font>
                <li><font size="2">Patterns : 匹配的路径，可以用*,那些被访问的页面需要被装饰。</font> </li>
            </ul>
            <p><font size="2">　</font> </p>
            </td>
        </tr>
        <tr>
            <td width="100%" bgcolor="#000080" height="13"><strong><font color="#ffffff" size="2">最重要的是写出装饰器本身(也就是那些要复用页面，和结构页面)。</font></strong> </td>
        </tr>
        <tr>
            <td width="100%" height="15"><font size="2">其实，重要的工作就是制作装饰器页面本身(也就是包含结构和规则的页面)，然后把他们描述到decorators.xml中。</font>
            <p><font size="2">让我们来先看一看最简单的用法：其实最常用也最简单的用法就是我们的hello例子，面对如此众多的技术，我想只要达到功能点到为止即可，没必要去研究太深(除非您有更深的需求)。</font></p>
            <table style="border-collapse: collapse" bordercolor="#000000" height="1" cellspacing="0" cellpadding="0" width="80%" bgcolor="#efefef" border="1">
                <tbody>
                    <tr>
                        <td width="100%">
                        <pre><font size="2">&lt;%@ page contentType="text/html; charset=GBK"%&gt;&lt;%@ taglib uri="sitemesh-decorator" prefix="decorator" %&gt;&lt;html&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;head&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;title&gt;&lt;decorator:title default="装饰器页面..." /&gt;&lt;/title&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;decorator:head /&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/head&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;body&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sitemesh的例子&lt;hr&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;decorator:body /&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;hr&gt;chen56@msn.com&nbsp;&nbsp;&nbsp;&nbsp; &lt;/body&gt;&lt;/html&gt;</font></pre>
                        </td>
                    </tr>
                </tbody>
            </table>
            <p><font size="2">我们在装饰器页面只用了2个标签：</font></p>
            <p><font size="2">&lt;decorator:title default="装饰器页面..." /&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ： 把请求的原始页面的title内容插入到&lt;title&gt;&lt;/title&gt;中间。</font></p>
            <p><font size="2">&lt;decorator:body /&gt; ： 把请求的原始页面的body内的全部内容插入到相应位置。</font></p>
            <p><font size="2">然后我们在decorator.xml中加入以下描述即可： </font></p>
            <p><font size="2">&lt;decorator name="main" page="main.jsp"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;pattern&gt;*&lt;/pattern&gt;<br />
            &lt;/decorator&gt;<br />
            </font></p>
            <p><font size="2">这样，请求的所有页面都会被重新处理，并按照main.jsp的格式重新展现在你面前。</font></p>
            <p>　 </p>
            </td>
        </tr>
        <tr>
            <td width="100%" bgcolor="#000080" height="19"><strong><font color="#ffffff" size="2">让我们看看更多的用法。(抄袭sitemesh文档)</font></strong> </td>
        </tr>
        <tr>
            <td width="100%" height="15"><font size="2">以下列着全部标签：</font>
            <table width="80%" align="center">
                <tbody>
                    <tr>
                        <td valign="top"><strong><font size="2">Decorator Tags</font></strong></td>
                        <td valign="top"><strong><font size="2">Page Tags</font></strong></td>
                    </tr>
                    <tr>
                        <td valign="top"><font size="2">被用于建立装饰器页面.</font></td>
                        <td valign="top"><font size="2">被用于从原始内容页面访问装饰器.</font></td>
                    </tr>
                    <tr>
                        <td valign="top"><font size="3"><a href="http://docs.huihoo.com/java/sitemesh/2.html#decorator:head"><code><font face="新宋体" color="#800080">&lt;decorator:head /&gt;</font></code></a><br />
                        <a href="http://docs.huihoo.com/java/sitemesh/2.html#decorator:body"><code><font face="新宋体" color="#800080">&lt;decorator:body /&gt;</font></code></a><br />
                        <a href="http://docs.huihoo.com/java/sitemesh/2.html#decorator:title"><code><font face="新宋体" color="#800080">&lt;decorator:title /&gt;</font></code></a><br />
                        <a href="http://docs.huihoo.com/java/sitemesh/2.html#decorator:getProperty"><code><font face="新宋体" color="#800080">&lt;decorator:getProperty /&gt;</font></code></a><br />
                        <a href="http://docs.huihoo.com/java/sitemesh/2.html#decorator:usePage"><code><font face="新宋体" color="#800080">&lt;decorator:usePage /&gt;</font></code></a><br />
                        </font></td>
                        <td valign="top"><font size="3"><a href="http://docs.huihoo.com/java/sitemesh/2.html#page:applyDecorator"><code><font face="新宋体" color="#800080">&lt;page:applyDecorator /&gt;</font></code></a><br />
                        <a href="http://docs.huihoo.com/java/sitemesh/2.html#page:param"><code><font face="新宋体" color="#800080">&lt;page:param</font></code></a></font></td>
                    </tr>
                </tbody>
            </table>
            　
            <p><strong><a name="decorator:head"><font color="#000000" size="2">&lt;decorator:head /&gt;</font></a></strong></p>
            <p><font size="2">插入原始页面(被包装页面)的head标签中的内容(不包括head标签本身)。</font></p>
            <strong><a name="decorator:body"><font color="#000000" size="2">&lt;decorator:body /&gt;</font></a></strong>
            <p><font size="2">插入原始页面(被包装页面)的body标签中的内容。</font></p>
            <p><strong><a name="decorator:title"><font color="#000000" size="2">&lt;decorator:title [ default="..." ] /&gt;</font></a></strong></p>
            <p><font size="2">插入原始页面(被包装页面)的<a name="decorator:title"><font color="#000000">title</font></a>标签中的内容，还可以添加一个缺省值。</font></p>
            <p><font size="2">例：</font></p>
            <p><font size="2">/_decorator/main.jsp中 （装饰器页面）: &lt;title&gt;</font><a name="decorator:title"><font color="#000000" size="2">&lt;decorator:title default="却省title-hello"&nbsp;&nbsp;&nbsp;&nbsp; /&gt;</font></a><font size="2"><a name="decorator:title"><font color="#000000"> - 附加标题</font></a>&lt;/title&gt;</font></p>
            <p><font size="2">/aaa.jsp中 (原始页面)：&lt;title&gt;<a name="decorator:title"><font color="#000000">aaa页面</font></a>&lt;/title&gt;</font></p>
            <p><font size="2">访问/aaa.jsp的结果：&lt;title&gt;<a name="decorator:title"><font color="#000000">aaa页面</font></a> <a name="decorator:title"><font color="#000000">- 附加标题</font></a>&lt;/title&gt;</font></p>
            <p><strong><a name="decorator:getProperty"><font color="#000000" size="2">&lt;decorator:getProperty property="..." [ default="..." ] [ writeEntireProperty="..." ]/&gt;</font></a></strong></p>
            <p><font size="2">在标签处插入原始页面(被包装页面)的原有的<a name="decorator:title"><font color="#000000">标签的属性</font></a>中的内容，还可以添加一个缺省值。</font></p>
            <p><font size="2">sitemesh文档中的例子很好理解：</font><br />
            <font size="2">The decorator: </font><font size="3"><font face="新宋体"><code>&lt;body bgcolor="white"&lt;decorator:getProperty property="body.onload" writeEntireProperty="true" /&gt;&gt;</code><br />
            </font></font><font size="2">The undecorated page: </font><font size="3"><font face="新宋体"><code>&lt;body onload="document.someform.somefield.focus();"&gt;</code><br />
            </font></font><font size="2">The decorated page: </font><font face="新宋体" size="3"><code>&lt;body bgcolor="white" onload="document.someform.somefield.focus();"&gt;</code></font></p>
            <p><font size="2"><strong>注意，</strong></font><code><font face="新宋体" size="2">writeEntireProperty="true"会在插入内容前加入一个空格。</font></code></p>
            <p><font size="2"><strong><a name="decorator:usePage"><font color="#000000">&lt;decorator:usePage id="..." /&gt;</font></a></strong><br />
            象jsp页面中的&lt;jsp:useBean&gt;标签一样，可以使用被包装为一个Page对象的页面。 (懒的用)</font></p>
            <p><font size="2">例：可用<a name="decorator:usePage"><font color="#000000">&lt;decorator:usePage id="page" /&gt;<strong> ：</strong></font></a></font><a name="decorator:usePage"><font color="#000000" size="3">&lt;%=</font></a><font size="3"><code><font face="新宋体"><nobr>page.getTitle()%&gt;达到</nobr>&lt;decorator:title/&gt;的访问结果。</font></code></font></p>
            <p>　</p>
            <p><font size="2"><a name="page:applyDecorator"><strong><font color="#000000">&lt;page:applyDecorator name="..." [ page="..." title="..." ] &gt;<br />
            </font></strong></a><strong><a name="page:param"><font color="#000000">&lt;page:param name="..."&gt; ... &lt;/page:param&gt;</font></a></strong><br />
            <strong><a name="page:param"><font color="#000000">&lt;page:param name="..."&gt; ... &lt;/page:param&gt;</font></a><br />
            &lt;/page:applyDecorator&gt;</strong></font></p>
            <p><font size="2">应用包装器到指定的页面上，一般用于被包装页面中主动应用包装器。这个标签有点不好理解，我们来看一个例子：</font></p>
            <p><font size="2">包装器页面 /_decorators/panel.jsp：&lt;p&gt;&lt;decorator:title /&gt;&lt;/p&gt;&nbsp;&nbsp;&nbsp;&nbsp; ... &lt;p&gt;&lt;decorator:body /&gt;&lt;/p&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp; 并且在decorators.xml中有&lt;decorator name="panel" page="panel.jsp"/&gt;<br />
            <br />
            一个公共页面，即将被panel包装：/_public/date.jsp:&nbsp;&nbsp;<br />
            &nbsp;&nbsp;&nbsp;&nbsp; ... &lt;%=new java.util.Date()%&gt;&nbsp;&nbsp;&nbsp;&nbsp; ...&lt;decorator:getProperty property="myEmail" /&gt;<br />
            <br />
            被包装页面 /page.jsp ： <br />
            &nbsp;&nbsp;&nbsp;&nbsp; &lt;title&gt;page的应用&lt;/title&gt; <br />
            &nbsp;&nbsp;&nbsp;&nbsp; .....&nbsp;&nbsp;</font><a name="page:applyDecorator"><font size="2"><br />
            <font color="#000000">&nbsp;&nbsp;&nbsp;&nbsp; &lt;page:applyDecorator name="panel" page="/_public/date.jsp" &gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;page:param name="myEmail"&gt; chen_p@neusoft.com &lt;/page:param&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp; &lt;/page:applyDecorator&gt;</font><strong><br />
            </strong></font></a></p>
            <p><font size="2">最后会是什末结果呢？除了/page.jsp会被默认的包装页面包装上header,footer外，page.jsp页面中还内嵌了date.jsp页面，并且此date.jsp页面还会被panel.jsp包装为一个title加body的有2段的页面，第1段是date.jsp的title，第2段是date.jsp的body内容。</font></p>
            <p><font size="2">另外，<a name="page:applyDecorator"><font color="#000000">page:applyDecorator</font></a>中包含的page:param标签所声明的属性值还可以在包装页面中用</font><a name="decorator:getProperty"><font color="#000000" size="2">decorator:getProperty</font></a><font size="2">标签访问到。 </font></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<hr color="#ff0000" size="1" />
<p>
<table style="border-collapse: collapse" bordercolor="#000000" height="1" cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td width="100%" bgcolor="#000080" height="19"><font color="#ffffff" size="2">可打印的界面装饰</font> </td>
        </tr>
        <tr>
            <td width="100%" height="63"><font size="2">前面说过有1种可打印的装饰器，可以允许你当用http://localhost/aaa/a.html?printable=true方式访问时，应用其他的装饰器(自己指定)，给出原始页面以供打印(免得把header,footer等的花哨的图片也搭上)。</font>
            <p><font size="2">让我们来看一看怎样实现他：</font></p>
            <p><font size="2">1.首先在WEB-INFO/sitemesh.xml中设置：<br />
            &nbsp;&nbsp;&nbsp;&nbsp; &lt;mapper class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper"&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="decorator" value="printable" /&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="parameter.name" value="printable" /&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="parameter.value" value="true" /&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp; &lt;/mapper&gt;<br />
            这样就可以通过?printable=true来使用名为printable的装饰器，而不是用原来的装饰器。</font></p>
            <p><font size="2">2.在WEB-INFO/decorators.xml中定义相应的printable装饰器<br />
            &nbsp;&nbsp;&nbsp;&nbsp; &lt;decorator name="printable" page="printable.jsp"/&gt;</font></p>
            <p><font size="2">3.最后编写printable装饰器/decorators/printable.jsp </font></p>
            <table style="border-collapse: collapse" bordercolor="#000000" height="1" cellspacing="0" cellpadding="0" width="80%" bgcolor="#efefef" border="1">
                <tbody>
                    <tr>
                        <td width="100%" bgcolor="#efefef"><font size="2">&lt;%@ taglib uri="sitemesh-decorator" prefix="decorator" %&gt;<br />
                        &lt;html&gt;<br />
                        &lt;head&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp; &lt;title&gt;&lt;decorator:title /&gt;&lt;/title&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp; &lt;decorator:head /&gt;<br />
                        &lt;/head&gt;<br />
                        &lt;body&gt;<br />
                        <br />
                        &nbsp;&nbsp;&nbsp;&nbsp; &lt;h1&gt;&lt;decorator:title /&gt;&lt;/h1&gt;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp; &lt;p align="right"&gt;&lt;i&gt;(printable version)&lt;/i&gt;&lt;/p&gt;<br />
                        <br />
                        &nbsp;&nbsp;&nbsp;&nbsp; &lt;decorator:body /&gt;<br />
                        <br />
                        &lt;/body&gt;<br />
                        &lt;/html&gt;</font></td>
                    </tr>
                </tbody>
            </table>
            <p><font size="2">这样就可以让一个原始页面通过?printable=true开关来切换不同的装饰器页面。</font></p>
            <p>　 </p>
            </td>
        </tr>
    </tbody>
</table>
<table style="border-collapse: collapse" bordercolor="#000000" height="1" cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td width="100%" bgcolor="#000080" height="19"><font color="#ffffff" size="2">中文问题</font></td>
        </tr>
        <tr>
            <td width="100%" height="63"><font size="2">由于sitemesh内部所使用的缺省字符集为iso-8859-1，直接使用会产生乱码，我们可以通过以下方法纠正之：</font>
            <ul>
                <li><font size="2">方法1：可以在您所用的application server的配置文件中找一找，有没有设置encoding或<code></code></font><code><font face="新宋体" size="2">charset的项目，然后设成gbk或gb2312即可</font></code>
                <li><code><font face="新宋体" size="2">方法2：这也是我们一直使用的方法。<br />
                1.在每一个jsp页里设置: &lt;%@ page contentType="text/html; charset=gbk"%&gt; 来告诉server你所要求的字符集。<br />
                2.在每个jsp页的head中定义：&lt;META HTTP-EQUIV="content-type" CONTENT="text/html; charset=gbk"&gt; 来告诉浏览器你所用的字符集。</font></code> </li>
            </ul>
            </td>
        </tr>
    </tbody>
</table>
<table style="border-collapse: collapse" bordercolor="#000000" height="1" cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td width="100%" bgcolor="#000080" height="19"><font color="#ffffff" size="2">总结：使用sitemesh最通常的途径：</font></td>
        </tr>
        <tr>
            <td width="100%" height="15">
            <p><font size="2">1.配置好环境，</font> </p>
            <p><font size="2">2.在WEB-INFO/decroators.xml中描述你将建立的包装器。</font> </p>
            <p><font size="2">3.开发在decroators.xml中描述的包装器，最好存放在/_decorators目录下</font></p>
            <p><font size="2">4.ok ，可以看看辛勤的成果了 :</font></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>：<a onclick="javascript:tagshow(event, 'sitemesh');" href="javascript:;" target="_self"><u><strong>sitemesh</strong></u></a>，一个不错的tiles替代方案，比tiles做的更漂亮优雅。本文是sitemesh官方推荐的入门文档，本来想自己翻译的，突然发现有人先行一步了，就转过来看吧。<br />
<br />
以前我通常<a onclick="javascript:tagshow(event, '%E4%BD%BF%E7%94%A8');" href="javascript:;" target="_self"><u><strong>使用</strong></u></a>旧式的方法来建立自己的<a onclick="javascript:tagshow(event, 'web');" href="javascript:;" target="_self"><u><strong>web</strong></u></a><a onclick="javascript:tagshow(event, '%E5%BA%94%E7%94%A8');" href="javascript:;" target="_self"><u><strong>应用</strong></u></a>：手工排版，仔细使用每一个字节使其工作在Unicode下，同时使用make文件来适应不同的CPU&#8230;&#8230;<br />
或许现在我们可以换一种方式。<br />
尽管我从没有感觉到需要使用assembly (CISC or RISC)来建立web应用，但也会偶尔觉得我的开发伙伴的工作相当繁琐。特别是我发现很多的开发者在痛苦的寻求一种比较好的方式来控制web应用的基本模块：例如那些页头、页尾、导航栏、打印页面、手持设备的轻量级页面，以及其他更多的问题。到了最后，令人惊异的是大部分人都采用了落后的includes和复制粘贴方式。<br />
根据经验，我可以采用在<u><font color="#0000ff"><a onclick="javascript:tagshow(event, 'java');" href="javascript:;" target="_self"><u><strong>java</strong></u></a>.net</font></u>上<a onclick="javascript:tagshow(event, '%E5%BC%80%E6%BA%90');" href="javascript:;" target="_self"><u><strong>开源</strong></u></a>的servlet 过滤器<a href="http://www.opensymphony.com/sitemesh/" target="_blank"><font color="#0000ff">SiteMesh</font></a>n来简单明了并优雅的解决这些问题。作为一种替代新的templating语言（XSLT）或部署您的页面到新的系统的解决方法，应用SiteMesh可以相当容易处理你的页面，这一切只需要普通的HTML，JSP，servlet(包括Struts)，以及其他常用的技术。<br />
工作原理SiteMesh利用了一种很少人知道的servlet规范实现了一种页面过滤器。设想一下，现在有一个简单的jsp页面用来返回当前的日期和时间。通常这个页面请求来到应用服务器，页面被处理，最后处理结果返回到web浏览器。SiteMesh作为一个页面过滤器，在页面被处理之后，返回web浏览器之前，对页面做了一些附加的操作。这个变化简单描述为图一和图二所示的附加步骤。<br />
<img title="点击图片可在新窗口打开" style="width: 400px; cursor: pointer" height="202" alt="" src="http://today.java.net/images/2004/03/sitemesh_fig1.gif" width="520" border="0" /><br />
<em>图一：普通页面处理情况</em><br />
<img title="点击图片可在新窗口打开" style="width: 400px; cursor: pointer" height="202" alt="" src="http://today.java.net/images/2004/03/sitemesh_fig2.gif" width="520" border="0" /><br />
<em>图二：SiteMesh对页面处理情况</em><br />
现在看一个简单的例子。<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&lt;title&gt;Simple Document&lt;/title&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
Hello World! &lt;br /&gt;<br />
&lt;%= 1+1 %&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;你会发现这个页面有一个title和body（类似普通的HTML页面）。你也会发现一小段JSP代码——它将会如同你期望的那样被处理。同时你可以使用任何你想使用的JSP语法和特性来替换这一小段代码。<br />
现在来看一个简单的SiteMesh "装饰（decorator）"页面。列表2显示了一个被SiteMesh调用的JSP页面。<br />
&lt;%@ taglib uri="sitemesh-decorator"<br />
prefix="decorator" %&gt;<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&lt;title&gt;<br />
My Site - &lt;decorator:title default="Welcome!" /&gt;<br />
&lt;/title&gt;<br />
&lt;decorator:head /&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&lt;h1&gt;&lt;decorator:title default="Welcome!" /&gt;&lt;/h1&gt;<br />
&lt;p&gt;&lt;decorator:body /&gt;&lt;/p&gt;<br />
&lt;p&gt;&lt;small&gt;<br />
(&lt;a<br />
href="?printable=true"&gt;printable version&lt;/a&gt;<img title="点击图片可在新窗口打开" style="cursor: pointer" alt="" src="http://blog.51766.com/images/smileys/wink.gif" border="0" /><br />
&lt;/small&gt;&lt;/p&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;查看这个装饰器（decorator），我们能看到一些有趣的东西。首先，在第一行申明了一个SiteMesh标签库。这个标签库包含了与原始页面一起工作时所需的所有东西。你能看到我们使用了两个SiteMesh的装饰标签（declared tags），<font face="新宋体">&lt;decorator:title&gt;</font>和<font face="新宋体">&lt;decorator:body&gt;</font>。不要惊讶于标签<font face="Courier New">&lt;decorator:title&gt;在</font>原始页面中显示<font face="Courier New">&lt;title&gt;标签</font>中的内容，<font face="新宋体">&lt;decorator:body&gt;</font>中的内容也是如此。我们在这个页面的HEAD和BODY元素都使用了同一个title标签。（We're making a few fairly radical changes to the page, including repeating the title both in the<font face="新宋体">HEAD</font>element as well as the<font face="新宋体">BODY</font>. ）同时，我们还增加了一个到可打印版本页面的链接。<br />
作为对照，图三显示了原始处理页面，图四显示了被修饰过的处理页面。留意被装饰页面在浏览器窗口显示的标题文字和HTML内容。同时也可以看到增加了一个可打印页面的链接——这个我们回头再说。<br />
<img title="点击图片可在新窗口打开" style="cursor: pointer" height="186" alt="" src="http://today.java.net/images/2004/03/sitemesh_fig3.gif" width="309" border="0" /><br />
<em>图三：原始未修饰页面</em><br />
<img title="点击图片可在新窗口打开" style="cursor: pointer" height="299" alt="" src="http://today.java.net/images/2004/03/sitemesh_fig4.gif" width="309" border="0" /><br />
<em>图四：被修饰页面</em><br />
很明显，对比起使用include（例如<font face="Courier New">&lt;jsp:include page="foo.jsp" flush="true" /&gt;</font>）来说，以这样的方式使用页头、页尾系统结构要清晰得多。这种方式更易移植、更易理解，同时也鼓励了JSP页面不再使用导航或其他类似的表现层代码。我发现在JSP页面中使用装饰器和CSS的组合比标准HTML的标签更容易去除格式信息。<br />
安装SiteMesh注意下面的屏幕截图是基于Windows XP Professional，<a href="http://jakarta.apache.org/tomcat/index.html" target="_blank"><font color="#0000ff">Tomcat 5.0.19</font></a>，和Java 2 SDK 1.4.2_03的环境之上的。在这里我假定你的Tomcat已经安装完毕并且可以正常工作了。你或许会有一些混淆，但我们已经成功地在Tomcat 4.1 和 WebLogic <a onclick="javascript:tagshow(event, '%E6%B5%8B%E8%AF%95');" href="javascript:;" target="_self"><u><strong>测试</strong></u></a>过，同时 SiteMesh 也支持大部分的web应用服务器。<br />
本文描述的SiteMesh 2.0.1可以在<a href="https://sitemesh.dev.java.net/servlets/ProjectDocumentList?folderID=542" target="_blank"><font color="#0000ff">下载</font></a>到。 在java.net 上SiteMesh's 的<a onclick="javascript:tagshow(event, '%E9%A1%B9%E7%9B%AE');" href="javascript:;" target="_self"><u><strong>项目</strong></u></a>库中有四个文件可以下载。<em>sitemesh-2.0.1.jar</em>是其核心 JAR 文件，<em>sitemesh-2.0.1-sources.zip</em>的作用正如同其名字所述，<em>sitemesh-example.war</em>则提供了一个复杂的例子用来显示一些SiteMesh的高级特性。<br />
为了使描述更加简单，我们从<a href="https://sitemesh.dev.java.net/files/documents/887/2097/sitemesh-example.war" target="_blank"><em><font color="#0000ff">sitemesh-blank.war</font></em></a>文件开始。将该WAR文件放入Tomcat 的<em>webapps</em>目录，WAR包将自动解压显示内容（SoSo注：这里的前提是你的tomcat已经开始工作），如图五所示。<br />
<img title="点击图片可在新窗口打开" style="cursor: pointer" height="255" alt="" src="http://today.java.net/images/2004/03/sitemesh_fig5.gif" width="201" border="0" /><br />
<em>图五： SiteMesh_blank.WAR解开后的内容</em><br />
我们花点时间描述一下这些文件的作用。<br />
<em><strong>web.xml</strong></em>首先，<em>WEB-INF/web.xml</em>文件显示如列表3，这些语句用来安装SiteMesh 过滤器和标签库。如果你决定在一个已有的Web应用中使用SiteMesh，你必须把这些语句添加到你的<em>WEB-INF/web.xml</em>文件中。<br />
&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;<br />
&lt;!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"<br />
"http://java.sun.com/dtd/web-app_2_3.dtd"&gt;<br />
&lt;web-app&gt;<br />
&lt;!-- Start of SiteMesh stuff --&gt;<br />
&lt;filter&gt;<br />
&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;<br />
&lt;filter-class&gt;com.opensymphony.module.sitemesh.filter.PageFilter&lt;/filter-class&gt;<br />
&lt;/filter&gt;<br />
&lt;filter-mapping&gt;<br />
&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;<br />
&lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;<br />
&lt;/filter-mapping&gt;<br />
&lt;taglib&gt;<br />
&lt;taglib-uri&gt;sitemesh-page&lt;/taglib-uri&gt;<br />
&lt;taglib-location&gt;/WEB-INF/sitemesh-page.tld&lt;/taglib-location&gt;<br />
&lt;/taglib&gt;<br />
&lt;taglib&gt;<br />
&lt;taglib-uri&gt;sitemesh-decorator&lt;/taglib-uri&gt;<br />
&lt;taglib-location&gt;/WEB-INF/sitemesh-decorator.tld&lt;/taglib-location&gt;<br />
&lt;/taglib&gt;<br />
&lt;!-- End of SiteMesh stuff --&gt;<br />
&lt;/web-app&gt;注意：这里需要注意一下<font face="新宋体">url-pattern</font>的写法-- 如果使用的是Tomcat 5（而不是 Tomcat 4 ），需要将默认的*修改如*.jsp的形式。最新的servlet规范不再支持*样式。<br />
<em><strong>decorators.xml</strong></em><em>WEB-INF/decorators.xml</em>文件用来将一个装饰器名字同一个专门的JSP装饰文件绑定。作为一个例子，这里将JSP装饰文件minimal.jsp同一个称为handheld的装饰器绑定起来。<br />
&lt;decorators defaultdir="/decorators"&gt;<br />
&lt;decorator name="main" page="main.jsp"&gt;<br />
&lt;pattern&gt;*&lt;/pattern&gt;<br />
&lt;/decorator&gt;<br />
<br />
&lt;decorator name="panel" page="panel.jsp"/&gt;<br />
&lt;decorator name="printable" page="printable.jsp"/&gt;<br />
&lt;/decorators&gt;正如我们在代码列表里看到的一样，我们定义了三个装饰器，他们分别绑定了三个类似的JSP页面。我们可以看到一个默认装饰器（main.jsp），它将被默认运用于所有文件。<br />
缺省的，SiteMesh使用下面的逻辑来选择使用哪一个装饰器：
<table cellspacing="2" cellpadding="2" width="200" align="center" border="1">
    <tbody>
        <tr>
            <td>这个逻辑在<em>sitemesh-2.0.1.jar</em>包的<em>\com\opensymphony\module\sitemesh\factor\sitemesh-default.xml</em>文件里被描述。你可以针对诸如：客户端操作系统，web浏览器，用户代理等在<em>WEB-INF\sitemesh.xml</em>文件里，通过一个变量覆盖这个行为。(You can override this behavior. with a wide variety of<a href="http://www.opensymphony.com/sitemesh/api/com/opensymphony/module/sitemesh/mapper/package-summary.html" target="_blank"><font color="#0000ff">built-in mappers</font></a>for things like language, client operating system, web browser/user agent, etc. by creating a<em>WEB-INF\sitemesh.xml</em>file. ）可以在<em>sitemesh-example.war</em>找到例子。<br />
            </td>
        </tr>
    </tbody>
</table>
</p>
<ol type="1">
    <li>页面是否使用meta装饰器标签（meta. decorator tag）特别指定了一个装饰器？
    <li>页面是否是一个框架集（是的话则不应用装饰器）？
    <li>页面是否使用了<font face="新宋体">printable=true</font>参数（是的话则使用打印装饰器）
    <li>页面时候使用装饰器文件名特别指定了一个装饰器？
    <li>页面是否匹配<em>decorators.xml</em>文件里描述的样式？
    <ul>&nbsp;</ul>
        </li>
    </ol>
    <p>通常第一条规则仅用来确定该装饰器是否被使用（Conceptually, the first rule that evaluates to true determines the decorator that is used. ）在上面的例子中，当出现<font face="新宋体">printable=true</font>参数的时候，装饰器<font face="新宋体">printable.jsp</font>（规则 #3）替代了<font face="新宋体">main.jsp</font>（规则 #5）。在SiteMesh中，这些规则被描述为<em>mappers。</em><br />
    <em><strong>decorators/*.jsp</strong></em>这三个decorators目录下的文件是<em>decorators.xml</em>文件中描述的不同装饰器JSP文件。上面是一个简单的装饰器例子，在后面我们将讨论更复杂的示例。<br />
    <em><strong>sitemesh-2.0.1.jar</strong></em>这是SiteMesh最主要的二进制文件，通常被安装在<em>WEB-INF/lib</em>目录下。可以在<a href="http://www.opensymphony.com/sitemesh/api" target="_blank"><font color="#0000ff">www.opensymphony.com/sitemesh/api</font></a>找到这个库的javadoc。<br />
    <em><strong>*.tld</strong></em>SiteMesh使用两个标签库，但大多数人都只需要<em>sitemesh-decorator.tld</em>。你可以在<a href="http://www.opensymphony.com/sitemesh/tags.html" target="_blank"><font color="#0000ff">www.opensymphony.com/sitemesh/tags.html</font></a>找到相应的文档。我们已经讲述了最主要的标签：head，title和body。在下一章我们来讨论剩下的标签：getProperty。<br />
    SiteMesh高级特性SiteMesh的一个重要特性是使用原始HTML的meta标签（例如<font face="Courier New">&lt;meta. name="foo" c&gt;</font>）从基础页面传递信息到装饰器。作为一个例子，下面我们使用一个meta标签来定义HTML页面的作者。<br />
    &lt;html&gt;<br />
    &lt;meta. name="author" c&gt;<br />
    &lt;head&gt;<br />
    &lt;title&gt;Simple Document&lt;/title&gt;<br />
    &lt;/head&gt;<br />
    &lt;body&gt;<br />
    Hello World! &lt;br /&gt;<br />
    &lt;%= 1+1 %&gt;<br />
    &lt;/body&gt;<br />
    &lt;/html&gt;我们定义一个&#8220;smart&#8221;装饰器来研究meta标签，如果出现这个标签，则可以得到一个相应的HTML：<br />
    &lt;%@ taglib uri="sitemesh-decorator" prefix="decorator" %&gt;<br />
    &lt;decorator:usePage id="myPage" /&gt;<br />
    &lt;html&gt;<br />
    &lt;head&gt;<br />
    &lt;title&gt;My Site -<br />
    &lt;decorator:title default="Welcome!" /&gt;<br />
    &lt;/title&gt;<br />
    &lt;decorator:head /&gt;<br />
    &lt;/head&gt;<br />
    <br />
    &lt;body&gt;<br />
    &lt;h1&gt;&lt;decorator:title default="Welcome!" /&gt;&lt;/h1&gt;<br />
    &lt;h3&gt;<br />
    &lt;a href="mailto:&lt;decorator:getProperty property="meta.author"<br />
    default="staff@example.com" /&gt;"&gt;<br />
    &lt;decorator:getProperty property="meta.author"<br />
    default="staff@example.com" /&gt;<br />
    &lt;/a&gt;&lt;/h3&gt;&lt;hr /&gt;<br />
    &lt;decorator:body /&gt;<br />
    &lt;p&gt;&lt;small&gt;<br />
    (&lt;a href="?printable=true"&gt;printable version&lt;/a&gt;<img title="点击图片可在新窗口打开" style="cursor: pointer" alt="" src="http://blog.51766.com/images/smileys/wink.gif" border="0" /><br />
    &lt;/small&gt;<br />
    &lt;/p&gt;<br />
    &lt;/body&gt;<br />
    &lt;/html&gt;可以看到我们使用了<font face="Courier New">getProperty标签</font>的一个默认属性——如果没有指定author，我们就设定其为staff。如果你决定使用这个模型储存页面的meta数据，你或许需要和你的开发伙伴一起来确定将使用什么标签以及如何使用他们。简单的，你或许想要使用meta标签来描述诸如页面作者及时间戳之类的东西。更复杂一些，你或许会想像XML文件一样标准化的管理你的站点导航，同时使用meta标签来通过页面节点转到装饰器。（At the complex end, you may do things like standardize on an XML file to manage your site navigation and use a<font face="新宋体">meta</font>tag to pass the page's node to the decorator. ）<br />
    图六显示了应用上面的装饰器JSP页面之后生成的结果。<br />
    <img title="点击图片可在新窗口打开" style="cursor: pointer" height="359" alt="" src="http://today.java.net/images/2004/03/sitemesh_fig6.gif" width="392" border="0" /><br />
    <em>图六：meta标签显示</em><br />
    这些页面属性非常强大，并且拥有着很多不同的特性，并不仅止于meta标签（<a href="http://www.opensymphony.com/sitemesh/api/com/opensymphony/module/sitemesh/HTMLPage.html" target="_blank"><font color="#0000ff">常用页面特性列表</font></a>）。使用SiteMesh一段时间之后，你就会开始思考HTML和JSP作为一种简单标记语言的机制——接近最原始的HTML——无需操作就可以完整的切换到XML/XSL 或其他模版引擎。<br />
    小结综上所述，SiteMesh 提供了一个强大、易用、易结合的机制来使用页面模版。可以想象，它将会有很广泛的用户群。例如，你可以定义一个装饰器针对不同的浏览器输出额外的页面调试信息（和特定web浏览器结合之后将产生一个特别的功能，你可以强制指定使用某一种用户代理）。你也可以定义一个装饰器产生stripped-down XML输出，用来进行简单的自动化测试。你甚至可以使用装饰器从其他页面提取内容，例如输出到一些简单的门户容器。<br />
    从<em>sitemesh-blank.war</em>入手比较容易，但我建议学习<em>sitemesh-example.war</em>以获取更多的特性和思想。<br />
    不论你如何使用SiteMesh，我都发现它将大量的代码从表现层中移到我的装饰器中，而无需学习一种新的编程语言或是模版系统。<br />
    对了，作为最后的补充，如果你仍然对组合建立web页面感兴趣，可以查看<a href="http://home.worldonline.dk/viksoe/asmil.htm" target="_blank"><font color="#0000ff">home.worldonline.dk/viksoe/asmil.htm</font></a>。<br />
    文章引用自：<a href="http://blog.51766.com/comments/zy/Weblog/1143682180134" target="_blank"><font color="#4c87cb"><strong>http://blog.51766.com/comments/zy/Weblog/1143682180134</strong></font></a><br />
    &nbsp;</p>
<img src ="http://www.blogjava.net/libin2722/aggbug/164593.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/libin2722/" target="_blank">礼物</a> 2007-12-02 09:44 <a href="http://www.blogjava.net/libin2722/articles/164593.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>struts2.0 注意事项，Tomcat 5.5 没有日志</title><link>http://www.blogjava.net/libin2722/articles/155195.html</link><dc:creator>礼物</dc:creator><author>礼物</author><pubDate>Tue, 23 Oct 2007 01:59:00 GMT</pubDate><guid>http://www.blogjava.net/libin2722/articles/155195.html</guid><wfw:comment>http://www.blogjava.net/libin2722/comments/155195.html</wfw:comment><comments>http://www.blogjava.net/libin2722/articles/155195.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/libin2722/comments/commentRss/155195.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/libin2722/services/trackbacks/155195.html</trackback:ping><description><![CDATA[1、只能使用 tomcat5.5以上版本<br />
2、tomcat5.5没有日志信息，需要在%tomcat%\common\classes下建立log4j.properties文件，内容如下<br />
&nbsp;
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #008080">&nbsp;1</span><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">log4j.rootLogger</span><span style="color: #000000">=</span><span style="color: #000000">info,Console,R<br />
</span><span style="color: #008080">&nbsp;2</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
</span><span style="color: #008080">&nbsp;3</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.Console</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.ConsoleAppender<br />
</span><span style="color: #008080">&nbsp;4</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.Console.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.PatternLayout<br />
</span><span style="color: #008080">&nbsp;5</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#log4j.appender.Console.layout.ConversionPattern</span><span style="color: #000000">=%</span><span style="color: #000000">d&nbsp;[</span><span style="color: #000000">%</span><span style="color: #000000">t]&nbsp;</span><span style="color: #000000">%-</span><span style="color: #000000">5p&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">c&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">m</span><span style="color: #000000">%</span><span style="color: #000000">n<br />
</span><span style="color: #008080">&nbsp;6</span><span style="color: #000000"><img id="Codehighlighter1_272_290_Open_Image" onclick="this.style.display='none'; Codehighlighter1_272_290_Open_Text.style.display='none'; Codehighlighter1_272_290_Closed_Image.style.display='inline'; Codehighlighter1_272_290_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_272_290_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_272_290_Closed_Text.style.display='none'; Codehighlighter1_272_290_Open_Image.style.display='inline'; Codehighlighter1_272_290_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" />log4j.appender.Console.layout.ConversionPattern</span><span style="color: #000000">=%</span><span style="color: #000000">d</span><span id="Codehighlighter1_272_290_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_272_290_Open_Text"><span style="color: #000000">{yy</span><span style="color: #000000">-</span><span style="color: #000000">MM</span><span style="color: #000000">-</span><span style="color: #000000">dd&nbsp;HH:mm:ss}</span></span><span style="color: #000000">&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">5p&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">c</span><span id="Codehighlighter1_298_300_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_298_300_Open_Text"><span style="color: #000000">{</span><span style="color: #000000">1</span><span style="color: #000000">}</span></span><span style="color: #000000">:</span><span style="color: #000000">%</span><span style="color: #000000">L&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">m</span><span style="color: #000000">%</span><span style="color: #000000">n<br />
</span><span style="color: #008080">&nbsp;7</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
</span><span style="color: #008080">&nbsp;8</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.R</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.DailyRollingFileAppender<br />
</span><span style="color: #008080">&nbsp;9</span><span style="color: #000000"><img id="Codehighlighter1_395_409_Open_Image" onclick="this.style.display='none'; Codehighlighter1_395_409_Open_Text.style.display='none'; Codehighlighter1_395_409_Closed_Image.style.display='inline'; Codehighlighter1_395_409_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_395_409_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_395_409_Closed_Text.style.display='none'; Codehighlighter1_395_409_Open_Image.style.display='inline'; Codehighlighter1_395_409_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" />log4j.appender.R.File</span><span style="color: #000000">=</span><span style="color: #000000">$</span><span id="Codehighlighter1_395_409_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_395_409_Open_Text"><span style="color: #000000">{catalina.home}</span></span><span style="color: #000000">/</span><span style="color: #000000">logs</span><span style="color: #000000">/</span><span style="color: #000000">tomcat.log&nbsp;<br />
</span><span style="color: #008080">10</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.appender.R.layout</span><span style="color: #000000">=</span><span style="color: #000000">org.apache.log4j.PatternLayout<br />
</span><span style="color: #008080">11</span><span style="color: #000000"><img id="Codehighlighter1_527_547_Open_Image" onclick="this.style.display='none'; Codehighlighter1_527_547_Open_Text.style.display='none'; Codehighlighter1_527_547_Closed_Image.style.display='inline'; Codehighlighter1_527_547_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_527_547_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_527_547_Closed_Text.style.display='none'; Codehighlighter1_527_547_Open_Image.style.display='inline'; Codehighlighter1_527_547_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" />log4j.appender.R.layout.ConversionPattern</span><span style="color: #000000">=%</span><span style="color: #000000">d</span><span id="Codehighlighter1_527_547_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_527_547_Open_Text"><span style="color: #000000">{yyyy.MM.dd&nbsp;HH:mm:ss}</span></span><span style="color: #000000">&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">5p&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">c</span><span id="Codehighlighter1_555_557_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_555_557_Open_Text"><span style="color: #000000">{</span><span style="color: #000000">1</span><span style="color: #000000">}</span></span><span style="color: #000000">(</span><span style="color: #000000">%</span><span style="color: #000000">L):&nbsp;&nbsp;</span><span style="color: #000000">%</span><span style="color: #000000">m</span><span style="color: #000000">%</span><span style="color: #000000">n<br />
</span><span style="color: #008080">12</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
</span><span style="color: #008080">13</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.logger.org.apache</span><span style="color: #000000">=</span><span style="color: #000000">info,&nbsp;R<br />
</span><span style="color: #008080">14</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />#log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]</span><span style="color: #000000">=</span><span style="color: #000000">DEBUG,&nbsp;R&nbsp;<br />
</span><span style="color: #008080">15</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.logger.org.apache.catalina.core</span><span style="color: #000000">=</span><span style="color: #000000">info,&nbsp;R<br />
</span><span style="color: #008080">16</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />log4j.logger.org.apache.catalina.session</span><span style="color: #000000">=</span><span style="color: #000000">info,&nbsp;R<br />
</span><span style="color: #008080">17</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span></div>
3、在%tomcat%\common\lib下加入，commons-logging.jar和log4j-1.2.14.jar<br />
4、工程中不能用eclipse生成的cglib需要使用cglib-2.2_beta1.jar<br />
 <img src ="http://www.blogjava.net/libin2722/aggbug/155195.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/libin2722/" target="_blank">礼物</a> 2007-10-23 09:59 <a href="http://www.blogjava.net/libin2722/articles/155195.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>