1 Sample Flex Viewe架构
1.1 架构介绍
Sample Flex Viewer框架的构建有助于开发和部署针对GeoWeb的应用程序,使得能够充分的发挥服务器端的空间服务的能力。服务器端的服务通过ArcGIS服务器和ArcGIS在线数据提供。如下图所示,地球空间信息服务可以由工作在软件即服务方式的伺服机提供商获得,比如ArcGIS在线数据库,ArcGIS服务器或者是像GeoRSS反馈,KML文件库以及JSON/REST数据等网络数据源。基于Sample Flex Viewer框架开发的应用程序所消耗的数据可以由服务器端提供,也可以是从移动设备运行动态生成的数据,如现场项目师的笔记本电脑或智能手机。
图1 地球空间信息服务
1.2 Sample Flex Viewer实例的生命周期
一个Sample Flex Viewer框架的实例从开始应用程序的设计到用户看到带微件的界面经历了一个简单的生命周期。期间主要的5个事件如下:1.Flash播放器从加载和运行容器文件开始一个Sample Flex Viewer框架的应用程序。2.这个Flex Viewer容器再从网络服务器加载XML格式的配置文件和皮肤文件并应用于整个应用程序。3.在配置文件的基础上,Flex Viewer容器会从ArcGIS在线数据和ArcGIS9.3服务器下载相关的地图信息,然后会从配置文件中加载并且在控制条上显示菜单和来自配置文件的标记信息。 4.Flex Viewer容器的微件管理器会从XML配置文件指定的URLs下载并加载相关的微件文件(一般是swf文件)。 5.用户利用微件来实现各种业务逻辑。
1.3 Sample Flex Viewer容器
Sample Flex Viewer容器使设计人员能够摆脱地图管理、地图导航、应用配置、组件间的通信、数据管理等繁重复杂的编程工作,专注于核心业务功能开发,尤其是那些利用ERSI公司的ArcGIS技术的网络应用开发人员。而且只需要在Flex Viewer应用程序的配置文件中增加配置项,就可以将功能以widget的形式快速部署到已有的Flex Viewer应用中。Sample Flex Viewer容器由一系列高内聚、低耦合组件组成(如下图所示)。容器会把关注的任务交给相应的组件去完成。这种设计方法不但简化了代码维护和定制,而且缩小了模块编写过程中产生的阻力。
图2 Sample Flex Viewer容器整体架构
1.4 理解Widget编程模型
经过编译的widget是一个独立的SWF(Flash)文件,可在Flex Viewer程序中共享、移动和配置。Widget封装了一系列独立并且针对性很强的业务逻辑,用户可以在其中执行任务。在一个面向服务的环境下,一个widget可以代表是一种服务或者是一套相关的服务,用户可以很明了的用它来执行一个业务功能。widget不仅为用户提供了可视化的界面,也能够连到服务器端的资源,像是来自ArcGIS服务器或是ArcGIS在线数据库的地图服务。一系列相互关联的widget加上清晰定义好的业务操作流程组成了业务解决方案。而且这样的方案可以应用于企业级的业务进程中。轻量级的Flex Viewer Widget编程模型使得开发人员可以轻易定制widget,避免了将widget整合到Flex Viewer应用程序中所需的底层代码开发。widget编程模型包含了两个ActionScript类(其中一个后为mxml类)以及两个ActionScript接口。后面一个章节将会讲述如何使用这些类以及接口的相关细节。
IBaseWidget Interface (IBaseWidget.as) 这个接口定义了WidgetManager管理微件的通信方法。而基础widget类BaseWidget则要来实现这个接口。
BaseWidget Class (BaseWidget.as) 这个是widget的基类,所有的微件都要继承这个类。通过扩展BaseWidget这个父类,WidgetManager会验证所有扩展了BaseWidget的MXML或AS类是否为可部署的微件。另外,扩展了BaseWidget的类能够被编译为一个独立的SWF文件。每个Flex Viewer框架下的微件必须继承BaseWidget这个父类。
IWidgetTemplate (IWidgetTemplate.as) 这个接口定义了widget模板能够被BaseWidget识别所需要的一般操作。是使用一个widget模板还是使用内置的widget模板通常是可选的。内置的WidgetTemplate类要实现IWidgetTemplate这个接口。
WidgetTemplate (WidgetTeamplate.mxml) 这是一个内置的widget模板,它是一个为widget提供基本的布局和行为的用户界面组件。这些布局和行为包括一个标准的窗口面板,带有自定义图标按钮的标题栏等组件。使用这类模板,使得widget开发者能够把更多的时间和精力放在核心的业务需求上面。内置的widget模板通常也能被widget开发者用来定制属于自己的widget模板,前提是必须实现IWidgetTemplate这个接口。
1.5 Widget命名习惯
Widget 类: 一般来讲一个widget类得有”Widget”这样一个后缀,比如”NameWidget.mxml” ;Widget 的配置文件: 一个好的习惯就是,将widget的配置文件取相同的文件名,只是扩展名采用xml,比如NameWidget.xml。
2 开发一个widget
尽管前面两个章节讲述了两种widget项目开发的途径,但其实它们实际的核心功能开发的原理是一样的。这一章我们会用第一种开发方式来做更深入的讲解。我们先假设widge的开发员很熟悉Flex的开发环境。
2.1 使用WidgetTemplate模板
在接着2.1节所创建的一个widget文件MyFirstWidget.mxml讲,它的代码如下:
<?xml version="1.0" encoding="utf-8"?> <BaseWidget xmlns="com.esri.solutions.flexviewer.*" xmlns:mx="http://www.adobe.com/2006/mxml> </BaseWidget> |
在widget编程模型汇中的WidgetTemplate模板提供的默认widget窗口给出了一套很丰富的内置组件。使用这个模板添加两行如下代码:
<?xmlversion="1.0" encoding="utf-8"?> <BaseWidget xmlns="com.esri.solutions.flexviewer.*"xmlns:mx="http://www.adobe.com/2006/mxml> <WidgetTemplateid="widgetTempalte"> </WidgetTemplate> </BaseWidget> |
按照如下几个步骤进行配置和部署就能看到运行结果:
第一步:在config.xml中添加创建的widget;打开config.xml文件添加下面几行代码到<widget>标记块,你可以为创建的widget使用自己的图标,可以是40×40的一个png图像文件,或者gif、jpg文件。
<widget label = "My First Widget" icon = " com/esri/solutions/flexviewer/assets/images/icons/i_globe.png" menu = "menuWidgets" config= "";> mywidgets/MyFirstWidget.swf </widget> |
第二步:保存文件并编译整个项目;具体编译方法参考上一章内容。
第三步:运Flex Viewer应用程序;右键项目中的index.mxml文件并点击Run Application。
第四步:从工具菜单,点击MyFirstWidget;
下面将会加载并输出显示你的widget。
图3 My First Widget菜单
前面给widget添加的两行代码,是的当前的widget能够有一个标准的视图和感官效果,并且能够有一些基本功能,比如能够最小化,最大化以及关闭的效果。而且,当前的widget还可以和Sample Flex Viewer进行内部通信。接下来就可以在WidgetTemplate模板上添加自己的UI元素并且写自己的业务逻辑了。
2.2 获取地图信息
Sample Flex Viewer是一个基于地图服务开发的应用。一旦这个应用被初始化,通常widget能够从ArcGIS的地图服务上连接到一个或者多个地图资源。在基类BaseWidget中定义了一个公共属性map,一个widget被加载以后widget管理器就会把当前激活的一个地图对象传给这个widget。这个widget的map属性来自com.eari.ags.Map类,继承于ArcGIS API for Flex。你就能够访问到ArcGIS提供的所有的地图参数。widget的代码写起来就像一个常规的ArcGIS Flex的应用程序一样。这里有一个例子,在MyFirstWidget中添加了一个按钮。当点击这个按钮时,地图就会自动的以当前设置的坐标为中心。在编译并且配置完widget后重新运行Sample Flex Viewer应用程序,如图:
图4 My First Widget微件图
2.3 在地图上显示widget数据
添加图层
建议为每一个新创建的widget添加一个图层,这个图层能够被添加到地图服务中去,具体是在widgetConfigLoaded这个事件处理器中的init方法进行相关初始化操作。当所有的widget的配置信息加载完毕并且待命时就会传出一个widgetConfigLoaded事件。相应代码如下:
<?xmlversion="1.0" encoding="utf-8"?> <BaseWidgetx="600" y="300" xmlns:esri="http://www.esri.com/2008/ags" xmlns="com.esri.solutions.flexviewer.*"xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:mxeffects="com.adobe.ac.mxeffects.*" xmlns:widgets="com.esri.solutions.flexviewer.widgets.*" widgetConfigLoaded="init()"> <mx:Script> <![CDATA[ …
privatefunction init():void { graphicPointSym= new PictureMarkerSymbol(widgetIcon, 30, 30) graphicsLayer = new GraphicsLayer(); graphicsLayer.symbol= graphicPointSym; map.addLayer(graphicsLayer);
… |
一旦添加了图层,你接下来就能使用标准的ArcGIS API for Flex中的各个方法来给图层加上各种图形元素。当点击open/minimize的图标时打开/关闭widget图层。WidgetTemplate模板设置了两个窗口状态事件:widgetOpened以及widgetClosed事件。他们都是扩展于flash.events.Event这个类。你可以使用这两个事件来同步同步图层的可见性。在这个例子里,我们先添加两个事件处理器到WidgetTemplate模板:
<WidgetTemplateid="wTemplate" widgetClosed="widgetClosedHandler(event)" widgetOpened="widgetOpenedHandler(event)"> privatefunction widgetClosedHandler(event:Event):void { graphicsLayer.visible= false; }
privatefunction widgetOpenedHandler(event:Event):void { graphicsLayer.visible= true; } |
2.4 从地图接收数据(通过单击,画线等操作实现)
对于GIS网络应用,除了可视化数据这个特殊用途外,地图还是一个允许用户收集并且处理地图数据的数据源。或许在用户与地图进行交互的过程中,我们创建的widget需要接收如点和直线或多边形这一类的数据来进行处理。那么Sample Flex Viewer以及widget编程模型就能够用微件通过内置的setMapAction方法来请求或是接收这一类的地图数据。下面这段代码展示了如何激活画图工具来追踪用户在地图上面的点击操作:
privatefunction activateTool():void { setMapAction(Draw.POINT,"Click Point", drawEnd); } privatefunction drawEnd(event:DrawEvent):void { vargeom:Geometry = event.geometry; varpt:MapPoint = geom as MapPoint Alert.show("Click location: " + pt.x + ", " + pt.y); } |
在上面的示例中,点击widget中的按钮会调用activeTool()方法。当一个指定的任务需要用户点击widget上的按钮时,程序就能够随时从地图上获取一个点的坐标信息。用户下一步需要做的就是点击地图上任意位置,然后widget就能够接收这个点击行为传送的点信息。具体由一个回调函数drawEnd()传回参数到setMapAction()方法来实现具体操作。
setMapAction方法
公共方法setMapAcion定义在BaseWidget类里(在BaseWidget.as文件中),这样所有继承该类的widget就能够自动继承这个特性。该方法定义如下:public function setMapAction(action:String, status:String, callback:Function):void,其中参数:
action: 这个字符串标记表示ArcGIS API相应的画图工具被激活。下面列出的是ArcGIS Flex API提供的能够用来访问各种画图工具的字符串标记:
extent (Draw.EXTENT) point (Draw.MAPPOINT) line (Draw.LINE) polyline (Draw.POLYLINE) polygon (Draw.POLYGON)
multipoint (Draw.MULTIPOINT)
freehandpolyline (Draw.FREEHAND_POLYLINE)
freehandpolygon (Draw.FREEHAND_POLYGON)
status:在控制条的状态栏显示的文本文字;
callback:画图操作完成后Map Manager回调的函数。
2.5 在widget中控制导航
当开发一个widget时,为了能够全屏显示,放大或是缩小地图,往往在用例中会需要控制地图的导航。比如,当一个widget被关闭后,你需要关闭相应的图层,并且使得地图处于默认的全屏状态。BaseWidget类提供了一个public方法setMapNavigation用来进行这些操作。代码如下:
<WidgetTemplateid="wTemplate" widgetClosed="widgetClosedHandler(event)"… privatefunction widgetClosedHandler(event:Event):void { graphicsLayer.visible= false; setMapNavigation(Navigation.PAN,“Pan Map”); } |
在上面的代码里,我们给WidgetTemplate这个模板一个事件处理器来相应widget关闭这个事件。在widgetClosedHandle处理器内部,public方法setMapNavigation被调用来将地图的导航显示为全屏状态。
setMapNavigation方法在BaseWidget中setMapNavigation定义如下:public function setMapNavigation(navMethod:String, status:String):void,其中参数:
navMethod:地图导航的标记列表如下:(定义了Flex API类中的导航或者Sample Flex Viewer类的SiteContainer容器)
pan (Navigation.PAN) zoomin(Navigation.ZOOM_IN)
zoomout(Navigation.ZOOM_OUT)
zoomfull(SiteContainer.NAVIGATION_ZOOM_FULL)
zoomprevious(SiteContainer.NAVIGATION_ZOOM_PREVIOUS)
zoomnext (SiteContainer.NAVIGATION_ZOOM_NEXT)
status: 在控制条的状态栏显示的文本文字
2.6 不使用WidgetTemplate模板开发Widget
开发widget并不一定会用到WidgetTemplate这个模板,再有的情况下,widget模板的窗口并不一定是必要的。比如,或许在你的应用程序中需要用一个与时钟相关的widget来显示当前的时间。这个时钟并不需要一个window框架,其代码如下:
<BaseWidget xmlns="com.esri.solutions.flexviewer.*" xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:SWFLoadersource="mywidgets/clock.swf"/>
</BaseWidget> |
在上面的代码中,我们使用一个SWFLoader来加载外部的flash文件到要开发的widget中。然而,在这个时钟微件中,会发现WidgetTemplate模板所提供的很多有用的特性我们根本没用到。所以,作为widget的开发员要有这样一个共识,那就是随时需要自己写代码来增加开发widget时所想到,而不是仅仅依赖既有模板所提供的那些特性。
2.7 开发一个自己的Widget模板
Widge编程模型允许开发者创建自己的widget模板。当然,新的widget模板类也需要实现iWidgetTemplate这个模板接口,因为他是BaseWidget类与widget的模板之间进行交互的核心接口。实现一个接口就意味着里面所有的方法都必须得以实现。这样,新的widget模板类需要实现iWidgetTemplate接口中的setTitle,setIcon和setState这三个方法。下面说明如何创建一个基于Flex组件TitleWindow的widget模板MyTemplate:
<?xmlversion="1.0" encoding="utf-8"?> <mx:TitleWindowxmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" width="400" height="300" implements="com.esri.solutions.flexviewer.IWidgetTemplate"> <mx:Script> <![CDATA[ publicfunction setTitle(value:String):void { this.title = value; } publicfunction setIcon(value:String):void{ } publicfunction setState(value:String):void{ } ]]> </mx:Script> </mx:TitleWindow> |
接下来向MyTemplate组件中添加一些代码,上面展示的只是一个最简单的widget模板,它能够接收widget的标题,图标并在TitleWindow组件中进行配置。下一步我们在mywidgets空间(文件夹)下创建一个新的widget并,命名为MyTempWidget,使用我们自己的模板,然后在其中添加一个按钮。
<?xmlversion="1.0" encoding="utf-8"?> <BaseWidget xmlns="com.esri.solutions.flexviewer.*"xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:mywidgets="mywidgets.*"> <mywidgets:MyTemplate> <mx:Buttonlabel="Hello, World!"/> </mywidgets:MyTemplate> </BaseWidget> |
2.8 修改或创建一个主题
Sample Flex Viewer应用程序的整体观感都能够自定义或是根据需要进行修改。这个主题(或者叫做‘皮肤’)它跟我们编程代码是分开的。内置的主题名字叫做DarkAngle。DarkAngle皮肤是使用web上标准的层叠样式列表文件com/esri/solutions/flexviewer/themes/darkangel/style.css进行构建的。这个CSS文件也能被编译成一个独立的主题文件,一个SWF。它在运行时被从配置文件config.xml所指定的位置加载到应用程序中。在config.xml配置文件中stylesheet标签用来提供主题的swf文件的URL地址共应用程序访问。注意: 对Sample Flex Viewer应用程序作的修改会在运行时自动的应用到各个微件。下面的步骤说明如何新建一个自己的主题:
第一步:修改DarkAngle的css文件或者新建一个css文件;新建css文件的话要遵循css标准,可以参考Flex开发文档。
第二步:改变或者是替换原有图标:在css文件中有一些使用到内置图标的图像文件元素,你可以修改这些css文件中对于的图标。
第三步:编译css文件到swf文件中;这一步很重要只有编译到swf文件才能被Sample Flex Viewer应用在运行时所识别和加载。要编译这个css文件,只需要右键之并从弹出菜单选择Compile CSS to SWF 命令。选择了这个命令以后,下次build这个Flex Viewer项目时css文件会被自动编译到一个独立的swf文件中去。为了能够重新生成主题文件,你可以再编译一下当前的项目。
第四步:添加新建主题文件的URL到config.xml配置文件。要使用新建的主题文件,只需要修改config.xml中的stylesheet标签,指定到编译好的swf主题文件位置。
2.9 Widget配置
通过设计每个widget能够产生自己的配置文件,这些配置文件的位置在Sample Flex Viewer里config.xml相应的widget标记对中指定。widge编程模型只支持xml格式的配置文件。WidgetManager会把widget配置文件的URL传给BaseWidget。BaseWidget会加载并分析这个xml格式的配置文件,然后在该文件的actionScript代码段中设置一个public的属性configXML传递配置参数。当widget创建完成后可以在自己的widget代码中访问到configXML这个属性。即使盒外开发的Viewer只支持xml格式的配置文件,你也可用自己的配置文件来格式化widget代码。这些配置文件会被Flex的HTTPservice服务连接并加载。在加载和分析其他格式的配置数据时也能使用相同的方法。
3 了解Sample Flex Viewer核心代码
Sample Flex Viewer源代码对公众免费开放,而且在自定义和扩展Viewer的核心功能方面没有任何限制。具体限制参考发布包中许可文件。Flex Viewer的设计是为了使开发者在扩展时更方便。通过Container Event Bus以及利用依赖注入这两种设计方法可以实现高内聚和低耦合。在自定义Sample Flex Viewer的内核时,这两张方法很重要。
3.1 事件总线容器
Event Bus容器是一个全局的时间发布器,它是用来促进不同组件直接的交互(或者说信息传递)。事件总线容器在EventBus这个类(存在于EventBus.as文件)中定义,在SiteContainer类(存在于SiteContainer.mxml文件)中定义的一组静态代理方法保证了能够顺利访问event bus容器。下表说明了Configmanager如何加载配置并通过事件容器将其应用到其他组件的。当Configmanager被初始化以后,它就开始监听事件,如图:
public function ConfigManager() { super(); //make sure the container is properly initialized and then //proceed with configuration initialization.
SiteContainer.addEventListener(SiteContainer.CONTAINER_INITIALIZED, init); } |
在上面的代码中,定义的inti()函数是一个接收到事件后会开始加载配置数据的事件处理器。其中addEventListener方法又是一个用来访问事件总线的代理方法。
图5 Flex Viewer中Container组件的架构
当事件总线容器加载完毕以后SiteContainer容器就会发布CONTAINER_INITIALIZED 事件,具体参照以下代码:
public function init():void { _container = this; _lock = true; //make sure only one container is created. initLogging();//make sure the event bus is ready. _containerEventDispatcher = EventBus.getInstance(); //tell the modules it's on business. SiteContainer.dispatch(SiteContainer.CONTAINER_INITIALIZED); } |
在SiteContainer类中,如上所示,一旦被初始化,就会发布CONTAINER_INITIALIZED事件。通过使用发布信息方法,组件之间可以在无需其他方法和数据的直接干预下进行监护。最终这些组件就通过这些基于事件的消息达到了去耦和分离的效果。这样的话,只要组件之间的消息能够同步,那么任何组件的修改都不会直接影响到其他组件。
public function init(event:Event):void { configLoad(); } //config load privatefunction configLoad():void { var configService:HTTPService = new HTTPService(); configService.url = "config.xml"; configService.resultFormat = "e4x"; configService.addEventListener(ResultEvent.RESULT, configResult); configService.addEventListener(FaultEvent.FAULT, configFault); configService.send(); } //config result privatefunction configResult(event:ResultEvent):void { try { //parse config.xml to create config data object var configData:ConfigData = new ConfigData(); ………… //dispatch event SiteContainer.dispatchEvent(new AppEvent(AppEvent.CONFIG_LOADED, false, false, configData)); } |
在上面的表格中,一旦ConfigManager完成了对配置文件的分析,它就会发布一个带有配置信息的数据,而所有需要配置信息数据的组件,比如WidgetManager以及MapManager,只需要简单的接收这个事件发布的数据。
private function init():void {
SiteContainer.addEventListener(AppEvent.CONFIG_LOADED, config); … } |
这个通过事件总线发布消息的方法可以在Sample Flex Viewer的核心代码中找到。你也可以用相同的方法来添加组件或是改变组件之间交互的方式。
3.2 依赖注入(DI)
依赖注入在通常的电脑编程中指的是向一个软件中的组件添加一个外部依赖的过程。应用控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用,传递给它。也可以说,依赖被注入到对象中。所以,控制反转是,关于一个对象如何获取他所依赖的对象的引用,这个责任的反转。
一般情况下,如果一个对象获取了某一个服务资源,这个对象就有责任挂载这个服务:要么是直接挂载这个服务所在位置的一个依赖关系,要么转到所谓的“服务查询器”并请求它传回一个特定类型服务实现的依赖。相反,如果使用依赖注入,这个对象只需要简单的提供一个能够挂载住该特定类型服务依赖的属性即可;当这个对象被创建时,外部机制就会自动生成一个实现了该类型服务的依赖的属性。这种依赖注入的方式提供了更好的灵活性,因为使得创建给定服务类型的实现并将其应用于配置文件而不需要改变使用该类型服务的对象这个过程变得更加简单。在Sample Flex Viewer中,这个过程体现在创建widget中,DI同样能够被用来创建自定义的widget模板。
下面的代码介绍了WidgetManager是如何运用依赖注入在不需要知道widget的具体实现的情况下加载相应widget到容器的:
private function widgetReadyHandler(event:ModuleEvent):void { var info:IModuleInfo = event.module; moduleTable.add(info.url, info); var id:Number = info.data.id; var label:String = configData.configWidgets[id].label; var icon:String = configData.configWidgets[id].icon; var config:String = configData.configWidgets[id].config; var widget:IBaseWidget = info.factory.create() as IBaseWidget; widget.setId(id); widget.setTitle(label); widget.setIcon(icon); widget.setConfig(config); widget.setConfigData(configData); widget.setMap(map); widgetTable.add(id, widget); var widgetDO:DisplayObject = widget as DisplayObject; addChild(widgetDO); this.cursorManager.removeBusyCursor(); } |
在上面代码中,一旦widget模块被加载,他就会转变成IbaseWidget接口类型。而BaseWidget在这个Di应用中是需要扩展IbaseWidget接口的,这样WidgetManager就不需要知道所操作的widget是那种类型或是具有哪些功能。WidgetManager只需要调用IbaseWidget中定义的各个方法来和已加载的widget进行交互。由此,实现widget的时候就不用关心它可能会有多么的复杂,而且这个实现的过程跟WidgetManager乃至整个Flex Viewer容器是完全分离开的。在这种情况下,开发员就能够相对自由地开发自己的widget而不受Flex Viewer框架的限制了。建议在开发自定义的Sample Flex Viewer核心功能时最好通过使用DI来保持这种开发widget的灵活性。这样做可以通过添加微件而不是修改核心功能的特性来增加功能的一致性。这种方法可以使得你开发的程序比别人简单许多,而且一定程度上避免了在添加功能特性操作的复杂性。
3.3 国际化
国际化(aka i18n)和本地化(aka l10n)有很多不同之处。国际化(internationalization)是设计和制造容易适应不同区域要求的产品的一种方式。它要求从产品中抽离所有的与语言,国家/地区和文化相关的元素。换言之,应用程序的功能和代码设计考虑在不同地区运行的需要,其代码简化了不同本地版本的生产。开发这样的程序的过程,就称为国际化。国际化根据用户的需求不同,通常支持多种语言的选择;而本地化通常是针对区域语言。由于跟国际化所依赖的语言元素不同,它们的设计方法也有所区别。
鉴于Sample Flex Viewer并不是最终设计和开发的成品,它以在代码中以示例的形式支持国际化和本地化,而并没有将其统一化。
3.3.1使用Flex的国际化特性
对于Flex如何支撑国际化的具体细节,请参考Flex软件开发工具包(SDK)文档。在Sample Flex Viewer项目中创建了一个子文件夹nls来承载国际化的所有文本字符。比如,这里提供了有两种语言en_US(美式英语)和fr_FR(法语)。下面介绍配置Flex Builder使其支持国际化的步骤:
第一步:从项目属性中添加编译器选项;
第二步:把国际化的目录路径添加到Build Source;路径中的{locale}允许编译器根据步骤一中的编译选项进行操作。
第三步:为语言创建资源文件;比如说,我们在nls文件夹下的en_US以及fr_FR子文件夹中创建了一个资源文件WidgetTemplateStrings.properties然后Flex的编译器能够自动识别到扩展名properties。资源文件中的语言文本字符定义很简单;
第四步:在代码中使用国际化。比如在WidgetTemplate.mxml中使用国际化资源,需要先定义绑定到指定资源文件的资源绑定。
<mx:Metadata> [ResourceBundle("WidgetTemplateStrings")] </mx:Metadata> |
然后创建一个nlsString方法来检索指定语言的字符串。
private function nlsString(nlsToken:String):String { return resourceManager.getString('WidgetFrameStrings', nlsToken); } addTitlebarButton("com/esri/solutions/flexviewer/assets/images/ widget/w_delete.png",nlsString("close"), closeWidget); addTitlebarButton("com/esri/solutions/flexviewer/assets/images/ widget/w_min.png", nlsString("minimize"), minimizeWidget); |
3.3.2本地化设置
作为一个可选方法,使用配置文件来使得标签字符本地化还是很简便的。Sample Flex Viewer中内置的widget 比如LiveMapsWidget就是个很好的例子。在这个widget种,标签字符都被定义在widget的配置文件LiveMapsWidget.xml中。在这种情况下,如果想覆盖默认语言设置的话,只需要编辑配置文件中的代码即可。
<configuration> <labels> <visibilitylabel>Layer Visibility</visibilitylabel> <transparencylabel>Layer Transparency</transparencylabel> </labels> </configuration> |
3.4 日志和错误处理
日志和错误处理功能的结合有助于开发功能文档和高质量的软件。
日志处理
在ActionScript和Flex的应用程序的日志记录中常常有很多可用的选项和工具。比如,我们在SiteContainer中设置了一个日志文件来记录远过程调用协议(RPC)和基于基于网络信息传输过程中的错误信息。HTTP连接是一类RPC连接,它记录日志文件的代码如下:
private function initLogging():void { // Create a target. var logTarget:TraceTarget = new TraceTarget(); // Log only messages for the classes in the mx.rpc.* and // mx.messaging packages. logTarget.filters=["mx.rpc.*","mx.messaging.*"]; // Log on fatal levels. logTarget.level = LogEventLevel.FATAL; // Add date, time, category, and log level to the output. logTarget.includeDate = true; logTarget.includeTime = true; logTarget.includeCatego = true; logTarget.includeLevel = true;// Begin logging. Log.addTarget(logTarget); } |
这里用的是基于Flex的日志结构。更多详细信息可用参考Flex文档。
错误处理
ActionScript3提供了强大的堪比Java的错误处理机制。然而,相应的编译器却不能够如后者一样去预测潜在的错误和异常。所以,Flex或者说ActionScript的程序员就要自己使用错误事件处理器和try-catch异常捕获功能来捕获和处理编程过程中遇到的各种问题。最好的建议是:实现所有可能想到的错误事件;尽量尝试使用try-catch异常捕获功能。
一旦发现错误,最好用直白易懂的语言去做标注并解释错误情况。Sample Flex Viewer提供了一个简单的错误显示功能并能够方便地发送和提示相应的错误信息。对于一个widget ,定义在BaseWidget中的一个public方法showError()能够用来实现这一功能,例如:
showError("This is a <b>test</b> error message!");
这段代码用来返回Sample Flex Viewer应用程序中出现的错误。注意到这段错误信息窗口只是一个形式,里面的文本可以使用基本的Html标记进行必要的设计。在后台,这个错误信息是通过前面一章讲到过对的事件总线来进行传递的。换言之,错误信息能够在Flex Viewer或者一个widget中根据需要任意传播。
SiteContainer.dispatchEvent(new AppEvent(AppEvent.APP_ERROR, false, false, “the error message string”)); |
4 Sample Flex Viewer框架和Widget部署
4.1 部署一个Sample Flex Viewer应用程序
如果你已经下载了Sample Flex Viewer的发布包,那么只需要简单的解压该zip文件到一个能够访问到网络服务器的文件系统下面即可完成部署。也可能需要配置一下网络服务器是的加载这个文件系统时输入的URL更简洁。比如在第2.3节中讲到过,可以创建一个IIS的虚拟目录,这一块的部署跟其他Html的网络应用程序部署方法基本相同。
部署自己编译的Sample Flex Viewer 应用
如果你想使用自己编译的代码来部署Sample Flex Viewer应用程序,建议多做一步,就是用到Project菜单下的Export Release Build命令。因为去除了相应的debug信息,到处的swf文件往往会更小。最终,这个应用比Debug后创建的程序更好用。默认情况下,Flex会创建一个新的文件夹bin-release来放置相关的发布文件。而这个文件夹里面的所有文件都可以是你的发布包中的内容。也就意味着你可以对它重新命名,把它打包并部署到特定的网络应用中去。
4.2 部署一个widget到Sample Flex Viewer
假设一个Sample Flex Viewer的应用已经部署并且也已开发好了一个widget,那么下面说明如何配置这个widget:
第一步:把widget的swf文件复制到特定的文件位置;一个widge是一个独立于外部的swf文件,你可以把该swf文件拷到Sample Flex Viewer应用的网络服务器能够访问到的位置或者直接拷到另外一个网络服务器上。
第二步:修改 Sample Flex Viewer应用的配置文件;配置文件config.xml在该应用程序的根文件夹下,该文件内部的widgets标签下需要添加一个新的widget入口。Sample Flex Viewer应用程序支持widget在运行时配置到相同的网络服务器时的相对路径。这个新添加的widget标签如下:
<widget label="A New Widget" icon="urlpath/myicon.png" menu="menuWidgets" config=”youconfig.xml”>relative/urlpath/MyNewWidget.swf</widget> |
如果你将widget配置到了另外一个网络服务器,那么增加的widget表情里面的Url应该是一个完整路径。比如,应用到Icon图像如下:
<widget label="A New Widget" icon="http://another-host/urlpath/myicon.png"menu="menuWidgets"config=”yourconfig.xml”>http://another- host/urlpath/MyNewWidget.swf</widget> |
你可以在widget中明确指定一个配置文件。在这个代码中,定义于BaseWidget的的全局属性configXML也能够在widget中用到。目前,盒外开发的Sample Flex Viewer的应用程序只支持XML格式的配置文件并且能够自动地构建configXML属性。如果你想在自己的widget代码中分析配置数据的话该配置文件可以使用任意格式。
第三步:刷新Sample Flex Viewer应用。当下次Sample Flex Viewer应用程序被刷新时,新建的widget的配置将会被自动识别并且这个widget能够在用户界面中通过tool菜单(或者在config.xml文件中自定义的菜单)调用。
4.3 安全性考虑
4.3.1 crossdomain.xml
一个虽法律上站不住但事实上却普遍认知的网络浏览器标准就是把安全沙盒强加到浏览器的插件中。这就意味着当前网页运行的插件只能够访问通过相同网络服务器提供的远程资源。而Flash这个运行基于Flash开发的软件的浏览器插件也会受到同样的基于Flash开发的应用的沙盒限制。然而默认情况下,一个Flash应用只有在其他网络服务器部署有一个crossdomain.xml文件的情况下才能从该服务器URL的根目录下通过相关的Flash应用访问远程资源。
最简单形式的crossdomain.xml文件如下:
<cross-domain-policy xsi:noNamespaceSchemaLocation="http://www.adobe.com/xml/schemas/PolicyFile.xsd"> <allow-access-from domain="*"/>
</cross-domain-policy> |
这个crossdomain.xml文件能够访问由任何网络上的服务器提供服务的Flash应用程序。可以参考Adobe Flex的文档来了解设置这个文件的更多内容。注意:不管任何时候,只要运行Sample Flex viewer程序时发生了安全异常,就要及时检查crossdomain.xml所部属的资源服务器(比如ArcGIS的地图服务),哪怕只是自己内部组织的错误。
4.3.2网络资源代理
在许多情况下,你需要访问其他服务器所提供的资源,比如,各种GeoRSS在线反馈。如果这些反馈的服务器并没有配置crossdomain.xml文件,那么唯一的选择就是在自己由Flash部署的服务器上设置一个网络资源代理,并且在代码中指定相关代理。
这个链接提供了一些有关代理的更多资料
http://resources.esri.com/help/9.3/arcgisserver/apis/javascript/arcgis/help/jshelp_start.htm#jshelp/ags_pro xy.htm
附录: Configuration XML
关于config.xml配置文件的更多解释请参阅源代码中的readme.txt文件。
对于开发者,可以参考发布包里doc/ConfigXMLSchema目录下的xml配置文件,这里定义了config.xml文件中具体的XML标签。
相关推荐
从网上搜的也有,自己的理解也有,对于掌握FlexViewer真不错
ESRI-FlexViewer解析 了解FlexViewer内的一些控件和基础应用
ESRI公司发布的flexviewer1.3框架的源代码
Flexviewer解析,以实例代码,真实讲解了整体流程及核心代码。
FlexViewer2.3框架源码 可自由定制,开发自己的webgis
简要介绍了FlexViewer框架发展及其机制
主要讲述了FlexViewer3.1版本,新增加的一些重要的特征
ESRI公司发布的flexviewer2.0框架的源代码,较flexviewer1.3框架有很大的变化。
flexviewer2.5框架 很经典
改写FlexViewer2.4框架,将其用户界面改为FlexViewer1.3的样式。IDE FB4.5 SDK FLEX 4.5
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, ...
FlexViewer开发教程、开发指南、相关实例。
FlexViewer2.1框架源码 可自由定制,开发自己的webgis
flexviewer2.3源代码 配合arcgis flex api2.3使用 开发工具flash builder4
ESRI公司发布的flexviewer2.4框架的源代码,Flex Viewer是ArcGIS Viewer for Flex的简称, Flex Viewer是基于ArcGIS API for Flex(简称AGS Flex API)设计的一个WebGIS应用程序,用户可以通过修改配置文件、自定义...
FlexViewer开发教程,挺不错的一个FlexViewer文档,帮助快速了解Flex框架。
flexviewer的source code,2012年12月12日更新。
flexviewer简单登陆(新版本能用)