<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title></title>
    <description>张勇，现任金蝶中间件公司技术总监，资深软件开发专家，在Java及J2EE核心技术领域有逾十年的开发、管理经验。张勇先生2001年加入金蝶集团，是金蝶中央研究院最早一批J2EE核心专家，先后担任金蝶中间件公司Apusic Studio开发部经理、研发部经理、技术总监，成功主持开发出新一代Apusic应用服务器、Apusic Studio、Apusic MQ、Apusic ESB等产品，并率领研发团队全球第四家通过Java EE 5.0认证，获得金蝶集团首次设立的最高荣誉“杰出创新奖”。</description>
    <link>http://apusiczhang.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
          <item>
        <title>OperaMasks 2.0特性之三：输入校验</title>
        <author>apusiczhang</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://apusiczhang.javaeye.com">apusiczhang</a>&nbsp;
                    链接：<a href="http://apusiczhang.javaeye.com/blog/182587" style="color:red;">http://apusiczhang.javaeye.com/blog/182587</a>&nbsp;
          发表时间: 2008年04月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="plain">
<div class="titlepage">
<div>
<div><span class="section"><a href="#d0e13"><span style="color: #4a719a;">1. 前言</span></a></span> </div>
<div><span class="section"><a href="#d0e24"><span style="color: #4a719a;">2. 简单校验</span></a></span> </div>
<div><span class="section"><a href="#d0e71"><span style="color: #4a719a;">3. 客户端校验</span></a></span> </div>
<div><span class="section"><a href="#d0e106"><span style="color: #4a719a;">4. 自定义校验方法</span></a></span> </div>
<div><span class="section"><a href="#d0e130"><span style="color: #4a719a;">5. 完整上下文校验</span></a></span> </div>
<div><span class="section"><a href="#d0e149"><span style="color: #4a719a;">6. 总结</span></a></span></div>
<div></div>
<div></div>
</div>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="CLEAR: both"><a name="d0e13"></a>1.&nbsp;前言</h2>
</div>
</div>
</div>
<p>本教程介绍在 AOM 2.0中，是如何对用户的输入参数进行验证的。在阅读本文之前，我建议你首先阅读前两篇文章：</p>
<p><a href="http://www.operamasks.org/articles/magic-1/html_single" target="_top">http://www.operamasks.org/articles/magic-1/html_single</a></p>
<p><a href="http://www.operamasks.org/articles/magic-2/html_single" target="_top">http://www.operamasks.org/articles/magic-2/html_single</a></p>
<p>&nbsp;</p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="CLEAR: both"><a name="d0e24"></a>2.&nbsp;简单校验</h2>
</div>
</div>
</div>
<p>坦白说，我已经厌倦了介绍常规JSF引擎是如何实现用户输入校验的，无非就是在页面中加入： &lt;f:validateLength minimum="5" maximum="6" /&gt;诸如此类的代码。在我看来，倘若你了解了 AOM 是如何实现校验机制的，那么，你肯定无法再忍受传统的校验方式。现在，就让我们来体验一下吧！</p>
<p>我们依然围绕计算器这个例子。首先，我们希望用户输入的数值不能为空，那么， 我们只需要在CalcBean中做如下更改：</p>
<pre name="code" class="java">@Bind
Requiredprivate double first = 22.0;
@Bind
@Requiredprivate double second = 7.0;</pre>
<p>&nbsp;</p>
<p>请注意，我们只是在 first 及 second 这两个成员变量上增加了一个新的annotation：@Required，那么，运行结果是怎样的呢？</p>
<p>中文环境下：</p>
<div><img src="http://www.operamasks.org/articles/magic-3/html_single/images/calc_zh_CN_required.jpg" alt="" /></div>
<p>英文环境下：</p>
<div><img src="http://www.operamasks.org/articles/magic-3/html_single/images/calc_en_US_required.jpg" alt="" /></div>
<p>是不是非常简单？</p>
<p>再做个稍微复杂些的，我们希望：第一个参数必须位于 10 至 100 之间，如果输入参数不合法，则显示给用户我们的自定义异常信息，如何做？将 CalcBean 改成这样：</p>
<pre name="code" class="java"> @Bind
@Required
@ValidateDoubleRange(minimum=10, maximum=100, message="This number must be between 10 to 100 ")
private double first = 22.0;</pre>
<p>运行效果如下：</p>
<div><img src="http://www.operamasks.org/articles/magic-3/html_single/images/calc_en_US_range.jpg" alt="" /></div>
<p>&ldquo;等等，我希望这个错误信息也是多语言的，怎么办？&rdquo;</p>
<p>首先，我们修改一下properties文件</p>
<pre name="code" class="java"> #demo.LocalStrings_zh_CN.properties
CalcBean.firstRangeErrMessage=该数值必须位于10至100之间</pre>
<pre name="code" class="java">#demo.LocalStrings_en_US.properties
CalcBean.firstRangeErrMessage=This number must be between 10 to 100</pre>
<p>然后，我们修改一下CalcBean：</p>
<pre name="code" class="java">@LocalString
private Map&lt;String,String&gt; messages;
@Bind
@Required
@ValidateDoubleRange(minimum=10, maximum=100, message="<a name="???"></a><img src="http://www.operamasks.org/articles/magic-3/html_single/images/callouts/1.png" border="0" alt="1" />#{this.messages.firstRangeErrMessage}")<br />private double first = 22.0;</pre>
<p>请注意，在message中，我们也可以嵌入 EL表达式的。现在，让我们看一下中文的运行效果：</p>
<div><img src="http://www.operamasks.org/articles/magic-3/html_single/images/calc_zh_CN_range.jpg" alt="" /></div>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="CLEAR: both"><a name="d0e71"></a>3.&nbsp;客户端校验</h2>
</div>
</div>
</div>
<p>好像非常简单的就实现了用户校验的功能，但你可能又有新的疑问了：&ldquo;以前我在做这种输入校验时， 我可以在页面中嵌入一些 javascript，虽然我的开发工作量较大，但是这种校验是放在客户端的，性能及用户体验都很好。AOM 虽然可以方便我完成校验功能，但每一次校验，都要与服务器端交互，这岂非对性能造成很大的影响？&rdquo;。</p>
<p>你说的对，我完全明白你的意思，而且，我负责任的告诉你： AOM 能够满意你的所有要求！请在页面中加入如下代码：</p>
<pre name="code" class="xml">&lt;w:form id="calc" <a name="???"></a><img src="http://www.operamasks.org/articles/magic-3/html_single/images/callouts/1.png" border="0" alt="1" />clientValidate="true"&gt;
&lt;layout:panelGrid columns="3"&gt;
   ...
&lt;/layout:panelGrid&gt;
&lt;/w:form&gt;</pre>
<p>请注意，我只是加入一个属性：clientValidate="true"，那么，运行效果是怎样的呢？</p>
<div><img src="http://www.operamasks.org/articles/magic-3/html_single/images/calc_zh_CN_client.jpg" alt="" /></div>
<p>执行效果完全达到我们的预期目的，并且，当你点击&ldquo;加&rdquo;、&ldquo;减&rdquo;、&ldquo;乘&rdquo;、&ldquo;除&rdquo;这些按钮时，浏览器根本就没有和服务器端交互，我建议你可以装个 Firebug 监控一下，以证实我说的是真是假。</p>
<p>AOM 是怎么做到的呢？又是在变魔术？我们不妨打开页面生成的源代码看一下，其中包含这样一些代码片断：</p>
<pre name="code" class="xml">&lt;script type="text/javascript" language="Javascript"&gt;
document.forms['calc']._validators=[ new RequiredValidator('calc:first','数值一:: 校验错误，输入不能为空。','calc:j_id3'),
new FloatValidator('calc:first','该数值必须位于10至100之间','calc:j_id3',10.0,100.0),
new RequiredValidator('calc:second','数值二:: 校验错误，输入不能为空。','calc:j_id5')];
&lt;/script&gt;</pre>
<p>明白了吗？AOM 自动帮你生成了客户端的校验代码，而这一切，对你而言都是透明的，这就是 AOM 神奇魔力的其中之一！</p>
<p>但你可能又会问了：&ldquo;你举的这些例子太简单了，有时候我需要在客户端完成非常复杂的逻辑，譬如，我这个人好吉利， 我希望第一个参数不能是514，该怎么办？&rdquo;。</p>
<p>你逼我出狠招了！你可以在页面中嵌入一个&lt;ajax:clientValidator/&gt;，将页面修订成这样：</p>
<pre name="code" class="xml"> &lt;w:textField id="first"&gt;
&lt;ajax:clientValidator message="数值不能等于514"&gt;
if(value == 514) return false;
return true;
&lt;/ajax:clientValidator&gt;
&lt;/w:textField&gt;</pre>
<p>我们在&lt;ajax:clientValidator/&gt;标签中嵌入任意的 JavaScript 代码，并且，在这段 JavaScript 代码中，可以直接引用 "value" 这个变量，该变量就是控件传递给你需要进行校验的值，然后你可以通过 JavaScript 完成你想要完成的任何逻辑。上述示例的效果如下：</p>
<div><img src="http://www.operamasks.org/articles/magic-3/html_single/images/calc_zh_CN_client_514.jpg" alt="" /></div>
<p>&ldquo;但是，那个 message 能否以 IoVC 的思想放到CalcBean呢？&rdquo;</p>
<p>唉，你已经在页面中嵌入 JavaScript 代码了，你还指望什么 IoVC呢？</p>
<p>&nbsp;</p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="CLEAR: both"><a name="d0e106"></a>4.&nbsp;自定义校验方法</h2>
</div>
</div>
</div>
<p>回顾刚才介绍的校验方式，我们可能会有一些疑问：上文所列的校验方式都是基于Annotation的，但毕竟Annotation 的表述能力是有限的，而有时候，我们需要进行的校验逻辑是非常复杂的，那么，这个问题如何解决？</p>
<p>可惜，由于我所举的 Calculator 例子过于简单，要描述复杂的校验逻辑，无法举出一个适合的场景，我只能把客户端校验那个比较&ldquo;委琐&rdquo;的校验逻辑拿过来做以示意： 我们不希望用户输入的第一个参数为514，那么，我们该怎么做？最简单的做法是通过基于正则表达式的@ValidateRegexp的 Annotation，但你还可以定义自己的校验方法：</p>
<pre name="code" class="java">@Validate
private boolean validateFirst(double value) {
 return Double.compare(514, value) != 0;
}</pre>
<p>为什么 AOM 会自动调用此方法？第一，它有一个 @Validate 的 annotation 声明，其次，它的名称为：validateFirst 。哦，又是&ldquo;约定优于配置&rdquo;这一原则的体现。</p>
<p>执行效果如下：</p>
<div><img src="http://www.operamasks.org/articles/magic-3/html_single/images/calc_en_US_514.jpg" alt="" /></div>
<p>事实上，这个方法签名可以有很多种，除了直接返回boolean值的这种最简单形式，你还可以：</p>
<p>1) 标准写法： public void validate(FacesContext context, UIComponent component, Object value); 这是javax.faces.validator.Validator接口所定义的标准方法，采用这种写法可以得到当前正在校验的UI组件， 以获得更多的控制。</p>
<p>2) 简略写法 public boolean validate(Object value); 对输入值进行校验，如果成功则返回true，否则返回false。当采用这种写法时最好设置 @Validate 标注的message属性，用于提供出错信息。</p>
<p>3) 返回不同出错信息的简略写法 public String validate(Object value); 当需要根据不同的校验结果显示不同的出错信息时可以采用这种写法，当方法返回null时表示校验成功， 否则将返回值作为出错信息。注意在返回的字符串中可以包含EL表达式，因此可以很容易地实现国际化 而不是硬编码的固定字符串。</p>
<p>4) 抛出ValidatorException的简略写法 public void validate(Object value) throws ValidatorException; 同第三种方式类似，只不过将出错信息包含在ValidatorException中抛出。</p>
<p>&nbsp;</p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="CLEAR: both"><a name="d0e130"></a>5.&nbsp;完整上下文校验</h2>
</div>
</div>
</div>
<p>你可能又提出一个新的问题：&ldquo;刚才所有的验证，无论是基于 Annotation的，还是用自定义方法的，无论是服务器端校验，还是客户端校验，都是对单个控件的值进行校验，但有时候， 我需要在完整上下文中进行校验，这种情况又该如何实现呢？&rdquo;</p>
<p>这种情况下，你可以在某个具体的 Action 中进行校验。举个简单的例子，众所周知，除数是不能为零的。在这种场景下，你需要知道完整的上下文：即需要知道 second 的具体数值，还需要知道用户点击的是哪个operator，那么，这种逻辑如何实现？你可以对 CalcBean 进行这样的修订：</p>
<pre name="code" class="java"> @Action
public void divide() {
  if (second == 0) {
    <a name="???"></a><img src="http://www.operamasks.org/articles/magic-3/html_single/images/callouts/1.png" border="0" alt="1" />FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Divide by zero", null);
    <a name="???"></a><img src="http://www.operamasks.org/articles/magic-3/html_single/images/callouts/2.png" border="0" alt="2" />FacesContext.getCurrentInstance().addMessage("calc:second", message);
    return;
  }
  result = first / second;
}</pre>
<p>上述第1条语句无非是先 new 一个 FacesMessage，但 addMessage 方法中的 "calc:second" 是怎么回事呢？还记得我们的页面吗？</p>
<pre name="code" class="xml">&lt;w:form id="calc" clientValidate="true"&gt;
  ......
    &lt;h:outputLabel for="second"/&gt;
    &lt;w:textField id="second"/&gt;
    &lt;h:message for="second"/&gt;
  ......
