与许多人一样,我使用过各种不同的Adobe产品,并使用过Flash和其他技术完成了各种类型的任务。我也听说过Flex可以在各种BEA产品中使用,包括WebLogic Portal,但是这一方面的示例并不多见。如果只言其实现结果而不言其原理,我想用户一定会难于理解。因此我决定着手深入研究这方面的内容。在本文中,我将向大家介绍如何使用Flex构建一个应用程序,该应用程序能够通过WebLogic Portal Virtual Content Repository (VCR)显示内容。
使用Flex构建器
本文并不会详细介绍 Flex 构建器,但是使用过Workshop for WebLogic Platform之类产品的用户应该知道它是一个基于Eclipse的工具。我选择独立安装它,而不是作为一个插件。实际上就是将其从Workshop中分离出来,这是我一贯的作法。可能有些人会觉得奇怪,其实我比较偏好在两个不同的视图中主观地进行上下文切换,这样可以避免我的Workshop实例更加混乱。
Flex构建器中的可视编辑器非常不错,比许多其他的Eclipse编辑器具有更佳的直接可视化效果。考虑到Adobe在这一领域中开发了众多以媒体为中心的工具,这一功能也就不足为奇了。能够如此方便地编辑XML代码,这也着实让我吃了一惊。我并不是觉得这样不好,事实上我更习惯于使用控件,但是我也希望可视化的内容能够更多一点。确实有非常优秀的 ActionScript 和 MXML编辑器,它们拥有比Workshop目前提供的更佳的代码完成和验证功能。此类特性为开发人员提供了巨大的方便,从而避免了不断查阅文档的麻烦。
惟一让我感到不足的是打包和部署应用程序的问题。应用程序不能在Flex环境之外运行。我还无法确定如何解决该问题。我知道可以查阅相关文档,我也知道这不难解决,但是软件提供商应该简化这些问题或者至少让问题更加明确。
构建内容查看器
如果您阅读过我前几期的文章,那么您应该了解了如何使用 wlp.bea.com 上可用的原型REST命令。其中许多命令都专注于BEA WebLogic Portal的内容管理特性,旨在使聚合和其他Web 2.0应用程序联系更加紧密。Flex提供了一种丰富的(或许是最丰富的)用户界面技术,超越了DHTML、CSS和AJAX等提供的功能。也就是说,我相当希望Flex是基于JavaScript和HTML的,这样我就不必重新学习另一种脚本和标记语言了。
此处是我所构建的内容查看器的屏幕截图:

