§3.3 GeoWeb2.0开发框架Flex Viewer3.3.1
Flex Viewer 简介Flex Viewer是一个组成 GeoWeb 2.0 的Flex 应用程序,同时也是一个GeoWeb 2.0应用的开发框架,它整合了ArcGIS Online ,ArcGIS Server以及其他服务器提供的服务(GeoRSS等),它将使GeoWeb 2.0成为现实。如图3-2所示:
图 3-2 GeoWeb2.0 架构图
FlexViewer设计目标是:
1)
一个使用ArcGIS API for
Flex开发并且能够即拆即用的部署(out-of-box)的RIA应用;
2)
支持ArcGIS Online ,ArcGIS Server以及其他服务器提供的服务(GeoRSS等)的访问;
3)
支持使用widget编程模型进行快速开发;
4)
提供一种GeoWeb 2.0的开发模式。
3.3.2
Flex Viewer 体系结构1)Flex Viewer 实例的生命周期
Flex Viewer实例的生命周期主要包括5个方面,如图3-3所示:
图3-3 Flex Viewer实例生命周期
a)
在浏览器中Flash Player打开Flex Viewer应用程序,加载并运行 container。
b)
container从web服务器加载配置文件(config.xml)和皮肤(skin.swf),并应用到整个应用程序(根据skin.swf生成界面效果)。
c)
根据配置文件(config.xml)加载地图服务,并生成工具条和菜单项。
d)
Container中的widget Manager根据配置文件中提供的widget url加载widget swf 文件。
e)
用户结合widget完成自己的业务逻辑。
2)Flex Viewer Container
Flex Viewer container 提供了复杂的地图管理,数据管理,程序配置,内部组件通信等功能,使Web开发人员特别是使用ESRI ArcGIS技术的人员能够只关注于业务逻辑的开发。并且因为使用配置文件来动态生成应用程序,适合快速开发和部署(只需要修改配置文件,不需要重新编译)。Flex Viewer container的体系架构如图3-4:
图 3-4 Flex Viewer container体系架构图
3)Widget 编程模型(Programming Model)
一个编译好的widget 是一个标准的swf文件,可以部署到任何一个Flex viewer应用程序中,需要做的只是修改flex viewer 应用程序的配置文件。
Flex viewer中的Widget 编程模型是一个轻量级的编程模型,他使开发人员方便的开发自定义的Widget而不需要关心flex viewer 应用程序底层的实现。
图3-5为Flex viewer开发一个Widget的流程:
图 3-5 Widget开发流程
a)
继承base widget。
b)
封装业务逻辑(包括对地图的操作,对数据和服务的访问等)。
c)
部署到Flex viewer 应用程序中(widget manager 根据配置文件来加载widget)。
d)
widget manager 通过配置信息来管理widget的声明周期。
e)
Flex viewer 应用程序通过接口和widget进行交互。
在Flex viewer的实现中,Widget 编程模型包括2个AS类和2个AS接口,分别是IBaseWidget接口,BaseWidget类,IWidgetTemplate接口和WidgetTemplate类。IBaseWidget接口提供了和widget manager交互的方法,BaseWidget 类实现了IBaseWidget接口。一个Flex viewer的自定义Widget必须继承BaseWidget类。IWidgetTemplate接口定义了WidgetTemplate和BaseWidget之间进行协作的方法。内建的WidgetTemplate类实现了IWidgetTemplate接口。WidgetTemplate类为BaseWidget提供基本的UI布局和行为,包括风格化的窗口面板(styled window panel),标题栏(title bar)以及自定义的图片按钮(custom image buttons)。
3.3.3开发Widget开发工具:Flex Builder3
开发语言:ActionScript & mxml
1)开发环境配置:
a)
首先确保Flex Builder3(Flex SDK 3.1)安装成功,并下载Flex viewer(libs目录中包含ArcGIS API for Flex v1.0)。
b)
解压下载下来的Flex viewer压缩包。
c)
打开Flex Builder3,将刚解压出来的源代码导入到flex workspace中。在导入向导中选择源代码的目录,点击finish。
d)
编译Flex Viewer。选中当前工程,在Project 菜单下选择Build Project。
2)自定义widget开发
a)
新建一个mxml组件(右键单击flex
Viewer ,选择New->MXML Component)。选择组件目录,输入组件名称,并确保该组件继承BasWidget类。
b)
将创建好的widget添加Flex Builder Project Module list。
右键单击Flex Viewer 工程,选择属性(properties),打开属性配置框,然后在左边列表择Flex Modules。单击Add按钮,选择MyFirstWidget.mxml。 这一步的目的是确保MyFirstWidget能够被编译成单独的swf文件。
c)
编译widget。
重新编译整个Flex Viewer 工程即可。编译完成之后在bin-debug目录下就会有MyFirstWidget.swf。
3)使用WidgetTemplate
打开MyFirstWidget.mxml文件,可以看到如下代码。
要使用WidgetTemplate,只需要添加2行代码,如下所示:
内置的WidgetTemplate提供了丰富的界面元素。下面介绍如何部署Widget。
a)
把Widget加入到config.xml文件中。
打开config.xml文件并在
b)
保存config.xml文件并重新编译Flex Viewer。
c)
运行Flex Viewer。
d)
从Tool菜单中选择My First Widget。如图3-6所示:
图3-6 自定义模板
至此,通过添加2行代码就完成了个基本的Widget UI 设计,已经有了最大化,最小化,关闭等功能。下一步,就是实现业务逻辑。
4) 访问地图 (Accessing a Map)
Flex Viewer是一个以地图为中心的应用程序,所有的操作都是围绕地图来进行。Flex Viewer初始化之后,Widget就可以访问地图了(来自ArcGIS Server 的地图服务)。
map是BaseWidget类中定义的一个public 属性,只要是继承BaseWidget的类都可以访问改属性,该属性是com.esri.ags.Map(ArcGIS API for Flex)类型,因此可以使用map对象访问任何在ArcGIS API for Flex中的对象。当widget 被加载之后,widget manager会动态的把当前活动的地图对象关联到widget。
下面的例子演示的是当点击按钮之后,地图中心会平移到指定的坐标处。
重新编译Flex Viewer,并运行。可以看到下面结果,如图3-7:
图 3-7平移到地图中心
5) 在地图上显示业务数据
a)
添加Graphics Layer
建议为每个Widget都创建一个Graphics Layer。创建并添加Graphics Layer的代码如下:
在上面代码中,Graphics Layer在widgetConfigLoaded事件的响应函数中创建。widgetConfigLoaded事件在widget所有的配置信息被加载之后分发(dispatched)。
b)
Widget打开/最小化的时候打开/关闭Graphics Layer
WidgetTemplate提供了2个窗口状态的事件:widgetOpened 和 widgetClosed,可以使用这两个事件来同步WidgetTemplate窗口状态的变化和Graphics Layer显示。当widget打开的时候显示Graphics Layer,当widget关闭的时候隐藏Graphics Layer。例子如下:
首先侦听widgetOpened 和 widgetClosed事件。
在widgetOpened 和 widgetClosed事件的响应函数中控制Graphics Layer的显示。
6)Widget中使用绘制功能
在 Flex Viewer 中通过调用setMapAction方法,可以方便的进行地图上的绘制。setMapAction是在BaseWidget类中定义的public方法,因此只要继承于BaseWidget类的Widget都可以使用该方法。
setMapAction方法的定义如下:
参数:
action: String 类型,定义为当前绘制操作的要素类型。对应ArcGIS Flex API 中绘制工具的绘制要素类型。对应列表如表3-2:
表 3-2:flexViewrer与ArcGIS API for Flex绘制消息对应表
Flex Viewer |
ArcGIS API for Flex |
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: String 类型,在控制栏上显示的状态文本。
callback: Function类型,绘制结束后调用的回调函数。回调函数的定义可以参考下面代码:
7)Widget控制地图浏览
地图的浏览主要包括放大、缩小、漫游、复位、上一视图、下一视图等。和在地图上绘制类似,在 Flex Viewer 中通过调用setMapNavigation方法,可以控制地图的浏览操作。setMapNavigation是在BaseWidget类中定义的public方法,因此只要继承于BaseWidget类的Widget都可以使用该方法。
setMapNavigation函数的定义如下:
参数:navMethod:String类型,浏览操作类型。对应ArcGIS Flex API中Navigation工具中的浏览操作类型以及SiteContainer中定义的浏览操作类型。对应列表如表3-3:
表 3-3:flexViewrer与ArcGIS API for Flex浏览操作消息对应表
Flex Viewer |
ArcGIS Flex API / 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: String 类型,在控制栏上显示的状态文本。
8)其他Widget开发方式(不使用Widget Template)
开发Widget不一定非要使用Widget Template,因为在有些情况下不需要Widget Template,例如在Widget中显示一个时钟。如图3-8所示:
图 3-8
FlexViewer中显示时钟
开发这个Widget,只需要下面几行代码:
9)开发自定义Widget Template
当使用内置的Widget Template不能满足业务需求的时候,就需要开发自定义的Widget Template,来定制Widget 的UI。
开发自定义的Widget Template,必须实现iWidgetTemplate接口。
下面是开发一个自定义的Widget Template的步骤:
a)
新建一个mxml组件,名称为MyTemplate,继承TileWindow类。
b)
实现iWidgetTemplate接口
在上面的代码中只是简单实现了iWidgetTemplate接口,没有定义复杂的界面元素和操作,只是一个TileWindow。
下面就可以使用MyTemplate来制作widget ,使用方法和WidgetTemplate相同,如下代码:
编译,部署,运行,可以看到结果如图3-9:
图 3-9 自定义模板
10)修改或创建新的主题( Theme)
Flex Viewer程序的界面风格是可以修改和自定义的,是不依赖于程序编码的。默认的Flex Viewer程序主题叫Dark Angel。Dark Angel主题是由CSS(com/esri/solutions/flexviewer/themes/darkangel/style.css)文件来定义的,这个CSS文件被编译成但对的主题文件(swf)。当Flex Viewer程序运行的时候通过读取配置文件(config.xml)中配置信息加载不同的主题。在config.xml中,
下面的步骤为创建一个自定义的主题:
a)
修改Dark Angel CSS文件或者创建一个新的CSS文件。
b)
修改或替换图标文件。
c)
把CSS文件编译到swf中。
d)
在config.xml中引用改主题。
修改config.xml中
11)Widget 配置
每个Widget都可以有自己的配置文件,Widget的配置在config.xml文件中指定。
Widget编程模型只支持xml形式的配置文件,Widget Manager首先从config.xml文件中解析出Widget对应的配置文件的URL给BaseWidget,BaseWidget加载并解析Widget对应的配置文件,构造一个XML类型的configXML。configXML是个public的变量,Widget创建好之后就能够被访问。
3.3.4 Flex Viewer设计模式Flex Viewer的设计原则就是“simple”,方便开发人员定制和扩展。Flex Viewer的源代码是可以自由使用的,因此可以很方便的在Flex Viewer基础上进行定制和扩展。
1)事件总线(Event Bus)
Event Bus 是Flex Viewer中组件用来进行通信的模块,其本质是是一个全局的事件调度器,负责各个事件的分发。Event Bus是在EventBus类中实现,在这个类中定义了一些静态代理函数,保证各个组件对Event Bus的访问。
下面介绍一下ConfigManager如何加载配置文件,然后通过Event Bus发送给其他组件。
a)
在ConfigManager的构造函数里添加CONTAINER_INITIALIZED事件的侦听。
当侦听到CONTAINER_INITIALIZED事件后,Init函数响应。CONTAINER_INITIALIZED事件是在SiteContainer构造完成后分发的,如下代码:
b)
当ConfigManager将配置文件解析完成之后,就会分发CONFIG_LOADED事件。解析后的配置文件打包成一个ConfigData和事件一起分发。
c)
其他需要ConfigData的组件添加对CONFIG_LOADED事件的侦听。下面是WidgetManager的init函数,添加了对CONFIG_LOADED事件的侦听。
详细流程如图3-10:
图 3-10
Event Bus流程图
2)依赖注入原则(Dependence Injection)
依赖注入是指将类之间的关系通过第三方进行注射,不需要类自己去解决调用关系。目的是降低类之间的耦合度,实现的时候就是把依赖从编译时推迟到运行时。
在Flex Viewer 中使用了DI原则。通过使用配置文件的方式将对界面的构建,服务的调用推迟到运行时,而不是在编译时就固定好。即编译时刻程序不知道使用哪些图片来创建UI,不知道调用哪些地图服务,只有当配置文件被加载到Flex Viewer 中时,这些要素才被固定。因此这就为程序的发布提供很大的灵活性,界面修改,服务更换只需要编辑配置文件,而不需要重新编译。
下面以WidgetManager加载Widget为例,介绍一个DI在Flex Viewer中的应用。
在上面代码中,Widget模块被加载之后将会转换成IBaseWidget类型。IBaseWidget接口就是供DI来使用的。当Widget被转换成IBaseWidget之后,WidgetManager不关心Widget从哪里来,也不关心Widget能做什么,WidgetManager只关心IBaseWidget的方法。通过IBaseWidget的方法,WidgetManager来管理Widgets。
3)国际化(Internationalization)
国际化(Internationalization)和本地化(localization)是有区别的。国际化是支持多国语言,而本地化是只关注于本国语言的支持。因为Flex Viewer不是一个完整的产品,所以他的国际化和本地化没有完全支持,只是提供了示例代码,而不是完整的实现。目前Flex Viewer提供了两种语言的支持,英语 (US English) 和法语(French)。
a)
创建资源文件
在Flex Viewer 工程的源代码nls目录下的en_US和 fr_FR目录下都有WidgetTemplateStrings.properties文件,这个文件就是资源文件,Flex 编译器会自动识别properties文件并编译。
properties文件中字符串的定义很简单,是[name,value]对,中间用等号隔开,如下面代码:
b)
在代码中使用资源文件
使用这些资源文件,首先定义这些资源文件:
然后创建nlsString函数去资源文件中查找特定的字符串。
例如,想查“close”, nlsString(“close”)即可,如下代码:
4)自定义本地化
对Flex Viewer进行本地化(比如对简体中文的支持),推荐使用修改widget配置文件的方式来做,而不是通过国际化的方式。
在widget配置文件中定义需要本地化的字符串,然后通过解析配置文件,完成本地化工作。如下面代码(printWidget.xml):
当需要修改显示的内容时,只要编辑配置文件就可以了。
5)日志和错误处理
记录日志以及添加错误处理逻辑,能够很好的保证程序的健壮性,也能够更加快速的定位到问题,在Flex Viewer中提供了日志记录和错误处理的能力。
a)
日志记录:
在SiteContainer中,定义日志记录模块,用来记录RPC远程调用错误信息。
代码如下:
b)
错误处理:
ActionScript 提供了强大的错误处理能力,但flex编译器不像java那样强制捕捉可能的错误或异常。在flex 编程中,程序员要么使用ErrorEvent要么使用try-catch去处理错误。一旦捕捉到错误或者异常,最好通知用户发生了什么错误并说明什么情况下会产生这个错误。
在Flex Viewer中,只需要调用showError()函数即可讲错误信息返回给用户。showError()函数是BaseWidget中定义的public方法,只要继承于BaseWidget的Widget都可以调用。如下面代码:
效果如图3-11:
图 3-11 错误信息显示
3.3.5 Flex Viewer部署1) 部署 Flex Viewer应用程序
a)
导出release Build。
b) 将bin-release目录的内容拷贝到web服务器即可,详细请参考IIS 或其他web服务器如何发布网站。
2) 部署Widget到Flex Viewer应用程序
将一个新开发的Widget部署到已经发布的Flex Viewer应用程序中去的步骤如下:
a)
拷贝Widget.swf到需要部署的目标位置,即部署Flex Viewer的web服务器或其他web服务器,确保有对其访问的权限。
b)
修改Flex Viewer的配置文件,即config.xml
在widgets标签下面添加如下代码:
如果widget不和Flex Viewer在同一个web服务器上,则url需要使用全路径,如下面代码:
c)
刷新Flex Viewer程序。
新的widget就已经出现在Flex Viewer程序中了。
4) Security Considerations
a)
crossdomain.xml
在flex开发中,经常会遇到安全沙箱的问题。Flex 不能进行跨域访问。解决这个问题,就需要将crossdomain.xml放置到发布服务的web服务器的root目录下。
crossdomain.xml的内容如下:
b) 网络资源代理(Internet Resource Proxy)
在一些情况下需要访问一些服务(例如GeoRSS feeds),发布这些服务的web服务器又没有配置crossdomain.xml,那么只能通过网络资源代理来访问。