&lt;/w:form&gt;</pre>
<p>哦，原来calc指的是 form的id，而second，指的是 message的id。</p>
<p>&nbsp;</p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="CLEAR: both"><a name="d0e149"></a>6.&nbsp;总结</h2>
</div>
</div>
</div>
<p>本章节，我们简单体验了 AOM 2.0 对&ldquo;输入校验&rdquo;的处理，同样，我们也不需要再去阐述 AOM 和常规处理模式的差异，优劣高下，我想，各位读者自有判断。</p>
<p><span style="color: #ff0000;">更多技术文章，请见：</span><a href="http://www.operamasks.org/"><span style="color: #ff0000;">http://www.operamasks.org/</span></a></p>
</div>
</div>
          <br/>
          <span style="color:red;">
            <a href="http://apusiczhang.javaeye.com/blog/182587#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 14 Apr 2008 15:09:59 +0800</pubDate>
        <link>http://apusiczhang.javaeye.com/blog/182587</link>
        <guid>http://apusiczhang.javaeye.com/blog/182587</guid>
      </item>
          <item>
        <title>OperaMasks 2.0特性之二：国际化</title>
        <author>apusiczhang</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://apusiczhang.javaeye.com">apusiczhang</a>&nbsp;
                    链接：<a href="http://apusiczhang.javaeye.com/blog/182563" style="color:red;">http://apusiczhang.javaeye.com/blog/182563</a>&nbsp;
          发表时间: 2008年04月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="toc"><dl><dt><span class="section"><span class="link-external"><a href="../../../blog/182563#d0e13"><span style="color: #4a719a;">1. 前言</span></a></span></span> </dt><dt><span class="section"><span class="link-external"><a href="../../../blog/182563#d0e21"><span style="color: #4a719a;">2. 常规国际化的做法</span></a></span></span> </dt><dt><span class="section"><span class="link-external"><a href="../../../blog/182563#d0e48"><span style="color: #4a719a;">3. AOM 2.0 的国际化处理</span></a></span></span> </dt><dt><span class="section"><span class="link-external"><a href="../../../blog/182563#d0e67"><span style="color: #4a719a;">4. AOM的扩展能力</span></a></span></span> </dt><dt><span class="section"><span class="link-external"><a href="../../../blog/182563#d0e100"><span style="color: #4a719a;">5. 在程序中注入资源文件</span></a></span></span> </dt><dt><span class="section"><span class="link-external"><a href="../../../blog/182563#d0e133"><span style="color: #4a719a;">6. 总结</span></a></span></span></dt></dl></div>
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title" style="CLEAR: both"><a name="d0e13"></a>1.&nbsp;前言</h3>
</div>
</div>
</div>
<p>本教程介绍在 AOM 2.0中，是如何简化国际化多语言相关工作的。在阅读本文之前，我建议你首先阅读第一篇文章：</p>
<p><span class="link-external"><a href="http://www.operamasks.org/articles/magic-1/html_single" target="_top">http://www.operamasks.org/articles/magic-1/html_single</a></span></p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<p>&nbsp;</p>
<h3 class="title" style="CLEAR: both"><a name="d0e21"></a>2.&nbsp;常规国际化的做法</h3>
</div>
</div>
</div>
<p>假设我们现在希望让 Calculator 这个示例支持中英文，让我们先回顾一下常规JSF的实现手段：</p>
<p>首先，我们需要准备两个资源文件，分别是：</p>
<pre name="code" class="java">#demo.LocalStrings_en_US.properties
first.label=First:
second.label=Second:
result.label=Result:
add.label= +
subtract.label= -
multiply.label= *
divide.label = /</pre>
<p>&nbsp;&nbsp;</p>
<pre name="code" class="java">#demo.LocalStrings_zh_CN.properties
first.label=数值一:
second.label=数值二:
result.label=结果:
add.label= +
subtract.label= -
multiply.label= *
divide.label = /</pre>
<p>&nbsp;</p>
<p>当然，我们需要通过 Ant 将上述的LocalStrings_zh_CN.properties进行 native2ascii 的转换，这是基础知识，不是本文介绍的重点。</p>
<p>为了使用上述资源文件，我们的页面要改成这样：</p>
<pre name="code" class="xml">&lt;f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
  xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
  renderKitId="AJAX" xmlns:h="http://java.sun.com/jsf/html"&gt;
  &lt;f:loadBundle basename="demo.LocalStrings" var="msgs"/&gt;
  &lt;w:page title="Calculator"&gt;
    &lt;w:form id="calc"&gt;
      &lt;layout:panelGrid columns="3"&gt;
        &lt;h:outputLabel for="first" value="#{msgs['first.label']}"/&gt;
        &lt;w:textField id="first"/&gt;
        &lt;h:message for="first" value="#{msgs['second.label']}"/&gt;
        &lt;h:outputLabel for="second"/&gt;
        &lt;w:textField id="second"/&gt;
        &lt;h:message for="second"/&gt;
        &lt;h:outputLabel for="result" value="#{msgs['result.label']}"/&gt;
        &lt;h:outputText id="result"/&gt;
      &lt;/layout:panelGrid&gt;
      &lt;br/&gt;
      &lt;layout:panelGrid columns="4"&gt;
        &lt;w:button id="add" value="#{msgs['add.label']}"/&gt;
        &lt;w:button id="subtract" value="#{msgs['subtract.label']}"/&gt;
        &lt;w:button id="multiply" value="#{msgs['multiply.label']}"/&gt;
        &lt;w:button id="divide" value="#{msgs['divide.label']}"/&gt;
      &lt;/layout:panelGrid&gt;
    &lt;/w:form&gt;
  &lt;/w:page&gt;