DataGrid中的这一内容来自wlp.bea.com上的content.nodelist REST命令,其中的图像和文章来自content.node命令。它们的使用方法与JavaScript示例相同,需要使用Flex UI组件。这个示例看上去与使用AJAX工具集构建的效果没多大区别,因此我们有必要开发一个内容更加丰富的UI。此处提供了一个 WLPCMViewer.mxml 文件供大家下载,或者也可以直接复制以下的代码:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
verticalAlign="top"
horizontalAlign="left"
backgroundImage="images/background2.png"
viewSourceURL="srcview/index.html" width="100%" height="100%" paddingBottom="0" paddingLeft="0" paddingRight="0" paddingTop="0" verticalGap="2">
<mx:Label height="0" id="baseUrl" visible="false" text="http://wlp.bea.com"/>
<mx:Label height="0" id="baseRestUrl" visible="false" text="{baseUrl.text}/rest-web-lib/api/"/>
<mx:HBox width="100%" verticalAlign="bottom" height="50" paddingTop="0" verticalGap="0">
<mx:Image source="images/bealogo.png"/>
<mx:Label height="36" text="WebLogic Portal Content Viewer" width="100%" htmlText="WebLogic Portal Content Viewer" fontSize="20" fontStyle="normal" fontWeight="bold" textAlign="left"/>
</mx:HBox>
<mx:Script source="WLPCMViewer.as"/>
<mx:VBox width="100%" height="100%"
borderThickness="2" borderStyle="solid" borderColor="#A0A0F0"
backgroundColor="#C0C0C0" backgroundAlpha="0.5"
initialize="init()" paddingTop="5" paddingLeft="5" paddingRight="5" paddingBottom="5">
<mx:HBox width="100%" horizontalGap="2">
<mx:TextInput width="303" id="nodePathInput" text="/BEA Repository"/>
<mx:Button icon="@Embed('images/rt_arrow.png')" click="{wlp_content_node_list.send()}" width="23" toolTip="Display folders for path"/>
<mx:Button icon="@Embed('images/updir.png')" click="upOneLevel();" paddingLeft="0" horizontalGap="0" width="22" toolTip="Go to parent folder"/>
</mx:HBox>
<mx:DataGrid id="nodes" rowCount="6"
width="100%"
backgroundAlpha="0.5"
dataProvider="{wlp_content_node_list.lastResult.rsp.nodes}"
itemClick="itemClickEvent(event);">
<mx:columns>
<mx:Array>
<mx:DataGridColumn dataField="name" headerText="Name"/>
<mx:DataGridColumn dataField="path" headerText="Path"/>
<mx:DataGridColumn dataField="type" headerText="Type"/>
<mx:DataGridColumn dataField="workflowStatus" headerText="Status"/>
</mx:Array>
</mx:columns>
</mx:DataGrid>
<mx:VBox width="100%" height="500" horizontalAlign="center" verticalAlign="top">
<mx:Canvas width="100%" height="100%">
<mx:Image id="imageContent" visible="true" source=""/>
<mx:Image id="imageContent2" visible="true" source=""/>
<mx:TextArea id="htmlContent" visible="false" width="100%" height="100%"
horizontalScrollPolicy="auto" verticalScrollPolicy="auto">
<mx:htmlText>
</mx:htmlText>
</mx:TextArea>
</mx:Canvas>
</mx:VBox>
</mx:VBox>
<mx:HTTPService id="wlp_content_node_list"
url="{baseRestUrl.text}content.nodelist"
method="GET" showBusyCursor="true">
<mx:request xmlns="">
<nodePath>{nodePathInput.text}</nodePath>
</mx:request>
</mx:HTTPService>
<mx:HTTPService id="wlp_content_node"
url="{baseRestUrl.text}content.node"
method="GET" showBusyCursor="true">
<mx:request xmlns="">
<nodePath></nodePath>
</mx:request>
</mx:HTTPService>
</mx:Application>
在DataGrid中进行数据绑定不需要进行编码,可以使用以下代码定义服务:
<mx:HTTPService id="wlp_content_node_list"
url="{baseRestUrl.text}content.nodelist"
method="GET" showBusyCursor="true">
<mx:request xmlns="">
<nodePath>{nodePathInput.text}</nodePath>
</mx:request>
</mx:HTTPService>
baseRestUrl映射到http://wlp.bea.com/rest-web-lib/api/,这与之前的JavaScript示例是一样的。
我们在代码中通过nodePathInput(文本输入字段)设置了nodePath请求参数。这是调用数据服务所需的惟一操作,将其映射到DataGrid也相当简单:
<mx:DataGrid id="nodes" rowCount="6"
width="100%"
backgroundAlpha="0.5"
dataProvider="{wlp_content_node_list.lastResult.rsp.nodes}"
itemClick="itemClickEvent(event);">
<mx:columns>
<mx:Array>
<mx:DataGridColumn dataField="name" headerText="Name"/>
<mx:DataGridColumn dataField="path" headerText="Path"/>
<mx:DataGridColumn dataField="type" headerText="Type"/>
<mx:DataGridColumn dataField="workflowStatus" headerText="Status"/>
</mx:Array>
</mx:columns>
</mx:DataGrid>
dataProvider属性指向上面代码中定义的wlp_content_node_list的lastResult。这是从REST命令返回的XML值,并且我们可以使用rsp.nodes映射节点数组。DataGrid有足够的灵活性,可以将这些值显示出来,并使用其余的标记设置列名称。接下来我们再看看ActionScript代码,不过需要注意它只使用了7行MXML标记显示wlp.bea.com数据:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:DataGrid dataProvider="{wlp_content_node_list.lastResult.rsp.nodes}" initialize="{wlp_content_node_list.send()}"/>
<mx:HTTPService id="wlp_content_node_list" method="GET" url="http://wlp.bea.com/rest-web-lib/api/content.nodelist">
<mx:request xmlns=""><nodePath>/BEA Repository/Smithsonian</nodePath></mx:request>
</mx:HTTPService>
</mx:Application>
您可以复制上面的代码或者下载 Simple.mxml 在Flex构建器中试验一下。运行之后,该代码将使用wlp.bea.com中的内容节点填充DataGrid,而不需要额外的代码。这相当了不起,不过我们才刚开始而已。
使用ActionScript完成更多任务
本站点所面像的是开发人员,因此您应该了解编写代码的重要性。虽然MXML易于在可视化的或文本编辑器中使用,但是单独使用它所能完成的任务是有限的。这算不上是什么问题;实际上Adobe并没有宣称所谓的业务用户使用可视化工具可以完成任何事情。不知有多少产品都只注重前端的华丽而忽略了后台的实质。
ActionScript是强类型的语言,这点类似于JavaScript。我相信它们两者之间存在其他方面的差异,但这并不表示我将对这两种语言进行一番学术讨论。我确实发现它相当易于使用,并不需要阅读大量的文档或者购买许多书籍。在线Adobe文档就非常不错,其中含有大量的博客文章和讨论主题。通过Google和其他搜索引擎也可以找到一些其他的参考资料。
本文中查看器所引用代码的可以点击 WLPCMViewer.as 下载,或者直接复制以下代码:
import mx.rpc.events.ResultEvent;
import mx.events.ListEvent;
import mx.collections.ArrayCollection;
import mx.core.Application;
import mx.core.UIComponent;
import mx.effects.Parallel;
import mx.effects.Fade;
import mx.controls.Image;
import flash.events.Event;
private var parentNodePath:String = "";
private var imageIndex:int = 0;
private function debug(text:String):void {
}
private function init():void {
debug("init");
wlp_content_node_list.addEventListener(ResultEvent.RESULT, nodeListResultEvent);
wlp_content_node.addEventListener(ResultEvent.RESULT, nodeResultEvent);
wlp_content_node_list.send();
}
private function nodeListResultEvent(event:ResultEvent):void {
var path:String = wlp_content_node_list.lastResult.rsp.nodePath;
if (path == null || path == "null") {
path = "/BEA Repository";
parentNodePath = path;
} else {
parentNodePath = path.substring(0, path.lastIndexOf("/"));
}
nodePathInput.text = path;
debug(path + " -> " + parentNodePath);
}
private function itemClickEvent(event:ListEvent):void {
var type:String = event.currentTarget.selectedItem.type;
var path:String = event.currentTarget.selectedItem.path;
if (type == "folder") {
wlp_content_node_list.request.nodePath = path;
wlp_content_node_list.send();
} else {
wlp_content_node.request.nodePath = path;
wlp_content_node.send();
}
}
private function upOneLevel():void {
wlp_content_node_list.request.nodePath = parentNodePath;
wlp_content_node_list.send();
}
private function nodeResultEvent(event:ResultEvent):void {
var name:String = null;
var contentType:String = null;
var property:Object = null;
var value:Object = null;
var url:String = null;
var nodeName:String = wlp_content_node.lastResult.rsp.name;
var type:String = wlp_content_node.lastResult.rsp.type;
var path:String = wlp_content_node.lastResult.rsp.path;
var canDisplay:Boolean = false;
for (var i:int = 0; i < wlp_content_node.lastResult.rsp.properties.length; i++) {
property = wlp_content_node.lastResult.rsp.properties[i];
name = property.name;
if (name == "file") {
contentType = property.values.contentType;
debug("contentType is " + contentType);
if (contentType.indexOf("text") >= 0) {
htmlContent.htmlText = property.values.value;
htmlContent.setVisible(true);
imageContent.setVisible(false);
imageContent2.setVisible(false);
canDisplay = true;
} else if (contentType.indexOf("image") >= 0) {
url = "http://wlp.bea.com" + property.values.value;
showImage(url);
imageContent.setVisible(true);
imageContent2.setVisible(true);
htmlContent.setVisible(false);
canDisplay = true;
}
} else if (name == "url") {
if (property.values != null) {
url = property.values.value;
showImage(url);
imageContent.setVisible(true);
imageContent2.setVisible(true);
htmlContent.setVisible(false);
canDisplay = true;
}
}
}
if (!canDisplay) {
var msg:String = "No viewer for <b>" + nodeName + "</b>";
msg += " of type <i>" + type + "</i>."
htmlContent.htmlText = msg;
htmlContent.setVisible(true);
imageContent.setVisible(false);
imageContent2.setVisible(false);
}
}
private function showImage(url:String):void {
var image:Image;
var image2:Image;
if (imageIndex == 0) {
image = imageContent2;
image2 = imageContent;
} else {
image = imageContent;
image2 = imageContent2;
}
image2.addEventListener(Event.COMPLETE, _imageLoadedEvent);
image2.load(url);
}
private function _imageLoadedEvent(event:Event):void {
var image:Image;
var image2:Image;
if (imageIndex == 0) {
image = imageContent2;
image2 = imageContent;
} else {
image = imageContent;
image2 = imageContent2;
}
var parallel:Parallel = new Parallel();
var fade:Fade = new Fade();
fade.target = image;
fade.duration = 1000;
fade.alphaFrom = 1;
fade.alphaTo = 0;
parallel.addChild(fade);
var fade2:Fade = new Fade();
fade2.target = image2;
fade2.duration = 1000;
fade2.alphaFrom = 0;
fade2.alphaTo = 1;
parallel.addChild(fade2);
parallel.play();
imageIndex++;
if (imageIndex > 1)
imageIndex = 0;
}
这些代码大致上是一些事件处理程序,用于在应用程序运行时或者响应用户点击操作并显示内容时进行一些相应的设置。大部分代码处理图像和文件夹导航之间的淡出效果。我并未与Dojo和其他一些工具集进行比较(看哪个工具使用的代码比较多),不过我猜测如果结合使用更丰富的UI组件时Flex会比较出色。也就是说,不要认为使用Flex只需少量编码或者完全不编码就可以完成任何事情。不过幸好这并不难实现,使用各种工具和框架可以完成各种不同的工作。
要使用这个示例,您还需要一些其他的文件。为简单起见,我将所有文件都放入了一个zip文件,您可以从 此处 下载。这个文件包含上面所描述的那些MXML和ActionScript文件,同时还有一些背景和按钮的图像。要使用它们,可以在Flex构建器中创建一个新Flex项目并将该文件导入。操作完成之后,显示界面应该如下所示:

bin和html-template文件夹是由Flex构建器生成的,它们对于项目是隐藏的。要运行应用程序,请选中WLPCMViewer.mxml并单击Run按钮或者单击右键并选择Run Application。尝试导航文件夹层次并选择要显示的内容节点。这个示例应用程序将显示image、swivelgraph和article类型的节点,但是也可以修改设置以处理其他的类型。
我在前几篇文章中说过会给大家带来更多精彩的内容。我将在以后的文章中和大家分享Dojo小配件并演示如何在Microsoft Popfly中使用原型REST命令。如果您还对其他的Web 2.0技术感兴趣,可以给我留言,我将尽量满足大家的需要。
原文出处:http://dev2dev.bea.com/blog/skip/archive/2007/07/restpowered_fle.html