本文用一个非常简单的例子“helloDuke",介绍IoVC编程模型的一种实际场景。
在IoVC编程模型下的HelloDuke版本,功能没做任何增减,依然如下图所示:
但由于在程序中用到了IoVC思想,及facelets技术,因此,整个程序的目录结构更改如下:
helloDuke --duke.gif --greeting.xhtml --sameName.xhtml --WEB-INF --web.xml --faces-config.xml --operamasks.xml --classes --helloduke --GreetingBean.class
下面就让我们来完成此应用。
首先,我们来看一下老版本的greeting.jsp是怎样的:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <f:view> <h:form> <h2>Hello, my name is Duke. What is yours?</h2> <h:graphicImage url="duke.gif"></h:graphicImage> <h:outputText value="#{userBean.result}"/><br> <h:inputText value="#{userBean.name}"></h:inputText> <h:commandButton value="sayHello" action="#{userBean.sayHello}"/> </h:form> </f:view>
那么,在AOM 2.0(即Apusic OperaMasks 2.0)版本下,并且在IoVC编程思想下,greeting.xhtml又是怎样的呢?
<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"> <w:page title="helloDuke"> <w:form> <h2>Hello, my name is Duke. What is yours?</h2> <img src="duke.gif" /> <hutputText id="result"/><br/> <w:textField id="name"/> <w:button id="sayHello" /> </w:form> </w:page> </f:view>
我们的注意力不要被<w:>还是<h:>所影响,我们先假设这两者都是等价的。我们主要观察<h:outputText>、<w:textField> 以及<w:button> 这三个主要UI控件的写法。我们可以看到,在新版本中,<h:outputText> 和<w:textField>并没有指定value,而<w:button>也没有指定action,但这三者都有不同的id,并且,整个页面全部都是展现层相关信息,没有任何代码片断或 EL 表达式的引入。
那么,这三者的值以及动作事件,又是怎样和后台的JavaBean关联起来的呢?
首先,我们也是先熟悉一下老版本中的UserBean(在新版本中,它的名称改为GreetingBean)。
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 || "".equals(name.trim())) return "Please input your name."; else return "Hello " + name; } public Object sayHello() { if("duke".equalsIgnoreCase(name)) return "duke"; return null; } }
那么,在新版本中,上述逻辑变成怎样的呢?如下所示:
package helloduke; @ManagedBean(name="GreetingBean", scope=ManagedBeanScope.SESSION) public class GreetingBean { @Bind(id="result") private String result; @Bind(id="name") private String name; @Action(id="sayHello") public Object sayHello(){ if("duke".equalsIgnoreCase(name)) return "/sameName.xhtml"; return null; } @BeforeRender private void settingValues(boolean isPostBack){ if(this.name == null || "".equals(name.trim())) { result = "Please input your name."; } else { result = "Hello " + name; } } }
我们可以观察到,在result属性上,有一个@Bind(id="result")的annotation声明;同样,在name上,也有@Bind(id="name") 的声明,而在sayHello方法上,则有@Action(id="sayHello") 的声明。至此,我们恍然大悟:通过这样一些声明,<h:outputText>的值自动和result属性关联,<w:textField>的值自动和name属性关联,而<w:button> 的Action事件,则和sayHello方法关联。
等一下,这里有个问题:针对result属性和name属性,在AOM 2.0下,连setter/getter方法都没有?是的,完全可以忽略。
那么,result的值是在哪里设置的?请注意settingValues方法,它有一个@BeforeRender的声明,意思就是说:当页面在渲染前,请调用此方法。这就相当于一个回调函数,因此,对result属性的设置,我们就可以在此处进行处理。
好像一切都很完美,但是,还有一个问题,greeting.xhtml页面,是怎样和GreetingBean对应起来的?目前,你可以假设认为:这是通过命名规则获得的,但这部分内容已经超过本文所要介绍的范围, 请允许我在下一篇文章中介绍。