&lt;/f:view&gt;</pre>
<p>&nbsp;</p>
<p>经过对页面进行上述修订，在中文环境下，页面运行效果如下图所示：</p>
<p>&nbsp;</p>
<div><img src="http://www.operamasks.org/articles/magic-2/html_single/images/calc_zh_CN.jpg" alt="" /></div>
<p>&nbsp;</p>
<p>而在英文环境中，运行效果是这样的：</p>
<p>&nbsp;</p>
<div><img src="http://www.operamasks.org/articles/magic-2/html_single/images/calc_en_US.jpg" alt="" /></div>
<p>&nbsp;</p>
<p>看上去好像也完成了我们的需求，但回过头来看看我们的页面，已经被我们改的面目全非。倘若这个页面是由美工设计的，请问，她知道什么叫做资源文件吗？她知道什么是 "#{msgs['add.label']}" 吗？</p>
<p>让我们忘掉这种丑陋的做法吧，看看 AOM 会带来怎样的魔力！</p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<p>&nbsp;</p>
<h3 class="title" style="CLEAR: both"><a name="d0e48"></a>3.&nbsp;AOM 2.0 的国际化处理</h3>
</div>
</div>
</div>
<p>首先，让我们把页面恢复成原先那整洁的基于IoVC原理的页面：</p>
<pre name="code" class="xml">&lt;f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
  xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
  renderKitId="AJAX" xmlns:h="http://java.sun.com/jsf/html"&gt;	
  &lt;w:page title="Calculator"&gt;
    &lt;w:form id="calc"&gt;
      &lt;layout:panelGrid columns="3"&gt;
        &lt;h:outputLabel for="first"/&gt;
        &lt;w:textField id="first"/&gt;
        &lt;h:message for="first"/&gt;
        &lt;h:outputLabel for="second"/&gt;
        &lt;w:textField id="second"/&gt;
        &lt;h:message for="second"/&gt;
        &lt;h:outputLabel for="result"/&gt;
        &lt;h:outputText id="result"/&gt;
      &lt;/layout:panelGrid&gt;
      &lt;br/&gt;
      &lt;layout:panelGrid columns="4"&gt;
        &lt;w:button id="add"/&gt;
        &lt;w:button id="subtract"/&gt;
        &lt;w:button id="multiply"/&gt;
        &lt;w:button id="divide"/&gt;
      &lt;/layout:panelGrid&gt;
    &lt;/w:form&gt;
  &lt;/w:page&gt;
