OperaMasks2.0开发实例入门之一:HelloWorld

1. 前言

本系列文章将从原始的HelloWorld应用讲起,逐步深入,到后面的在线酒店预订等应用,来介绍OperaMasks2.0应用的实际开发。 在阅读本文之前,我建议你阅读《OperaMasks2.0的神奇魔力》系列文章。

2. 实例介绍

干我们这行的,面对一个新的技术的时候,总是习惯于从经典的HelloWorld程序开始,实际上这也是最有效的入门方法,这里我们也世俗的从HelloWorld实例开发入手,毕竟它太经典了。
例子比较简单,在一个输入页面中输入,然后再另一个页面中显示你刚才的输入。
效果图(1):输入页面
效果图(2):结果页面

3. 开发与运行环境

开发环境
选择1:基于Eclipse的集成开发工具ApusicStudio,她能够很好的支持AOM的可视化开发(如下图),利用她开发AOM应用时,会自动帮你加入AOM的相关包和基本配置文件,并且内置Apusic应用服务器开发调试环境,而ApusicServer又自带最新的AOM包,所以,你可以迅速的开发,部署和运行你的AOM应用。所以笔者强烈建议使用ApusicStudio+Apusic
选择2:当然,你也可以使用MyEclipse,Eclipse甚至Editplus来开发应用。
(1)选择1:应用服务器: Apusic5.1(已内置OperaMasks2.0引擎) ,下载地址: 点这里
(2)选择2:Web容器:Tomcat6 ; OperaMasks2.0:下载地址: 点这里
OperaMasks2作为一款优秀的开发框架,并没有和哪个应用服务器有绑定的行为,所以,笔者这里采用的是Tomcat6作为本例运行的WEB容器。

4. 应用的JAR包

OK,现在让我们正式开始应用的编写。 首先,用你熟悉的工具建立一个标准的Web应用,起名为aom-example-hello,然后下载OperaMasks2,将解压后的根目录的jar文件及其lib目录下的jar文件拷贝到你建立的这个应用的WEB-INF/lib目录(因为本例没有使用spring,所以,没有把spring目录中的jar包拷贝出来)。
注意:如果你下载的OperaMasks版本低于2.0 m2,并且你想把开发的应用运行在Tomcat中,需要做些小小的调整: 1)打开拷贝到应用的WEB-INF/lib目录。 2)把elite.jar中的javax目录删除。 3)把javaee.jar拷贝到你的tomcat下的lib目录中。
调整后的应用WEB-INF/lib目录看起来是这个样子:
如果你使用的服务器是Apusic5.1最新版,就无需任何改动,他内置了AOM引擎。

5. 配置文件

从OperaMasks下载目录里,打开blank示例的war包,里面有OperaMasks需要使用的4个配置文件,直接拿出来拷贝到应用的WEB-INF目录底下(web.xml ,faces-config.xml,jsf-ui.tld,operamasks.xml)。
鉴于篇幅的原因,我就不具体贴出这4个文件的内容了,基本上,程序没有什么特别的地方,这些配置文件你是不需要改动的。

6. 背景知识

实现表示层和业务层的分离,这是J2EEWeb应用一直以来的理想,可惜众多的Web框架并没有真正实现这个目标。大多数框架的Web开发技术“脚本”味道很浓,在页面中混淆了大量用于显示逻辑的HTML 和用于业务逻辑的Java 代码,使得页面设计与程序开发无法分离;另一个更大的缺陷是脚本不能重用,这常常导致开发者不得不在页面之间进行复制-粘贴操作,进而导致同一段代码出现多个版本,从而使得程序的调试和设计极其错综复杂。而标签库作为一个补充,将Java代码从页面中剥离,也只是有限地实现了表现与逻辑的分离,始终没有摆脱代码和HTML页面揉和的问题。
著名的MVC模式强调视图层,控制层,业务层的分离,虽然传统的WEB开发框架都超着这个方向努力,然而他们大多数仍是这样一些工作:将页面中控件的值取出打包成 Java Bean;再无非就是在帮助你完成页面导航的过程中,辅助你进行页面参数的传递与分析。这样一种“简单 MVC”架构,是无法完全解决“视图层,控制层与业务数据完全解耦”这个问题的。 一旦你的需求超越了框架的能力,那么,你将面对的依然是:不得不在展现层中嵌入大量的 Script 代码,可能是Java代码片断,也可能是大量tag-lib及EL表达式的引入。
例如,下面的代码是大多数传统框架的代码形式:
 
   
<w:textField value= "#{helloBean.txt}"></w:textField>
可以看出,传统的开发框架的视图层是多么的“强势”,表面看其来好像是控制层逻辑helloBean决定了页面上txt的输出,其实helloBean只是挂了一个控制层的名而已,其幕后还是页面决定了自己显示,控制权在自己,如果它不调用#{helloBean.txt},你这个所谓的控制层,不就对视图失去了控制?并且,这里用户还会写上自己许多的Java片段,JS代码,EL表达式,各种自定义标签等等,进一步厄杀了控制层的作用,同时导致其MVC结构惨不忍睹,到后来用户都不知道页面复杂到什么程度了。 那么在OperaMasks中,情况是如何的呢?OperaMasks2.0提出了一个新的编程思想:IoVC--“Inversion of View-Control”,即“视图控制反转”,换言之:它能够把对“View(即 UI 视图)的控制力”注入到后面的控制逻辑中。这样一来,你在编写控制逻辑的过程中,对 View 拥有足够的控制力,从而能够将展现层与控制逻辑,业务逻辑完全的解耦。
例如,OperaMasks2.0下的页面代码形式:
 
   
@Bind(id=”txt”)
private String txt;
这里通过Annotation方式,将控制层和页面的txt控件进行了绑定,而页面层不知道这个事情,控制页面的显示及其内容是由控制层的类来完成的,这个类就是一个LiteBean。

