引言
如今在企业级应用中,Ajax、Widget、RSS/Atom 等 Web
2.0 技术正在得到越来越广泛的使用,这些技术不但产生了良好的用户体验,同时也来越来越多地影响着许多前端系统的编程模式和系统架构。许多传统的
Java EE 产品和框架也在越来越多地引入这些 Web 2.0 技术,如 Struts2 和 JSF
都有了越来越完善的 Ajax 扩展,Portal 产品中也基于 Dojo 等 javascript 框架引入部分刷新等机制,大幅提升了性能和用户体验。可以看出,Web
2.0 不仅是互联网应用的概念,它为企业级应用乃至整个软件行业都产生着深远影响。
基于 SOA 的企业应用,要考虑和 Web 2.0 的结合,首先需要解决的是怎样将各种各样的服务与那些
Web 2.0 技术整合在一起,在很多时候服务端和客户端的整合是具有一定难度的。SCA 作为一种跟具体语言、平台无关的
SOA 编程模型,必然需要考虑那些 SOA 传统技术与 Web 2.0 技术的整合。Apache Tuscany
作为开源界最成熟的 SCA 框架之一,在这方面提供了很多支持。本文正是从这个角度出发,结合实例介绍 Tuscany
在 Web 2.0 方面提供的诸多功能,同时对 SCA 和一些典型的 Web 2.0 技术作一定的介绍。
Tuscany 简介
SCA 的基本概念以及 SCA 规范的具体内容并不在本文的范畴之内,有兴趣的读者可以通过一些相关文档了解相关内容,这也是阅读本文的基础。下面本文首先对
Tuscany 框架做一定的介绍。
Tuscany 是 Apache 的开源项目,它是 IBM、Oracle、SAP
等厂商联合成立的 SOA 标准化组织 -OSOA 支持下开发出的 SCA 框架,它既是开源界 SCA 的试金石,也是当前开源界最成熟的
SCA 框架之一。
Tuscany 基本架构
图 1 为 Tuscany 的基本架构图,从图中可以看出,作为一个轻量级
SCA 框架,Tuscany 提供了非常松散耦合的框架结构。主要有以下几个特点:
- Tuscany 是平台无关的可嵌入框架,可以在各种 Hosting Platform 上运行,如
Tomcat,JBoss,WAS 等 Web 容器上运行,也可以在 J2SE 环境下运行。
- Tuscany 的核心模块提供了 SCA 规范的 API 实现,Tuscany 系统的 SPI
接口,一些系统基本实现(如事件,工厂类,存储等),以及一整套扩展机制,这些扩展机制为 Tuscany
整合各个平台的服务提供了基础。
- Tuscany 的扩展是完全松散耦合的,框架本身提供了大量的扩展实现,用户也可以在自己的系统中扩展
Tuscany 的实现,只需要遵循 Tuscany 的扩展规范以及 API 接口。
图 1. Tuscany 基本架构图
Tuscany 主要有以下几个方面的扩展:
- Implementation:SCA 组件(Component)的实现方式,一个 SCA 组件可以由各种语言或技术平台实现,如:POJO,EJB,Spring
Bean,bpel 流程,各种脚本语言等等。
- Binding:是 SCA 的绑定(Binding)规范的实现,SCA 服务(Service)和引用(Reference)的绑定方式,即一个
SCA 服务可以暴露为 Web Service,Java RMI 服务,http 资源,jms 消息等等,一个
SCA 引用也可以通过 Web Service,RMI 调用,http 调用,jms 调用等方式调用远端服务。
- Databinding:数据绑定方式,这是 Tuscany 提出的概念,一般用与在 Binding
中定义参数的传输格式,比如 Web Service 的 Binding 一般用 XML 格式,SCA
的 Binding 一般用 SDO 格式,Jsonrpc 的 Binding 一般用 Json 格式等等。
- Interface:是 SCA 的接口(Interface)规范的实现,SCA 服务(Service)和引用(Reference)的接口暴露方式,一般有
Java,WSDL 等类型。
Tuscany 的 Web 2.0 扩展
Tuscany 在 Web 2.0 方面主要提供了以下几类扩展:
- Implementation 扩展:script implementation 提供了各种脚本语言的实现,如
Javascript,python,ruby 等,widget implementation 提供了将一个
SCA Component 封装成 widget 的能力。resource implementation
提供了一种简单的 http 资源的实现。
- Binding 扩展:atom binding 提供了 atom 方式的绑定实现,dwr binding
提供了利用 dwr 框架进行 ajax 调用的能力,http binding 提供了直接进行 http
访问的能力,jsonrpc binding 提供了在 Javascript 中使用 jsonrpc
进行 ajax 调用的能力。
- Databinding 扩展:json 格式的 databinding 提供了将 json 格式的数据与其他格式(如
xml,Java Bean,SDO 等)之间互相转换的能力。
以上只是简要地列出了 Tuscany 在 Web 2.0 方面提供的一些扩展,后面本文将通过一些实例讲述怎样使用其中的某些扩展功能,并且对其中具体实现细节进行一定的介绍
环境建立
下面介绍运行本中示例所需要的环境。
要运行基于 Tuscany 的应用,除了需要 Tuscany 的运行库支持以外,还需要很多
Tuscany 的依赖库,由于 Tuscany 是一个 SCA 集成框架,它使用了大量的第三方框架来进行各方面平台的集成,因此它的依赖库的管理比较复杂,因此本文的示例基于
Maven 构建,可以较为方便地管理依赖库,并且 Tuscany 本身也是基于 Maven 建立的,下面首先对
Maven 作简要的介绍。
Maven 简介
Maven 是一个基于模型描述的软件项目管理工具,通过一种 XML 格式的文件(POM)文件来描述项目对象模型。它兼有
Ant 的一部分功能,可以对 Java 项目进行编译,测试,打包,安装以及部署。它基于插件机制实现,以插件的方式实现软件项目管理的生命周期中各个时期所需要执行的任务(goal),它不仅便于单个项目的构建,同时可以建立一个庞大的软件资源库(repository),资源库可以在本地建立,也可以连接到远程的、官方的,通过资源库使项目依赖更加方便。很多开源项目都具有自己的
Maven repository。Tuscany 也是基于 Maven 建立的,它的各个模块和各个扩展都依赖着不同的开源框架。
M2Eclipse 简介
本文的示例所用的 IDE 环境为 Eclipse,因此介绍一下 Maven
在 Eclipse 平台上的插件:M2Eclipse。
基于命令行运行 Maven 比较直观但是不利于在开发环境中部署和调试。M2Eclipse
提供了一整套 Maven 和 Eclipse 结合的插件,极大的方便了在 Eclipse 上开发 Maven
项目,M2Eclipse 包括以下功能:
- 最基本的 Maven 运行环境,Maven Builder 以及 Maven Launch 等等。
- 一系列简化 Maven 配置文件编写的可视化界面,如 POM 编辑器,Maven repository
搜索框等。
- 新建 Maven 工程和导入已有 Maven 应用的向导。会建立基本的 Maven 工程目录结构。
- Maven repository 的本地索引库,便于在 POM 文件中搜索和添加依赖。
- 将 Maven 与 WTP 结合,使得用 Maven 建立的 Web app 工程能直接部署到通过
WTP 配置的 Server 上,这极大地方便了 web 应用的部署和调试。
场景简述
下面介绍一个简单的业务场景,做为本文示例的出发点。
大家买股票的时候都比较关心一个股票的实际价值与成长性,因此在证券行业,市盈率是一个比较重要的指标,它可以从一定程度上衡量股票的具体价值,市盈率分静态市盈率和动态市盈率,静态市盈率的计算比较简单,其计算公式为:
市盈率=股票每股市价/每股税后利润
即:
市盈率 = 股价 / 每股收益
本文的示例就是对静态市盈率进行计算,并且用基于 Web 2.0 的界面显示不同的公司市盈率的比较。一般情况下当前股价的获取会来自固定的服务提供商,在本文的示例中,当前股价由一个
web service 提供,而每股收益由一个 Java 的 RMI 服务提供,以展示 Tuscany
整合不同服务的能力。
示例应用服务端开发
建立示例应用
首先通过 Eclipse 建立一个 Maven 工程,如图 2 所示,在此对话框中,请勾选”Create
a simple project (skip archetype selection)”,这个选项会直接通过属性配置建立
Maven 工程,而不会使用 archetype 机制,本文的示例并不需要使用 archetype 机制。在
Advanced 选项里面,为 Name template 填入值,它将会作为新建工程的工程名。
图 2. 新建 Maven 工程
下面配置刚建立的 Maven 工程的基本 POM 属性,如图 3 所示,主要有以下几个属性:
- Group Id:该 Maven 产品的组织名称,类似于 Java 的包名
- Artifact Id:该产品的产品名
- version:版本号
- Packaging:该产品的打包方式。这个属性比较重要,由于我们需要建立一个 web 应用,这里的打包方式应选择
war。该属性还有其他选项,如 jar,ear 等。
图 3. Maven 工程的基本属性
等待示例工程创建完毕,Maven 会创建一个初始目录结构,如图 4 所示。这是一个典型的
Maven web 应用的目录结构,其中,src/main 存放主程序源文件,src/test 存放测试文件。在
src/main 中有两个 classpath 目录:Java 和 resources,其中 Java
存放 Java 类源文件,resources 存放一些需要处于 classpath 中的资源文件。src/main/webapp
为 web 应用的根目录。在工程目录上右击,选择 Maven->Update Project Configuration。M2Eclipse
插件会为 WTP 创建必要的配置,使得该 web 应用能够通过 WTP 部署到 web server 上。
图 4. 初始目录结构
添加工程依赖
下面我们需要为刚建立的工程添加依赖,本示例需要掩饰 Tuscany 的一些
Web 2.0 功能,因此需要添加 Tuscany 的基本库以及一些 Web 2.0 扩展库。双击工程根目录中的
pom.xml,使用 POM 文件编辑器打开该文件,切换至 Dependencies 页,添加必要的依赖。如图
5 所示
图 5. Maven 工程依赖
需要添加的工程依赖如表 1 所示
表 1. 示例应用工程依赖列表
groupId |
artifactId |
version |
org.apache.tuscany.sca |
tuscany-implementation-Java-runtime
|
1.4 |
org.apache.tuscany.sca |
tuscany-binding-ws-axis2 |
1.4 |
org.apache.tuscany.sca |
tuscany-binding-rmi-runtime |
1.4 |
org.apache.tuscany.sca |
tuscany-host-webapp |
1.4 |
org.apache.tuscany.sca |
tuscany-binding-jsonrpc-runtime |
1.4 |
SCA 组件开发
如前文所述,本示例需要开发一个用于计算股票市盈率的组件服务,该服务需要导入两个外部服务接口,一个用于获取当前股价,另一个用于获取股票的每股收益,当然在本示例中这两个外部服务也是用
Tuscany 建立的应用,返回一定的示例数据,此处不详述,请参见本文附件里面的源码。
首先需要导入外部服务的接口,获取当前股价的服务为 web service,其
wsdl 如图 6 所示,Endpoint 为:http://localhost:8085/services/StockQuoteService
图 6. stockQuote.wsdl
为了在 Java 实现里能调用该 web service 提供的服务,需要生成该
wsdl 对应的 Java 接口,该 Java 接口可以由一般的 wsdl2Java 的程序来实现,Tuscany
也提供了一个 wsdl2Java 的插件,该插件除了生成 Java 接口外,还在接口上添加了一些 Tuscany
的 annotation。本文示例中的 wsdl 比较简单,它生成的接口 org.kth.demo.ws.StockQuote
如清单 1 所示。其中 @Remotable 是一个标准的 SCA annotation,它用于表示当前接口可以进行远端调用。
清单 1. StockQuote 接口
import org.osoa.sca.annotations.Remotable;
@Remotable
public interface StockQuote {
public float getQuote(String company, String date)
throws Java.rmi.RemoteException;
}
<a name="_代码清单与预格式化文本"/> |
获取每股收益的服务有一个 Java rmi 提供,其接口 org.kth.demo.rmi.EarningPerShare
如清单 2 所示。
清单 2. EarningPerShare 接口
import org.osoa.sca.annotations.Remotable;
@Remotable
public interface EarningPerShare {
public float getEarningPerShare(String company, String date)
throws Java.rmi.RemoteException;
} |
下面定义需要实现的 SCA 组件的接口 org.kth.demo.StockPE,该接口接受
2 个参数:公司名称和日期,返回某个上市公司某一天的静态市盈率。该接口的代码如清单 3 所示。其中 @Service
也是一个标准的 SCA annotation,用于表示基于该接口的 SCA 组件可以暴露为服务。
清单 3. StockPE 接口
import org.osoa.sca.annotations.Remotable;
import org.osoa.sca.annotations.Service;
@Remotable
@Service
public interface StockPE {
public float getPERatio(String company, String date)
throws Java.rmi.RemoteException;
} |
下面为 StockPE 组件开发具体的 Java 实现,新建 Java
类 org.kth.demo.impl.StockPEImpl,写入如清单 4 所示的代码。在该段代码中,@Service(StockPE.class)
声明了该 Java 实现是作为 SCA Interface StockPE 的实现。可以看到,对于 stockQuote
和 earningPerShare 都有 get 和 set 函数,这里是将这两个 Reference
暴露出来,让 Tuscany 框架在运行时进行依赖注入。在运行时,Tuscany 会根据具体的 Reference
类型创建特定的 Java 实现,比如 web service 或者 RMI 的 Stub,并且将这些实现注入该
SCA 组件的实现。getPERatio 为具体的实现方法,它首先获取外部服务的 reference,然后调用外部服务获取当前股价和股票的每股收益,然后计算出市盈率并返回。
清单 4. StockPEImpl 实现
import org.kth.demo.StockPE;
import org.kth.demo.rmi.EarningPerShare;
import org.kth.demo.ws.StockQuote;
import org.osoa.sca.annotations.Service;
@Service(StockPE.class)
public class StockPEImpl implements StockPE {
private StockQuote stockQuote;
private EarningPerShare earningPerShare;
public StockQuote getStockQuote() {
return stockQuote;
}
public void setStockQuote(StockQuote stockQuote) {
this.stockQuote = stockQuote;
}
public EarningPerShare getEarningPerShare() {
return earningPerShare;
}
public void setEarningPerShare(EarningPerShare earningPerShare) {
this.earningPerShare = earningPerShare;
}
/* (non-Javadoc)
* @see org.kth.demo.QuotePE#getPERatio(Java.lang.String, Java.lang.String)
*/
public float getPERatio(String company, String date) throws RemoteException {
float quote = stockQuote.getQuote(company, date);
float earning = earningPerShare.getEarningPerShare(company, date);
if (earning != 0)
return quote / earning;
else
return 0;
}} |
SCA 组件配置
在完成 SCA 组件的 Java 实现之后,我们需要配置具体的 SCA
环境,在 Tuscany 应用中,SCA 的配置主要放在 .composite 文件中,一个 .composite
文件实质上是一个 SCA Composite 的 XML 配置,这些 .composite 文件一般位于
classpath 下的 META-INF/sca-deployables 路径中,Tuscany 的
runtime 在初始化的时候会在 classpath 中搜索所有 .composite 文件,并且将它们定义的
SCA Composite 初始化。本文的示例需要定义一个 SCA Composite:InvokeDemoComposite,我们在
src/main/resources/META-INFO/sca-deployables 下建立 XML
文件 invokeDemo.composite,清单 5 先列出此配置文件的内容,后面会对其中细节一一介绍。
清单 5. composite 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
targetNamespace="http://tuscany.demo.kth.org"
xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.0"
xmlns:dbsdo="http://tuscany.apache.org/xmlns/sca/databinding/sdo/1.0"
name="InvokeDemoComposite">
<component name="StockPEComponent">
<implementation.Java class="org.kth.demo.impl.StockPEImpl"/>
<reference name="stockQuote">
<interface.wsdl
interface="http://ws.demo.kth.org#wsdl.interface(StockQuote)"/>
<binding.ws
uri="http://localhost:8085/services/StockQuoteService"/>
</reference>
<reference name="earningPerShare">
<tuscany:binding.rmi host="localhost" port="8099"
serviceName="EarningPerShareService" />
</reference>
</component>
<service name="StockPE" promote="StockPEComponent/StockPE">
<interface.Java interface="org.kth.demo.StockPE"/>
<tuscany:binding.jsonrpc />
</service>
</composite> |
首先看一下这个文件中需要定义的 namespace,
tagetNamespace:用于表示此 SCA Composite 的名称空间,在
SCA 部署的时候,contribution 文件中的 composite 部署配置应于这个名称空间一致。
xmlns:tuscany:Tuscany 的特有 Binding 扩展的名称空间,由于
Tuscany 是一个开放式框架,它的 binding 扩展有多种类型,其中有些是 SCA 规范中定义的扩展,这些扩展不需要名称空间,有些是
Tuscany 自己定义的扩展,这些扩展就需要使用 xmlns:tuscany 定义的名称空间,Web
2.0 扩展大多属于这种类型。用户也可以自己开发扩展,那使用的时候就需要引入用户自定义的名称空间。
xmlns:dbsdo:Tuscany 的特有 databinding
扩展的名称空间,一般来讲每个 binding 都有自己默认的 databinding,比如 web service
的 binding 就会默认使用 JAXB 的 databinding,打多数情况下不需要特定指出 databinding
的类型,但是不排除某些特殊情况下需要用户特别指出 databinding 的类型,此时就需要加上这个名称空间。
接下来看 SCA Component 的配置,component 元素就是配置一个
SCA Component 的声明,它有一个在同 composite 必须唯一的名称,每一个 component
都必须有一个 implementation 元素,这里我们采用 Java 实现 Component,因此需要配置
implementation.Java,这个配置会制定一个 Java 类的全名作为此 Component
的实现。
Component 中可以配置 Service 以及 Reference,Service
是定义该 Component 暴露出的一些服务,Reference 是定义该 Component 需要引用的其他外部服务。在
Reference 中,需要指定该引用的接口(interface)和绑定(binding),在本文示例中,我们引入了两个外部服务,因此需要定义两个
Reference,其中一个 Reference 用来引用通过 web service 暴露的查询股价的服务,在它的定义里需要制定
wsdl 方式的 interface,以及该 web service 的 endpoint 地址。另一个
Reference 用来引用通过 Java RMI 暴露的查询股票每股收益的服务,它需要指定 Java
RMI 的主机名,端口号,以及服务名。
最后看一下 SCA Component 暴露给 Web 2.0 应用的服务。通过一个外部的
service 定义,该 Component 可以指定一个在 composite 层暴露的服务。此服务的名称必须与用
@Service 指定的接口名一致,在该服务的定义里也必须指定 interface 和 binding,其中
binding 采用 jsonrpc 方式,便于在 web client 端使用 ajax 调用,注意此处必须加上
tuscany 的名称空间。
通过这个配置文件将之前开发的 Java 实现封装成了 SCA Component,并使其可以在
Tuscany 中运行。到目前为止创建的实现和配置文件应该组成如图 7 所示的目录结构。
图 7. 服务端组件目录结构
示例应用客户端开发
前文已经讲述了如何利用 Tuscany 创建出服务端的 SCA 组件,接下来本章讲述如何以
Web 2.0 的方式消费这些 SCA 组件。
Web 配置
要在 Web 应用中调用 SCA 组件,需要对 Web 应用进行一定的配置,主要是配置
SCA 的 contribution,SCA Contribution 是将 SCA 组件在 JAVA
EE 容器或者 Web 容器部署的部署信息。在 src/main/webapp/ META-INF/ 下建立文件
sca-contribution.xml,并写入如清单 6 的内容。该文件的内容比较简单,就是声明一个
SCA Composite,deployable 元素就是用做这样的声明,InvokeDemoComposite
为之前定义的 Composite 的名称,sample 为其名称空间,这里的定义必须与与 composite
配置文件中定义的一致。
清单 6. SCA Contribution 文件
<contribution xmlns="http://www.osoa.org/xmlns/sca/1.0"
xmlns:sample="http://tuscany.demo.kth.org">
<deployable composite="sample:InvokeDemoComposite"/>
</contribution> |
JsonRPC 示例
web 页面开发
下面我们创建利用 JsonRPC 方式调用 SCA 组件的示例。我们的目标是创建一个
web 页面,该页面展示一张列表,列出中国石油,中国石化和工商银行三家公司的市盈率。在 src/Java/webapp
中创建 html 页面 StockDemoRpc.html,并且写入如清单 7 的代码。
清单 7. StockDemoRpc.html 页面内容
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Tuscany RPC Stock Demo</TITLE>
<script type="text/Javascript" src="SCADomain/scaDomain.js"></script>
<script type="text/Javascript" src="jquery/jquery.js"></script>
<script language="JavaScript">
window.onload = function(){
var companies = [" 中国石油 " , " 中国石化 " , " 工商银行 "];
$.each(companies, function(){
var pe = StockPE.getPERatio(this , "2009-03-25").toFixed(2);
$(".header").append("<th>" + this + "</th>");
$(".content").append("<td>" + pe + "</td>");
})
}
</script>
</head>
<body>
<h2> 市盈率列表 </h2>
<table border="1" cellpadding="2" cellspacing="2">
<tr class="header" />
<tr class="content" />
</table>
</body>
</html> |
下面分析这个文件的内容,首先需要引入必要的 Javascript 库,其中
scaDomain.js 比较重要,它不需要被导入到 webapp 中,是 Tuscany 运行时由 Servlet
动态生成的,它是 Tuscany 为客户端创建的 Javascript 库合集。页面的主体是一个 <table>,它有两行,一行显示公司名称,另一行显示对应公司的市盈率值。在
window.onload 里面实现表格的生成工作,在这个方法里面,我们看到 StockPE.getPERatio
为获取市盈率的操作,其中 StockPE 是在 scaDomain 中生成的专门用于做 JsonRPC
的 Javascript 对象,它封装了 JsonRPC 所需要的 Ajax 调用操作,可以看作是服务端的
SCA 组件在 Javascript 客户端的 Stub。在获取到市盈率值后利用 HTML 操作生成整个表格
部署运行
下面需要将之前开发的服务端组件以及客户端代码打包部署到服务器上,图 8
显示了需要部署的服务器上的工程的目录结构,由于我们使用了 M2Eclipse 可以直接在 Eclipse
中建立一个 Server,这里使用 Tomcat 的 Server,在 Tomcat Server 上右击选择
Add or Remove Projects,将 kth-tuscany-demo-invoke 工程加入到此
server 中,然后再右击 Server,选择 Start。等待 Server 启动,如图 9 所示。
图 8. 部署目录结构
图 9. 安装部署
运行结果
JsonRPC 示例的运行结果如图 10 所示,该列表分别列出了三家公司的静态市盈率值。
图 10. JsonRPC 示例运行结果
Dojo 示例
上一个示例展示了在客户端页面中直接使用 Tuscany 生成的 JsonRPC
的 Javascript 对象来调用 SCA Component,在本例中丰富一下客户端的内容,使用 dojo
框架显示一个柱状图,来更直观地展现中国石油,中国石化和工商银行几家公司的市盈率,可以有一个直观的比较。
Web 页面开发
在 src/Java/webapp 中创建 html 页面 StockDemoDojo.html,并且写入如清单
8 的代码。
清单 8. StockDemoDojo.html 页面内容
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Tuscany Dojo Stock Demo</TITLE>
<script src="dojo/dojo/dojo.js" type="text/Javascript" djConfig="parseOnLoad: true
,usePlainJson:true"></script>
<script src="dojo/dojo/custom/dojo-core.js" type="text/Javascript"></script>
<script src="dojo/dojo/custom/graphics.js" type="text/Javascript"></script>
<script language="JavaScript">
dojo.require("dojo.rpc.JsonService");
var PEService = new dojo.rpc.JsonService("StockPE?smd");
var companies = [" 中国石油 " , " 中国石化 " , " 工商银行 "];
var labels = [];
var pes = [];
function renderChart(){
var chartNode = dojo.byId("chart");
var chart = new dojox.charting.Chart2D(chartNode);
chart.addAxis("x", {fixLower: "minor", fixUpper: "minor", natural: true,
labels:labels});
chart.addAxis("y", {vertical: true, fixLower: "major", fixUpper: "major",
includeZero: true});
chart.addPlot("default", {type: "ClusteredColumns", gap: 20});
chart.addSeries("PE", pes , {stroke: {color: "blue"}, fill: "lightblue"});
chart.render();
}
function init() {
dojo.forEach(companies, function(item , i){
labels.push({text : item , value : i + 1});
var pe = PEService.getPERatio(item , "2009-03-25").addCallback(function(res){
pes.push(res);
if(pes.length == 3)
renderChart();
});
})
}
dojo.addOnLoad(init);
</script>
</head>
<body>
<h2> 市盈率图表 </h2>
<div id="chart" style="width:360px;height:200px"/>
</body>
</html> |
下面分析这个文件的内容,首先导入必要的 js 库,主要是 Dojo 的库,除了
dojo.js 以外导入了两个通过自定义打包生成的 dojo 文件,本文的附件中包含了这些 dojo 文件,感兴趣的读者可以参考
dojo 的文档了解自定义打包的内容。这里不再需要引入 scaDomain.js,因为 Dojo 有内置的
JsonRPC 实现,并且 Tuscany 除了在 scaDomain.js 里面提供 JsonRPC
的接口以外,还通过 Servlet 提供另一种 JsonRPC 接口,即以 ?swd 结尾的 JsonRPC
描述,dojo 的 JsonRPC 实现可以解析这种描述并且生成具体的 Javascript 对象。这个
web 页的主体就是一个空的 div,dojo 会在这个 div 上生成我们所需要的图表,下面主要分析页面中的
Javascript 脚本。
首先通过 dojo.require 将 dojo 的 JsonRPC 实现类导入,然后创建
JsonRPC 的 Service:PEService,此 service 与之前的 JsonRPC 的
Stub 有所不同,它是采用异步调用的方式与服务端交互,而不是此前示例中的同步方式。PEService.getPERatio
方法会返回另一个 Javascript 对象,该对象可以添加 callback 来完成异步操作的响应。我们在
callback 中接收返回的数据,并且最后一个数据接收到之后生成图表。
renderChart 为生成图表的操作,主要是通过 dojox.charting.Chart2D
来生成一个二维柱状图,这里的实现细节不再细述。请有兴趣的读者参考 dojo 文档
运行结果
此例的安装配置界面与 JsonRPC 示例中类似,其运行结果如图 11
所示,通过柱状图把三家公司的市盈率显示出来,有一个直观的比较。
图 11. 市盈率图表
总结
本文首先介绍了基于 SCA 进行 Web 2.0 开发的意义,然后分析了
Tuscany 的基本架构和扩展,接着通过一些示例简单地展示了利用 Tuscany 开发 Web 2.0
应用的典型过程。
在本文的示例中,SCA 作为一个整合框架,整合了基于 web service
和 Java RMI 的服务,并且将其暴露成 Json 服务以便于客户端的 Javascript 进行调用。这样的例子很典型了展示了
Tuscany 将各种平台上的服务整合并且以 Web 2.0 的方式暴露给客户端的特性和功能。其实 Tuscany
的 Web 2.0 特性还不至于此,它还有其他很多基于 Web 2.0 技术的扩展,如 widget,RSS,Atom
等等,感兴趣的读者可以通过分析 Tuscany 框架的样例应用来进一步了解。 |