&lt;/f:view&gt;</pre>
<p>我们继续保留 LocalStrings_en_US.properties 以及 LocalStrings_zh_CN.properties这 两个资源文件，但为了做到多语言，我们唯一需要做的事情是，将这两个资源文件的内容修订成如下内容：</p>
<pre name="code" class="java">#demo.LocalStrings_en_US.properties
CalcBean.first.label=First:
CalcBean.second.label=Second:
CalcBean.result.label=Result:
CalcBean.add.label= +
CalcBean.subtract.label= -
CalcBean.multiply.label= *
CalcBean.divide.label = /</pre>
<pre name="code" class="java">#demo.LocalStrings_zh_CN.properties
CalcBean.first.label=数值一:
CalcBean.second.label=数值二:
CalcBean.result.label=结果:
CalcBean.add.label= +
CalcBean.subtract.label= -
CalcBean.multiply.label= *
CalcBean.divide.label = /</pre>
<p>换言之，我们只是在资源串中的key上，加了一个限定词：CalcBean，然后，让我们运行这个页面。</p>
<p>你会发觉：哇，页面已经是多语言的了，这就是你想要的！</p>
<p>但回顾你做的工作，你会发觉，这是多么的简单，多么的享受！</p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<p>&nbsp;</p>
<h3 class="title" style="CLEAR: both"><a name="d0e67"></a>4.&nbsp;AOM的扩展能力</h3>
</div>
</div>
</div>
<p>我们现在希望对这个示例扩展一下：当鼠标移到第一个&lt;w:textFiled&gt;时，希望能够显示提示&ldquo;请输入第一个参数&rdquo;；当鼠标移到add button时，希望能够显示提示&ldquo;将这些数值相加&rdquo;。那么，我们只需要扩展一下这两个资源文件：</p>
<pre name="code" class="java">#demo.LocalStrings.properties
CalcBean.first.description=Please input the first number
CalcBean.add.description=Add these numbers
</pre>
<pre name="code" class="java">#demo.LocalStrings_zh_CN.properties
CalcBean.first.description=请输入第一个数值
CalcBean.add.description=将数值相加</pre>
<p>然后，我们重新运行此页面，你会发觉，你预期的效果已经达到了！</p>
<p>&nbsp;</p>
<div>
<div><img src="http://www.operamasks.org/articles/magic-2/html_single/images/calc_zh_CN_tooltip.jpg" alt="" /></div>
<div><img src="http://www.operamasks.org/articles/magic-2/html_single/images/calc_en_US_tooltip.jpg" alt="" /></div>
</div>
<div>&nbsp;</div>
<p>我们还可以做的更好！</p>
<p>假设我们有这样一种场景：&ldquo;add&rdquo;这个Button，在中文环境下显示&ldquo;加&rdquo;，在英文环境下显示&ldquo;Plus&rdquo;，由于语言的差异， 导致在不同语言下，button的宽度发生变化。我们希望，在中文环境下，此按钮的宽度为 30，而在英文环境下，此按钮的宽度为 60。那么，我们该怎么办？</p>
<p>解决这个问题的思路，无非要把宽度作为一个多语言资源拿出来放到properties文件中，但我们要怎么做呢？难道在页面中写入： &lt;w:button id="add" minWidth="#{msgs['add.minWidth]}"/&gt;？这样一来，岂非很丑陋？在 AOM 2.0中，我们只需要更改一下LocalStrings_zh_CN.properties 文件：</p>
<pre name="code" class="java">#demo.LocalStrings_zh_CN.properties
CalcBean.add.minWidth=30
CalcBean.subtract.minWidth=30
CalcBean.multiply.minWidth=30
CalcBean.divide.minWidth=30</pre>
<p>我们来看一下运行效果：</p>
<p>&nbsp;</p>
<div><img src="http://www.operamasks.org/articles/magic-2/html_single/images/calc_zh_CN_minWidth.jpg" alt="" /></div>
<p>我们再更改一下LocalStrings_en_US.properties：</p>
<pre name="code" class="java">#demo.LocalStrings_en_US.properties
CalcBean.add.minWidth=60
CalcBean.subtract.minWidth=60
CalcBean.multiply.minWidth=60
CalcBean.divide.minWidth=60</pre>
<p>注意，上述资源文件中设置最小宽度为60，比中文环境下的设置大了一倍，那么，在英文环境下，效果如下：</p>
<p>&nbsp;</p>
<div><img src="http://www.operamasks.org/articles/magic-2/html_single/images/calc_en_US_minWidth.jpg" alt="" /></div>
<p>是不是非常之简单？让我们再来看一看更高级的用法。</p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<p>&nbsp;</p>
<h3 class="title" style="CLEAR: both"><a name="d0e100"></a>5.&nbsp;在程序中注入资源文件</h3>
</div>
</div>
</div>
<p>假设我们现在有这样一种需求：当用户点击某一个操作时，result并不仅仅简单的显示一个结果， 我们还希望能够显示用户的操作是什么，譬如，当用户执行 1 + 2 操作时，中文环境下显示："数据 1 加 数据 2 等于 3"，英文环境下显示："Number 1 add number 2 equals 3"。换言之，我们现在要对多语言字符串进行参数化处理。在 AOM 2.0 中是怎样做的呢？</p>
<p>首先，我们需要把页面改一下：</p>
<pre name="code" class="xml">&lt;f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
  xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
  renderKitId="AJAX" xmlns:h="http://java.sun.com/jsf/html"&gt;
  &lt;w:page title="Calculator"&gt;
    &lt;w:form id="calc"&gt;
      &lt;layout:panelGrid columns="3"&gt;
        &lt;h:outputLabel for="first" /&gt;
        &lt;w:textField id="first" /&gt;
        &lt;h:message for="first" /&gt;
        &lt;h:outputLabel for="second" /&gt;
        &lt;w:textField id="second" /&gt;
        &lt;h:message for="second" /&gt;
        <a name="???"></a><a href="http://www.operamasks.org/articles/magic-2/html_single/images/callouts/1.png"></a><img src="http://www.operamasks.org/articles/magic-2/html_single/images/callouts/1.png" alt="" />&lt;layout:cell colspan="3" rowspan="1"&gt;
           &lt;h:outputText id="resultLabel" /&gt;
        &lt;/layout:cell&gt;
      &lt;/layout:panelGrid&gt;
      &lt;br /&gt;
      &lt;layout:panelGrid columns="4"&gt;
        &lt;w:button id="add" /&gt;
        &lt;w:button id="subtract" /&gt;
        &lt;w:button id="multiply" /&gt;
        &lt;w:button id="divide" /&gt;
      &lt;/layout:panelGrid&gt;
    &lt;/w:form&gt;
  &lt;/w:page&gt;
&lt;/f:view&gt;</pre>
<p>请注意，我们将&lt;h:outputText&gt;进行了修订，它占据了三列，id改为resultLabel。</p>
<p>然后，我们需要修订 CalcBean，修订如下：</p>
<pre name="code" class="java">@ManagedBean(scope = ManagedBeanScope.REQUEST)
public class CalcBean {

  @Bind
  private double first = 22.0;

  @Bind
  private double second = 7.0;

  @Bind
  private String resultLabel;

  /**
  * 注入资源文件
  */
  @LocalString
  private Map&lt;String,String&gt; messages;

  /**
   * 用来保存计算结果
   */
  private double result = 0;

  /**
   * 用来保存用户的操作符
   */
  private String operator = "";

  @Action
  public void add() {
    result = first + second;
   operator = "+";
  }

  @Action
  public void subtract() {
    result = first - second;
    operator = "-";
  }

  @Action
  public void multiply() {
    result = first * second;
    operator = "*";
  }

  @Action
  public void divide() {
    result = first / second;
    operator = "/";
  }
 