7. hello.xhtml

上面讲了环境的配置,也简单了介绍了一些背景知识,下面我们开始程序的编写,我们从输入页面hello.xhtml入手。
这个页面比较简单,一个输入框,一个按钮。页面代码如下:
 
<? xml version ="1.0" encoding ="UTF-8" ?>
< f:view xmlns:f ="http://java.sun.com/jsf/core"
         xmlns ="http://www.w3.org/1999/xhtml"
         xmlns:h ="http://java.sun.com/jsf/html"
         xmlns:ui ="http://java.sun.com/jsf/facelets"
         xmlns:w ="http://www.apusic.com/jsf/widget"
         xmlns:ajax ="http://www.apusic.com/jsf/ajax"
         xmlns:layout ="http://www.apusic.com/jsf/layout"
         renderKitId ="AJAX" >
     < w:head >
         < w:stylesheet src ="/resources/css/example.css" />
     </ w:head >
     < w:page title ="HelloWorld Example" >
     < p />
     < h1 >HelloWorld Example </ h1 >
     < hr noshade ="noshade" />
     < p />
         < w:form >
             < layout:panelGrid columns ="2" >
                 < w:textField id ="txt" > </ w:textField >
                 < w:button id ="btnSubmit" />
             </ layout:panelGrid >
         </ w:form >
     </ w:page >
</ f:view >
 
(1)这里使用了Css文件,使得页面更加美观一些,你可以使用任何自己想要的CSS。
(2)为了让两个控件在一行里显示,使用一个布局组件。
(3)这是一个文本控件,用于你填入文本。
(4)你单击该控件后,会导航到结果页面。

8. result.xhtml

结果页面主要用来显示你刚才的输入:
 
<? xml version ="1.0" encoding ="UTF-8" ?>
< f:view xmlns:f ="http://java.sun.com/jsf/core"
         xmlns ="http://www.w3.org/1999/xhtml"
         xmlns:h ="http://java.sun.com/jsf/html"
         xmlns:ui ="http://java.sun.com/jsf/facelets"
         xmlns:w ="http://www.apusic.com/jsf/widget"
         xmlns:ajax ="http://www.apusic.com/jsf/ajax"
         xmlns:layout ="http://www.apusic.com/jsf/layout"
         renderKitId ="AJAX" >
     < w:head >
         < w:stylesheet src ="/resources/css/example.css" />
     </ w:head >
     < w:page title ="HelloWorld Example" >
     < p />
     < h3 >HelloWorld Example Result </ h3 >
     < hr noshade ="noshade" />
     < p />
         < w:form >
             < b >Your input is : </ b >  
             < h:outputLabel id ="message" />
         </ w:form >
     </ w:page >
</ f:view >
 
(1)输出信息用的outputLabel控件。

9. HelloBean.java

现在,我们开始编写我们的后台控制逻辑层的代码,首先我们看看控制视图hello.xhtml的HelloBean的内容:
 
package org.operamasks.example.hello;

import org.operamasks.faces.annotation.Accessible;
import org.operamasks.faces.annotation.Action;
import org.operamasks.faces.annotation.Bind;
import org.operamasks.faces.annotation.Label;
import org.operamasks.faces.annotation.ManagedBean;
import org.operamasks.faces.annotation.ManagedBeanScope;