  @BeforeRender
  private void beforeRender(boolean isPostBack) {
    resultLabel = MessageFormat.format(messages.get("resultLabel"), first, operator, second, result);
  }
}
</pre>
<p>请注意，在CalcBean中，我们声明了两个临时变量 result 和 operator 来保存用户的计算结果及操作符，另外，声明了一个 @BeforeRender 的方法，意思就是告诉AOM，在你决定渲染前，请调用此方法。 我们在这个方法中，设置 resultLabel的具体值。那么，资源文件是怎样获取得呢？非常简单，只需要在前面声明一个private @LocalString Map&lt;String,String&gt; messages 即可。</p>
<p>再来看一下我们的资源文件：</p>
<pre name="code" class="java">#demo.LocalStrings_en_US.properties
CalcBean.resultLabel=Number {0} {1} number {2} equals {3}
</pre>
<pre name="code" class="java">#demo.LocalStrings_zh_CN.properties
CalcBean.resultLabel=数值 {0} {1} 数值 {2} 等于 {3}
</pre>
<p>我们在获取上述资源以后，只需要对其进行一下 format，将参数传递进去，即可获得我们期望的结果：</p>
<p>&nbsp;</p>
<div>
<div><img src="http://www.operamasks.org/articles/magic-2/html_single/images/calc_en_US_msg_para.jpg" alt="" /></div>
</div>
<p>等等，这里好像有一个疑问：你只是帮我把资源文件的获取简化了，但在对资源字符串的解析上，AOM好像并没有带来任何改进， 我还是需要调用 MessageFormat.format 方法，在这方面上，AOM能否带来一些便利呢？要知道，我可是非常懒惰的。</p>
<p>OK，我只能说：AOM 的 ELite 对资源文件的处理是非常简单的，简单到令人之发指，但同时，这也超出了本章所要阐述的范围，且留待下一章节分解吧。</p>
<p>&nbsp;</p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<h3 class="title" style="CLEAR: both"><a name="d0e133"></a>6.&nbsp;总结</h3>
</div>
</div>
</div>
<p>本章节，我们体会了 AOM 2.0 对国际化的处理，我想，我们已经不需要再去阐述 AOM 和常规处理模式的差异了，再次重申：AOM，确实是为&ldquo;懒人&rdquo;准备的。</p>
<p><span style="color: #ff0000;">更多技术文章，请见：</span><a href="http://www.operamasks.org/"><span style="color: #ff0000;">http://www.operamasks.org/</span></a></p>
</div>
          <br/>
          <span style="color:red;">
            <a href="http://apusiczhang.javaeye.com/blog/182563#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 14 Apr 2008 14:07:26 +0800</pubDate>
        <link>http://apusiczhang.javaeye.com/blog/182563</link>
        <guid>http://apusiczhang.javaeye.com/blog/182563</guid>
      </item>
          <item>
        <title>OperaMasks 2.0特性之一：约定优于配置</title>
        <author>apusiczhang</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://apusiczhang.javaeye.com">apusiczhang</a>&nbsp;
                    链接：<a href="http://apusiczhang.javaeye.com/blog/176579" style="color:red;">http://apusiczhang.javaeye.com/blog/176579</a>&nbsp;
          发表时间: 2008年03月27日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="toc"><dl><dt><span class="section"><span class="link-external"><a href="../../../blog/176579#d0e10"><span style="color: #4a719a;">1. 概述</span></a></span></span> </dt><dt><span class="section"><span class="link-external"><a href="../../../blog/176579#d0e11"><span style="color: #4a719a;">2. 构建基本页面</span></a></span></span> </dt><dt><span class="section"><span class="link-external"><a href="../../../blog/176579#d0e12"><span style="color: #4a719a;">3. 完成Life Bean</span></a></span></span> </dt><dt><span class="section"><span class="link-external"><a href="../../../blog/176579#d0e13"><span style="color: #4a719a;">4. 约定优于配置</span></a></span></span> </dt><dt><span class="section"><span class="link-external"><a href="../../../blog/176579#d0e14"><span style="color: #4a719a;">5. 一旦配置，那么，配置高于约定</span></a></span></span> </dt><dt><span class="section"><span class="link-external"><a href="../../../blog/176579#d0e15"><span style="color: #4a719a;">6. 总结</span></a></span></span></dt></dl></div>
<div class="section" lang="en">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a name="d0e10"></a><span style="font-size: small;">1.&nbsp;概述</span></h2>
</div>
</div>
</div>
<p>在本系列教程中，我们将通过一个小例子：Calculator，来体会一下Apusic OperaMasks 2.0的特性。</p>
<p>&nbsp;</p>
<p>本文中，将围绕的例子如下图所示：</p>
<p>&nbsp;</p>
<p><img src="http://www.operamasks.org/articles/magic-1/html_single/images/calculator.jpg" border="0" alt="" width="439" height="381" /></p>
<p>&nbsp;</p>
<p>现在，就让我们开始体验一下Apusic OperaMasks 2.0的神奇。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a title="d0e11" name="d0e11"></a><span style="font-size: small;">2.&nbsp;构建基本页面</span></h2>
</div>
</div>
</div>
<p>首先，让我们打开Apusic Studio，先画出这样一个页面：</p>
<p>&nbsp;</p>
<p><img src="http://www.operamasks.org/articles/magic-1/html_single/images/studio.jpg" border="0" alt="" width="741" height="650" /></p>
<p>&nbsp;</p>
<p>这个页面的代码如下：</p>
<p>&nbsp;</p>
<pre name="code" class="xml">&lt;f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
  xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
  renderKitId="AJAX" xmlns:h="http://java.sun.com/jsf/html"&gt;
  &lt;w:page title="Calculator"&gt;
    &lt;w:form id="calc"&gt;
      &lt;layout:panelGrid columns="3"&gt;
        &lt;h:outputLabel for="first"/&gt;
        &lt;w:textField id="first"/&gt;
        &lt;h:message for="first"/&gt;
        &lt;h:outputLabel for="second"/&gt;
        &lt;w:textField id="second"/&gt;
        &lt;h:message for="second"/&gt;
        &lt;h:outputLabel for="result"/&gt;
        &lt;h:outputText id="result"/&gt;
      &lt;/layout:panelGrid&gt;
      &lt;br/&gt;
      &lt;layout:panelGrid columns="4"&gt;
        &lt;w:button id="add"/&gt;
        &lt;w:button id="subtract"/&gt;
        &lt;w:button id="multiply"/&gt;
        &lt;w:button id="divide"/&gt;
      &lt;/layout:panelGrid&gt;
    &lt;/w:form&gt;
  &lt;/w:page&gt;
&lt;/f:view&gt;</pre>
<p>&nbsp;</p>
<p>此页面的解释：在页面的上半部分，放了两个&lt;w:textField&gt;，其id分别是&ldquo;first&rdquo;及&ldquo;second&rdquo;，还有一个 &lt;h:outputText&gt;，其id为&ldquo;result&rdquo;，页面下半部分放了四个&lt;w:button&gt;，其id分别是&ldquo;add&rdquo;、&ldquo;subtract&rdquo;、&ldquo;multiply&rdquo;及&ldquo;divide&rdquo;。OK，我们现在来运行一下这个页面，效果如下：</p>
<p>&nbsp;</p>
<p><img src="http://www.operamasks.org/articles/magic-1/html_single/images/calc_1.jpg" border="0" alt="" width="439" height="381" /></p>
<p>&nbsp;</p>
<p>和我们的预期差不多。下面，让我们来做一下后台的Lite Bean（在AOM 2.0中，将Managed Bean扩展成Lite Bean，详细资料请参考AOM 2.0参考手册），如果你用的是Apusic Studio，那么，在你新建这个页面的时候，这个Lite Bean已经自动帮助你生成了。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<div class="section">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a title="d0e12" name="d0e12"></a><span style="font-size: small;">3.&nbsp;完成Lite Bean</span></h2>
</div>
</div>
</div>
<p>这个LiteBean的基本代码如下：</p>
<p>&nbsp;</p>
<pre name="code" class="java">@ManagedBean(scope = ManagedBeanScope.REQUEST)
public class CalcBean {
  @Bind
  private double first = 22.0;
  @Bind
  private double second = 7.0;
  @Bind
  private double result;
  @Action
  public void add() {
    result = first + second;
  }
  @Action
  public void subtract() {
    result = first - second;
  }
  @Action
  public void multiply() {
    result = first * second;
  }
  @Action
  public void divide() {
    result = first / second;
  }
} </pre>
<p>&nbsp;</p>
<p>上述代码的解释如下：首先，我们声明了3个成员变量，分别是：first、second和result，请注意，他们的命名，和页面中相关控件的id是一样的，并且，它们都有一个@Bind 的annotation。同时，我们也声明了四个方法，分别是：add、subtract、multiply和divide，同样的，它们的命名也和页面中的四个&lt;w:button&gt;的id保持一致，而且，它们也都有@Action 的annotation声明。</p>
<p>&nbsp;</p>
<p>现在，让我们运行一下这个页面，我们来看看，会发生什么情况？</p>
<p>&nbsp;</p>
<p><img src="http://www.operamasks.org/articles/magic-1/html_single/images/calc_2.jpg" border="0" alt="" width="439" height="381" /></p>
<p>&nbsp;</p>
<p>哇，一切都OK了！我们要的功能已经全部具备了！</p>
<p>&nbsp;</p>
<p>这是怎么回事？印象中，我们好像并没有指定输入参数的label是什么吧，好像也没有指定四个button的value和action啊，AOM是怎么猜到我们想要让它做什么的？</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<div class="section">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a title="d0e13" name="d0e13"></a><span style="font-size: small;">4.&nbsp;约定优于配置</span></h2>
</div>
</div>
</div>
<p>记得一位朋友在向我介绍Ruby on Rails时，对RoR的两个特性赞不绝口，一个是Ruby这种动态语言（AOM 2.0中的ELite绝不逊色于Ruby），另一个就是&ldquo;约定优于配置&rdquo;（Convention Over Configuration) 这个原则。事实上，AOM 2.0 也将&ldquo;约定优于配置&rdquo;这条原则发挥得淋漓尽致。以上述代码为例：在页面中有个 &lt;h:outputLabel for="first"/&gt;，但我们并没有指定它的确切值，那么，AOM会认为，此label的值默认就是这个id，且首字母大写；&lt;w:textField id="first"/&gt;并没有指定它的value，那么，AOM会自动到后台的 CalcBean 中，找出所有带有@Bind标注且名称为 first 的属性，该textField 的值就对应此属性；对于&lt;w:button id="add"/&gt;，AOM会找出所有带有@Action标注且名称为add的方法，该button的Action就是此方法。</p>
<p>&nbsp;</p>
<p>看上去很美，但是，这样一来，是否意味着我的代码会受到很多限制呢？譬如，我不想让成员变量名称为first，那么，我该怎么办呢？</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
</div>
<div class="section">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a title="d0e14" name="d0e14"></a><span style="font-size: small;">5.&nbsp;一旦配置，那么，配置高于约定</span></h2>
</div>
</div>
</div>
<p>假如你希望将CalcBean中first属性的名称更改为first2，你可以这样做：</p>
<p>&nbsp;</p>
<pre name="code" class="java">@Bind(id="first")
private double first2 = 22.0;</pre>
<p>&nbsp;</p>
<p>假如你希望方法名不是add，改成plus，那么，你可以这样：</p>
<p>&nbsp;</p>
<pre name="code" class="java">@Action(id="add")
public void plus() {
  result = first + second;
}</pre>
<p>&nbsp;&nbsp;</p>
<p>假如你希望将Add按钮的名称改为&ldquo;Plus&rdquo;，那么，你可以这样：</p>
<p>&nbsp;</p>
<pre name="code" class="xml">&lt;w:button id="add" value="Plus"/&gt;</pre>
<p>&nbsp;</p>
<p>等等，将业务数据与展现层绑在一起，这不是违反了IoVC的原则吗？ 是，你说的对，那我们换个更好的做法，你可以这样：</p>
<p>&nbsp;</p>
<pre name="code" class="java">@Bind(id="add", attribute="value")
private String addLabel = "Plus";</pre>
<p>&nbsp;</p>
<p>好像还有一点不对劲，仅仅为了显示一个Label，我有必要在CalcBean中再增加一个属性吗？你说的对，但这是咱们第二篇文章要介绍的内容了。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both"><a title="d0e15" name="d0e15"></a><span style="font-size: small;">6.&nbsp;总结</span></h2>
</div>
</div>
</div>
<p>好了，我们只是简单的体会了一下AOM 2.0的一些新特性。文中所描述的计算器这个示例，在AOM 2.0中，只需要简单的十几行代码就轻松搞掂了。是不是非常省事？我记得我的老师袁红岗先生曾经跟我说过：聪明的程序员都是懒惰的。无疑，AOM 2.0是为&ldquo;懒人&rdquo;准备的，尤其是那些&ldquo;懒惰的&rdquo;、聪明的程序员们。</p>
<p>&nbsp;</p>
<p><span style="color: #ff0000;">更多技术文章，请见：</span><a href="http://www.operamasks.org/"><span style="color: #ff0000;">http://www.operamasks.org/</span></a></p>
<p>&nbsp;</p>
</div>
</div>
</div>
          <br/>
          <span style="color:red;">
            <a href="http://apusiczhang.javaeye.com/blog/176579#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 27 Mar 2008 01:07:44 +0800</pubDate>
        <link>http://apusiczhang.javaeye.com/blog/176579</link>
        <guid>http://apusiczhang.javaeye.com/blog/176579</guid>
      </item>
          <item>
        <title>IoVC实例分析：Hello Duke！</title>
        <author>apusiczhang</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://apusiczhang.javaeye.com">apusiczhang</a>&nbsp;
                    链接：<a href="http://apusiczhang.javaeye.com/blog/176576" style="color:red;">http://apusiczhang.javaeye.com/blog/176576</a>&nbsp;
          发表时间: 2008年03月27日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="titlepage"><div><div><h2 style="clear: both" class="title"><a name="d0e13" title="d0e13"></a><span style="font-size: small">1.&nbsp;概述</span></h2></div></div></div><p>本文用一个非常简单的例子&ldquo;helloDuke&quot;，介绍IoVC编程模型的一种实际场景。</p><p>&nbsp;</p><p>在IoVC编程模型下的HelloDuke版本，功能没做任何增减，依然如下图所示：</p><p>&nbsp;</p><p><img src="http://www.operamasks.org/articles/helloduck-iovc/html_single/images/overview.jpg" border="0" alt="" width="640" height="510" /></p><p>&nbsp;</p><p>但由于在程序中用到了IoVC思想，及facelets技术，因此，整个程序的目录结构更改如下：</p><p>&nbsp;</p><pre name="code" class="xml">helloDuke
  --duke.gif
  --greeting.xhtml
  --sameName.xhtml
  --WEB-INF
      --web.xml
      --faces-config.xml
      --operamasks.xml
      --classes
        --helloduke
          --GreetingBean.class</pre><p>&nbsp;</p><p>下面就让我们来完成此应用。</p><p>&nbsp;</p><p>&nbsp;</p><div class="titlepage"><div><div><h2 style="clear: both" class="title"><a name="d0e33" title="d0e33"></a><span style="font-size: small">2.&nbsp;应用的开发</span></h2></div></div></div><div class="titlepage"><div><div><h3 class="title"><a name="d0e36" title="d0e36"></a>2.1.&nbsp;greeting.xhtml</h3></div></div></div><p class="section">首先，我们来看一下老版本的greeting.jsp是怎样的：</p><p class="section">&nbsp;</p><div class="section"><pre name="code" class="xml">&lt;%@ taglib uri=&quot;http://java.sun.com/jsf/html&quot; prefix=&quot;h&quot; %&gt;