1@ManagedBean(scope = ManagedBeanScope.SESSION)
public class HelloBean {

2@Bind
3@Accessible
private String txt;

4@Action
5@Label("OK")
public String btnSubmit() {
6return  "view:result";
}
}
(1)@ManagedBean这个Annotation指出,当前这个类HelloBean是个LiteBean(也可称之为ManagedBean),这个Bean的作用域范围是Session,这样,在整个会话期间都可以访问这个bean。
(2)@Bind指出,当前的HelloBean需要控制页面中一个元素,即通过HelloBean中的变量txt来控制页面中一个id=txt元素。这里,如果bean的变量和页面的元素名字不一样,需要对这个标注增加一个id属性,来明确告诉AOM2引擎,例如:
 
   
@Bind(id="txt")
private String myTxt;
id就是我们在页面中那个元素的id。
(3)@Accessible的意思是,其他的LiteBean能够访问到这个属性。因为,我们需要在另外一个LiteBean中访问HelloBean的txt属性的值,以便在结果页面中输出,所以使用了这个标注。
(4)@Action指出这个方法是个一个事件响应,那有人问了,那这个LiteBean中有可能有许多方法被标注为@Action,那我又怎么知道哪个方法响应哪个控件啊? 对,问得好,这里体现了约定大于配置这么一条规则,例如,本例中,这个btnSubmit方法被标注为@Action,如果,这个这个标注没有指定id,那么框架会自动寻找视图中相同的id元素,进行事件的响应,同时,如果没有指定该标注的event属性,也会采用约定的事件进行相应。例如,本例的控件是个button,他的默认事件是click事件。比较完整的一个写法类似如下:
 
@Action(id="bntSubmit",event=”ondbclick”)
public String myFuncation() {
        return "view:result";
}
 
(5)这里可以决定Button的显示的内容。
(6)按钮按下后,我们希望页面导航到下一个result页面,因此通过返回view:的方式,告诉AOM2引擎,这个方法过后,需要显示视图result。
 

10. ResultBean.java

本例并不是想用最简单的方式来实现一个HelloWorld,所以可能熟悉OperaMasks2的人,认为一个HelloBean足以,只要在OperaMasks.xml增加一个配置,让HelloBean同样找到result.xhtml,就可以控制那个页面的显示了,那种情况确实比较方便,当你熟悉了OperaMasks2之后,自然会去那么做。
不过这里,为了让思路简单些,便于入门的理解,这个例子还是针对每个视图都产生一个后台的控制逻辑。 我们来看看ResultBean 的代码编写:
 
package org.operamasks.example.hello;

import org.operamasks.faces.annotation.BeforePhase;
import org.operamasks.faces.annotation.Bind;
import org.operamasks.faces.annotation.ManagedBean;
import org.operamasks.faces.annotation.ManagedBeanScope;
import org.operamasks.faces.annotation.ManagedProperty;

@ManagedBean(scope = ManagedBeanScope.REQUEST)
public class ResultBean {
     @Bind
     @ManagedProperty( "#{HelloBean.txt}")
     private String message;
}
 
(1)这里设置bean的作用域范围为request,表明当前请求范围内有效,因为这个页面时仅在被访问时,需要显示内容,不想HelloBean需要把保存起来(Session范围),以供其他LiteBean调用其值,所以,ResultBean的范围设置成REQUEST即可。
(2)这个LiteBean需要控制页面message元素的显示,利用@Bind进行绑定。
(3)使用这个@ManagedProperty标注的目的是:1,我不需要再增加这个变量的set/get方法。2,并且该标注中的EL表达式,直接作为该属性的初始化值。这样,我们就达到了把HelloBean中的txt的值,即用户输入的值传递到了第二个LiteBean中,并通过Bind的作用,控制了视图中id为txt元素的值的显示。

11. 打包运行

OK,到这里,代码我们也写完了,把应用打包成war文件,放到tomcat的webapps目录中就可以。启动tomcat,启动浏览器,在地址栏中敲入[url]http://localhost:8080/aom-example-hello/hello.jsf[/url]就可以看例子的运行效果了。
 
 
在输入框中输入文本,点击按钮,会触发HelloBean的事件响应(HelloBean中的btnSubmit方法),该方法通过返回view:result将视图导航到下一个结果显示页面。
那么这个结果页面显示时,其值是由ResultBean控制的,而该LiteBean在初始化的时候,通过访问HelloBean的txt属性获得了用户的输入,并把该值赋给了message变量,页面上的message元素取得该值,就显示了用户的在上一个页面的输入。
 