&lt;%@ taglib uri=&quot;http://java.sun.com/jsf/core&quot; prefix=&quot;f&quot;%&gt;
&lt;f:view&gt;
&lt;h:form&gt;
  &lt;h2&gt;Hello, my name is Duke. What is yours?&lt;/h2&gt;
  &lt;h:graphicImage url=&quot;duke.gif&quot;&gt;&lt;/h:graphicImage&gt;
  &lt;h:outputText value=&quot;#{userBean.result}&quot;/&gt;&lt;br&gt;
  &lt;h:inputText value=&quot;#{userBean.name}&quot;&gt;&lt;/h:inputText&gt;
  &lt;h:commandButton value=&quot;sayHello&quot; action=&quot;#{userBean.sayHello}&quot;/&gt;
&lt;/h:form&gt;
&lt;/f:view&gt;</pre></div><p class="section">&nbsp;</p><p class="section">那么，在AOM 2.0（即Apusic OperaMasks 2.0）版本下，并且在IoVC编程思想下，greeting.xhtml又是怎样的呢？</p><p class="section">&nbsp;</p><pre name="code" class="xml">&lt;f:view xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xmlns:f=&quot;http://java.sun.com/jsf/core&quot;
  xmlns:w=&quot;http://www.apusic.com/jsf/widget&quot; xmlns:layout=&quot;http://www.apusic.com/jsf/layout&quot;
  renderKitId=&quot;AJAX&quot; xmlns:h=&quot;http://java.sun.com/jsf/html&quot;&gt;
  &lt;w:page title=&quot;helloDuke&quot;&gt;
    &lt;w:form&gt;
      &lt;h2&gt;Hello, my name is Duke. What is yours?&lt;/h2&gt;
      &lt;img src=&quot;duke.gif&quot; /&gt;
      &lt;hutputText id=&quot;result&quot;/&gt;&lt;br/&gt;
      &lt;w:textField id=&quot;name&quot;/&gt;
      &lt;w:button id=&quot;sayHello&quot; /&gt;
    &lt;/w:form&gt;
  &lt;/w:page&gt;
&lt;/f:view&gt;</pre><p>&nbsp;&nbsp;</p><p>&nbsp;</p><p>我们的注意力不要被&lt;w:&gt;还是&lt;h:&gt;所影响，我们先假设这两者都是等价的。我们主要观察&lt;h:outputText&gt;、&lt;w:textField&gt; 以及&lt;w:button&gt; 这三个主要UI控件的写法。我们可以看到，在新版本中，&lt;h:outputText&gt; 和&lt;w:textField&gt;并没有指定value，而&lt;w:button&gt;也没有指定action，但这三者都有不同的id，并且，整个页面全部都是展现层相关信息，没有任何代码片断或 EL 表达式的引入。</p><p>&nbsp;</p><p>那么，这三者的值以及动作事件，又是怎样和后台的JavaBean关联起来的呢？</p><p>&nbsp;</p><div class="section"><div class="titlepage"><div><div><h2 style="clear: both" class="title"><a name="d0e51" title="d0e51"></a><span style="font-size: small">3.&nbsp;后台 JavaBean 的变化</span></h2></div></div></div><p>首先，我们也是先熟悉一下老版本中的UserBean（在新版本中，它的名称改为GreetingBean）。</p><p>&nbsp;</p><pre name="code" class="java">package helloduke;
public class UserBean {
private String name;
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getResult() {
    if(this.name == null || &quot;&quot;.equals(name.trim())) return &quot;Please input your name.&quot;;
     else return &quot;Hello &quot; + name;
  }
  public Object sayHello() {
    if(&quot;duke&quot;.equalsIgnoreCase(name)) return &quot;duke&quot;;
    return null;
  }
}</pre><p>&nbsp;</p><p>那么，在新版本中，上述逻辑变成怎样的呢？如下所示：</p><p>&nbsp;</p><pre name="code" class="java">package helloduke;
@ManagedBean(name=&quot;GreetingBean&quot;, scope=ManagedBeanScope.SESSION)
public class GreetingBean {
  @Bind(id=&quot;result&quot;)
  private String result;
  @Bind(id=&quot;name&quot;)
  private String name;
  @Action(id=&quot;sayHello&quot;)
  public Object sayHello(){
    if(&quot;duke&quot;.equalsIgnoreCase(name)) return &quot;/sameName.xhtml&quot;;    return null;
  }
  @BeforeRender
  private void settingValues(boolean isPostBack){
    if(this.name == null || &quot;&quot;.equals(name.trim())) {
         result = &quot;Please input your name.&quot;;
     }
    else {
      result = &quot;Hello &quot; + name;
     }
  }
}</pre><p>&nbsp;</p><p>我们可以观察到，在result属性上，有一个@Bind(id=&quot;result&quot;)的annotation声明；同样，在name上，也有@Bind(id=&quot;name&quot;) 的声明，而在sayHello方法上，则有@Action(id=&quot;sayHello&quot;) 的声明。至此，我们恍然大悟：通过这样一些声明，&lt;h:outputText&gt;的值自动和result属性关联，&lt;w:textField&gt;的值自动和name属性关联，而&lt;w:button&gt; 的Action事件，则和sayHello方法关联。</p><p>&nbsp;</p><p>等一下，这里有个问题：针对result属性和name属性，在AOM 2.0下，连setter/getter方法都没有？是的，完全可以忽略。</p><p>&nbsp;</p><p>那么，result的值是在哪里设置的？请注意settingValues方法，它有一个@BeforeRender的声明，意思就是说：当页面在渲染前，请调用此方法。这就相当于一个回调函数，因此，对result属性的设置，我们就可以在此处进行处理。</p><p>&nbsp;</p><p>好像一切都很完美，但是，还有一个问题，greeting.xhtml页面，是怎样和GreetingBean对应起来的？目前，你可以假设认为：这是通过命名规则获得的，但这部分内容已经超过本文所要介绍的范围， 请允许我在下一篇文章中介绍。</p><p>&nbsp;</p><div class="section"><div class="titlepage"><div><div><h2 style="clear: both" class="title"><a name="d0e70" title="d0e70"></a><span style="font-size: small">4.&nbsp;Apusic Studio的支持</span></h2></div></div></div><p>我们还可以做得更好，那就是Apusic Studio给予的全生命周期的开发支持。</p>&nbsp;&nbsp;</div></div><div class="section"><img src="http://www.operamasks.org/articles/helloduck-iovc/html_single/images/studio.jpg" border="0" alt="" width="775" height="626" /></div><div class="section">那么，Apusic Studio 对 IoVC 又提供了怎样的支持？在这里，我们提出了称为&quot;Smart DblClick&quot;的技术，针对任何控件对其双击，将自动弹出该控件 IoVC 支持的向导，以&lt;w:button&gt;为例，双击的效果如下：</div><div class="section"><img src="http://www.operamasks.org/articles/helloduck-iovc/html_single/images/btn_smart_dblclick.jpg" border="0" alt="" width="525" height="412" /></div><div class="section"><p>&nbsp;</p><p>看上去还不错，那么，为何不立即体验一下呢？</p><p>&nbsp;</p><div class="section"><div class="titlepage"><div><div><h2 style="clear: both" class="title"><a name="d0e81" title="d0e81"></a><span style="font-size: small">5.&nbsp;温馨提示</span></h2></div></div></div><p>IoVC的支持仅限于AOM 2.0版本，并请注意Apusic应用服务器及Apusic Studio的版本支持。在完成本文结束时，请使用AOM 2.0 M1，Apusic 应用服务器5.1 TP5，Apusic Studio 5.1 M5版本。&nbsp;</p></div></div>
          <br/>
          <span style="color:red;">
            <a href="http://apusiczhang.javaeye.com/blog/176576#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 27 Mar 2008 00:22:10 +0800</pubDate>
        <link>http://apusiczhang.javaeye.com/blog/176576</link>
        <guid>http://apusiczhang.javaeye.com/blog/176576</guid>
      </item>
          <item>
        <title>IoVC，一种新的编程思想</title>
        <author>apusiczhang</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://apusiczhang.javaeye.com">apusiczhang</a>&nbsp;
                    链接：<a href="http://apusiczhang.javaeye.com/blog/176066" style="color:red;">http://apusiczhang.javaeye.com/blog/176066</a>&nbsp;
          发表时间: 2008年03月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div class="section"><div class="titlepage"><div><div><h2 style="clear: both" class="title"><a name="d0e13" title="d0e13"></a><span style="font-size: small"><span style="font-size: small"><span style="font-size: small">1.&nbsp;概述</span></span></span></h2></div></div></div><p>长久以来，在Web编程中，一直很难克服的一个问题就是：展现层与业务数据纠缠在一起，无法进行良好的解耦， 从而造成应用系统的扩展性差，维护成本高。于是，出现了所谓的MVC框架，试图以 Model-View-Control 这种非常流行的设计模式，将两者有效的隔离开来。但回顾目前主流的 Web MVC 架构，它们所做的绝大部分工作无非是：将页面中控件的值取出打包成 Java Bean；再无非就是在帮助你完成页面导航的过程中，辅助你进行页面参数的传递与分析。这样一种&ldquo;简单 MVC&rdquo;架构，是无法完全解决&ldquo;展现层与业务数据完全解耦&rdquo;这个问题的。 一旦你的需求超越了框架的能力，那么，你将面对的依然是：不得不在展现层中嵌入大量的 Script 代码，可能是Java代码片断，也可能是大量tag-lib及EL表达式的引入。</p><p>&nbsp;</p></div><div class="section"><div class="titlepage"><div><div><h2 style="clear: both" class="title"><a name="d0e18" title="d0e18"></a><span style="font-size: small"><span style="font-size: small"><span style="font-size: small">2.&nbsp;什么是IoVC</span></span></span></h2></div></div></div><p>IoVC&mdash;&mdash;&ldquo;Inversion of View-Control&rdquo;，即&ldquo;视图控制反转&rdquo;，换言之：它能够把对&ldquo;View（即 UI 视图）的控制力&rdquo;注入到你的后台业务逻辑中。这样一来，你在编写业务逻辑的过程中，对 View 拥有足够的控制力，从而能够将展现层与业务逻辑完全的解耦。</p><p>&nbsp;</p><p>举一个场景：页面中有一个文本输入框，它的值对应后台的一个JavaBean的属性。我们首先来看一下传统的编程模型：</p><p>&nbsp;</p><pre name="code" class="java">页面：
&lt;w:textField value=&quot;#{myBean.value}&quot;/&gt;
后台：
public class MyBean {
    private String value;
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
}</pre><p>&nbsp;</p><p>此时，假设用户需要发生变化，我们需要设置文本输入框的tooltip，并且，它的值来自于后台 JavaBean 的另一个属性，那么，程序需要做如下调整：</p><p>&nbsp;</p><pre name="code" class="java">页面：
&lt;w:textField  value=&quot;#{myBean.value}&quot; tooltip=&quot;#{myBean.tooltip}&quot;/&gt;
后台：
public class MyBean {
    private String value;
    private String tooltip;
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }    public String getTooltip() {
        return tooltip;
    }
    public void setTooltip(String tooltip) {
        this.tooltip = tooltip;
    }
}</pre><p>&nbsp;</p><p>我们可以观察：在传统的编程模型下，如果页面逻辑发生变化，我们首先需要修改UI展现层，加上 tooltip=&quot;#{myBean.tooltip}&quot;　的语句，然后，再在后台Bean中设置此属性值。</p><p>那么，在IoVC编程模型下，情况又是怎样的呢？</p><p>&nbsp;</p><pre name="code" class="java">页面：
&lt;w:textField id=&quot;txt&quot;/&gt;
后台：
public class MyBean {
    @Bind(id=&quot;txt&quot;)
    private String value;
}</pre><p>&nbsp;</p><p>如果需要扩展文本编辑框的tooltip属性，只需要：</p><p>&nbsp;</p><pre name="code" class="java">页面：
&lt;w:textField id=&quot;txt&quot;/&gt;
后台：
public class MyBean {
    @Bind(id=&quot;txt&quot;)
    private String value;

        @Bind(id=&quot;txt&quot; att=&quot;tooltip&quot;)
    private String tooltip;
}</pre><p>&nbsp;</p><p>在IoVC编程模型下，Web页面不需要发生任何变化，你只需要在后台 Java Bean 中写上这样一行属性声明即可@Bind(id=&quot;txt&quot; att=&quot;tooltip&quot;) private String tooltip，甚至于你连传统的getter/setter都不需要。</p><p>&nbsp;</p><p>换言之，在传统的编程模型下，页面美工通过网页设计工具&ldquo;画&rdquo;出来的页面，程序员看不懂； 而如果程序员对页面进行修改，则页面美工又无法理解； 并且，如果要更改业务逻辑，程序员需要不断的维护页面内容，最终造成页面美工与程序员无法协同工作。而在 IoVC 的编程思想下，页面美工只需要给每个组件设置一个ID，程序员在后台的业务逻辑中，便拥有对页面 UI 元素的完全控制力。Web页面在美工完成之后，程序员再也无需因为需求的变更或者逻辑的变化，而再重新维护 Web页面内容。</p><p>&nbsp;</p><p>简而言之，IoVC是一种更好的MVC，是对MVC的一种高层次抽象。</p><p>&nbsp;</p><p>设想一下：日后美工人员画出来的页面（只要设置了正确的ID），程序员可以拿过来直接用，并且， 如果要对页面做调整（只要不是页面元素的增加或删除），程序员可以在自己熟悉的代码中直接设置，这岂非是一种很享受的境界？</p><p>&nbsp;</p><p><span style="color: #ff0000">更多技术文章，请见：</span><a href="http://www.operamasks.org/"><span style="color: #ff0000">http://www.operamasks.org/</span></a></p><p>&nbsp;</p></div>
          <br/>
          <span style="color:red;">
            <a href="http://apusiczhang.javaeye.com/blog/176066#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 25 Mar 2008 23:23:27 +0800</pubDate>
        <link>http://apusiczhang.javaeye.com/blog/176066</link>
        <guid>http://apusiczhang.javaeye.com/blog/176066</guid>
      </item>
      </channel>
</rss>