12. 只用HelloBean

有人可能说,这么简单的例子搞两个bean,是不是太麻烦了,如果你实在不愿意再多写一个ResultBean,那么你也可以这么做:
  • 输出页面(result.xhtml)的txt的id也写成txt
     
          
    <b>Your input is :</b><h:outputLabel id= "txt"/>
  • 修改operamasks.xml文件,增加一条,让你的HelloBean能够找到result.xhtml
     
          
    <view-mapping>
    <url-pattern>/result.xhtml</url-pattern>
    <model-bean>HelloBean</model-bean>
    </view-mapping>
    OK,这样也就可以不要resultBean来运行了,这种方式下,hello.xhtml和result.xhtml两个视图是由同一个控制类HelloBean来进行控制的。
 

13. 有趣的一点

另外顺带提一下,作为程序员的你,可能对页面的布局十分不感冒,当然,本例的页面十分简单,不存在这样的情况,当页面一复杂,页面的布局和设计就不是我们的强项了,而美工则是这方面的专家,传统的开发模式下,美工对于诸如struts这样的页面是不理解的,尤其加入了大量的表达式和代码片段之后,不仅如此,即使是程序员之间,也存在这样的问题,记得我刚开始参加革命工作的时候,一次去客户那里帮客户调整页面,当我打开由上一个程序员编写的页面时,我面对的是一片片的雷区,大量的控制逻辑混杂在页面中,让我不知道该怎么修改,一个不小心,就导致页面不工作了。
OK,让我们用Dreamweaver来开发这个页面,看情况如何?
  • 首先使用一个网页编辑器,例如Dreamweaver来进行页面的设计:
  • 设计时,记得组件都要设置一个id属性,然后,使用一个jsfc属性来标记这个组件实际运行时所代表的AOM组件,例如:
     
          
    <? xml version ="1.0" encoding ="UTF-8" ?>
    < f:view xmlns:f ="http://java.sun.com/jsf/core"
             xmlns ="http://www.w3.org/1999/xhtml"
             xmlns:h ="http://java.sun.com/jsf/html"
             xmlns:ui ="http://java.sun.com/jsf/facelets"
             xmlns:w ="http://www.apusic.com/jsf/widget"
             xmlns:ajax ="http://www.apusic.com/jsf/ajax"
             xmlns:layout ="http://www.apusic.com/jsf/layout"
             renderKitId ="AJAX" >
         < w:head >
             < w:stylesheet src ="/resources/css/example.css" />
         </ w:head >
         < w:page title ="HelloWorld Example" >
         < p />
         < h1 >HelloWorld Example Using Dreamwave </ h1 >
         < hr noshade ="noshade" />
         < p />
             < w:form >
                 < label >
                     < input type ="text" id ="txt" jsfc ="w:textField" name ="textfield" />
                 </ label >
                 < label >
                   < input type ="submit" name ="Submit" id ="btnSubmit" jsfc ="w:button" />
                 </ label >
             </ w:form >
         </ w:page >
    </ f:view >
    (1)form中的内容是由美工在其他网页编辑环境中编辑的,可以看到这些元素是标准的html元素。
  • 写好这个页面后,直接放入应用中,在浏览器中敲入[url]http://localhost:8080/aom-example-hello/hello_dreamwave.jsf[/url]看看实际运行的效果:
竟然一样可以运行。是不是有点意思,这样以后你和美工MM的工作将会变得更加愉快了。对了,因为你的页面改成了hello_dreamave.xhtml,默认约定是HelloBean能够找到hello.xhtml,为了让后台的控制逻辑(HelloBean)能够找到你这个页面进行控制,别忘了在operamasks.xml中增加一个配置:
 
<view-mapping>    
<url-pattern>/hello_dreamwave.xhtml</url-pattern>    
<model-bean>HelloBean</model-bean></view-mapping>

14. 示例应用的运行包及代码

Tomcat版本: aom-example-hello(for-tomcat).zip,里面包含了源代码。
其他参考文件:
1.Apusic版本: aom-example-hello(for-apusic).zip(需要Apusic5.1tp5版本),如果你下载的是Apusic5.1tp4,则把最新的AOM解压后的包,放入Apusic安装目录下的lib目录中。
2.空的war包: aom-example-blank.war
3.Tomcat下运行应用时需要的: javaee.jar
4.OperaMasks官方网站: [url]www.operamasks.org[/url]