Flex中的MySQL管理

 学习使用RIA Framework Flex创建MySQL管理UI

PHPMyAdmin的出现震撼了业界,这毫无疑问。它当然是基于PHP的最佳应用程序,因为它将MySQL管理界面由命令行的形式改为了web浏览器的形式。不过,虽然它的功能很强大,但使用并不太方便,界面也不够美观。因此,我尝试通过Rich Internet Application框架设计更理想的MySQL前台管理程序。

要达成此目标本可选用Ajax。但我不想处理客户端的不兼容问题。当然,Silverlight也是不错的选择,但它仍不够成熟。 之所以选择Adobe Flex,是因为它拥有富用户接口工具集和方便的web服务集成功能,而且它生成的Flash应用程序能够以相同方式在任何操作系统中运行。

我学习了很多有关创建应用程序方面的知识:如何为PHP程序创建安全的SQL web服务;如何通过Flex访问web服务;如何将web服务返回的数据输入数据网格中并显示。在本文中,我将引领读者从前台到后台,逐步创建MySQL管理程序。读者从中可了解一些有用的信息,以创建自己的Rich Internet应用程序。

创建后台程序

Flex应用程序擅长与web服务通讯,以发出请求及提交数据。因此,首先需要创建一个非常简单的PHP脚本,它将以XML格式返回数据库列表、表或表中的数据。
清单 1. req.php

<? php
require_once ( " MDB2.php " );
$sql   =   ' SHOW DATABASES ' ;
if  (  $_REQUEST [ ' mode ' ==   ' getTables '  )
$sql   =   ' SHOW TABLES ' ;
if  (  $_REQUEST [ ' mode ' ==   ' getData '  )
$sql   =   ' SELECT * FROM  ' . $_REQUEST [ ' table ' ];
$dsn   =   ' mysql://root@localhost/ ' . $_REQUEST [ ' db ' ];
$mdb2   =&  MDB2 :: factory( $dsn );
if  (PEAR :: isError( $mdb2 )) {  die ( $mdb2 -> getMessage()); }
$dom   =   new  DomDocument();
$dom -> formatOutput  =   true ;
$root   =   $dom -> createElement(  " records "  );
$dom -> appendChild(  $root  );
$res   =&   $mdb2 -> query(  $sql  );
if  (PEAR :: isError( $mdb2 )) {  die ( $mdb2 -> getMessage()); }
while  ( $row   =   $res -> fetchRow(MDB2_FETCHMODE_ASSOC))
{
$rec   =   $dom -> createElement(  " record "  );
$root -> appendChild(  $rec  );
foreach array_keys $row  )  as   $key  ) {
$key_elem   =   $dom -> createElement(  $key  );
$rec -> appendChild(  $key_elem  );
$key_elem -> appendChild(  $dom -> createTextNode(  $row [ $key ] ) );
}
}
$res -> free();
$mdb2 -> disconnect();
header " Content-type: text/xml "  );
echo   $dom -> saveXML();
?>
该脚本的第一项工作就是利用MDB2库连接数据库。如果没有安装MDB2库,则可使用PEAR安装该库,如下所示:
%  pear install MDB2
%
如果PEAR无法正常运行,可访问http://pear.php.net/mdb2,然后下载源代码并将其解包到PHP的include路径下。MDB2是通用的数据库适配器层,它已取代了广为使用的PEAR DB库。

脚本的第二项工作就是创建XML DOM Document对象,该对象将用来创建要输出的XML树。从此处开始,它将运行查询,并在XML树中添加row和column作为XML标签。最后,该脚本将关闭所有连接,并将XML保存到PHP输出流中。

选用XML DOM对象的原因是,它可避免任何与数据、不对称标签等有关的编码问题以及各种可能使XML产生混乱的因素。我可以将调试XML数据流的时间节省下来做其他许多更有意义的工作。您一定也会这样做。
将该脚本安装到本地机器上的可运行目录下,然后使用curl命令向服务器发出请求。
%  
curl 
" http://localhost/sql/req.php "
<? xml version = " 1.0 " ?>
< records >
< record >
< database > addresses </ database >
</ record >
< record >
< database > ajaxdb </ database >
</ record >
...
%

在本例中,我并未指定数据库或模式,这会要求脚本返回可用数据库的清单。假如web服务脚本有权执行该任务,则在curl语句后面就会显示执行的结果。在本例中,将以标签的形式显示不同数据库的列表。

该脚本返回的所有数据都带有<records>标签,它包含一组<record>标签。每个<record>标签的名称和内容取决于已执行的SQL语句。在本例中,只返回单列命名数据库。

除了使用curl命令,还可将URL输入浏览器中,然后在加载页面后选择“View Source(查看源文件)”。
在下例中,将连接articles数据库并获取它的表格列表。结果如下:

% curl ".../req.php?mode=getTables &db =articles"
<? xml version="1.0" ?>
< records >
< record >
< tables_in_articles > article </ tables_in_articles >
</ record >
</ records >
%
articles数据库中只有一个名为article的表格,这并不奇怪。要运行经典的select * from article查询以获取所有记录,可使用以下URL:
% curl ".../req.php?mode=getData
&db =articles &table =article"
<? xml version="1.0" ?>
< records >
< record >
< id > 1 </ id >
< title > Apple releases iPhone </ title >
< content > Apple Computer is going to release the iPhone... </ content >
</ record >
< record >
< id > 2 </ id >
< title > Google release Gears </ title >  
< content > Google, Inc. of Mountain View California has... </ content >
</ record >
</ records >
%
表格中有两条记录:第一条显示Apple公司将发布超炫的IPhone;第二条显示Google公司将发布同样很炫、但用途完全不同的Gears系统。
在本地机器上安装了极为强大且灵活的后台程序后,就可以着手为其创建Flex前台程序了。

创建用户界面

我想以层的形式创建Flex应用程序,首先是用户界面,然后在框架中添加代码以实现互动性。首先,若尚未安装Flex SDK则先安装。Flex SDK是免费软件,Flex Builder 2 IDE也有免费试用版。可从http://www.flex.org/download下载Flex SDK。Flex SDK是免费的,Flex 3 SDK也将成为开源软件。Flex Builder是一种基于Eclipse的开发环境,通过拖放控件即可创建界面,但本例不必使用该工具。我非常喜欢使用标签,因此通常采用代码视图并直接修改MXML。

我想在界面顶部放置几个控件并在底部放置一个数据网格,以显示表中的数据。顶部的控件就是两个下拉列表,可在其中选择数据库和表。

该窗体的MXML如清单2所示。
清单 2. flexmysql1.mxml
<? xml version="1.0" encoding="utf-8" ?>
< mx:Application  xmlns:mx ="http://www.adobe.com/2006/mxml"  layout ="vertical" >
< mx:VBox  horizontalAlign ="left" >
< mx:HBox >
< mx:Label  text ="Database:"   />
< mx:ComboBox  id ="selectedDatabase"  width ="381"  height ="21" >
</ mx:ComboBox >
</ mx:HBox >
< mx:HBox >
< mx:Label  text ="Table:"   />
< mx:ComboBox  id ="selectedTable"  width ="381"  height ="21" >
</ mx:ComboBox >
</ mx:HBox >
< mx:DataGrid  id ="dg1"  width ="452" >
</ mx:DataGrid >
</ mx:VBox >
</ mx:Application >

在Flex Builder 2中编译及运行这段代码时,结果如图1所示。


图1.界面布局


相当整洁,对吧?渐变背景很漂亮,控件也很美观。我只做了极少量的工作。当然,图形设计师也可添加一些修饰,以使其更加美观,例如过渡效果和图像。而我还是喜欢整洁的界面,并要确保它在每台客户机上都具有一致的外观和表现,而Ajax应用程序要做到这一点并不容易。
获取数据库清单
补充Flex应用程序代码的第一步就是,当应用程序加载后在窗体顶部显示数据库的组合框。相关代码如清单3所示。
清单 3. flexmysql2.mxml

<? xml version="1.0" encoding="utf-8" ?>
< mx:Application  xmlns:mx ="http://www.adobe.com/2006/mxml"  layout ="vertical"
initialize
="onInitialize()" >
< mx:Script >
<![CDATA[
import mx.collections.ArrayCollection;
private static const SERVICE_BASE:String = "http://localhost/sql/req.php";
public function onInitialize():void
{
myservice.url = SERVICE_BASE;
myservice.send( null );
} public function onResult(event:Event):void
{
selectedDatabase.dataProvider = myservice.lastResult..database.*;
}
]]>
</ mx:Script >
< mx:HTTPService  id ="myservice"  result ="onResult(event)"  resultFormat ="e4x" >
</ mx:HTTPService >
< mx:VBox  horizontalAlign ="left" >
< mx:HBox >
< mx:Label  text ="Database:"   />
< mx:ComboBox  id ="selectedDatabase"  width ="381"  height ="21" >
</ mx:ComboBox >
</ mx:HBox >
< mx:HBox >
< mx:Label  text ="Table:"   />
< mx:ComboBox  id ="selectedTable"  width ="381"  height ="21" >
</ mx:ComboBox >
</ mx:HBox >
< mx:DataGrid  id ="dg1"  width ="452" >
</ mx:DataGrid >
</ mx:VBox >
</ mx:Application >

我省略了与前例类似的部分代码,以缩短代码段长度。差别重点在于<mx:HTTPService>标签,它将创建HTTP Service Flex对象,而后者将与服务器进行通讯。该服务对象由onInitialize方法调用, 而后者在Flex应用程序启动时调用。onInitialize方法先设置服务的URL,然后开始发出请求。请求完成后,就调用onResult方法。onResult方法将组合框的dataProvider设为web服务器的返回结果。
该方法最有价值的部分如下:
myservice.lastResult..database.*
看看这个语句。如果之前不了解E4X的作用,我可以稍加解释。myservice.lastResult变量实际上是一个XML文档。‘..’句法等价于XPath ‘//’句法。它表示“将具有此名字的任何一个标签给我”,在本例中就是“将任何一个数据库标签给我”。星号表示数据库标签的任何子标签。由于数据库标签只有一个子标签,即数据库名称的文字部分,因此这段代码就表示“将XML文档中每个数据库的名称给我”。这个功能真的很好用!
正是由于ActionScript的这种E4X扩展,Flex才能够方便地与XML数据源进行通讯。据我所知,还没有其他语言能够如此方便地查询XML文档。因此利用强大的E4X,就可以在浏览器中运行该应用程序,并得到如图2所示的结果。

图2.填充数据库名称的数据库组合框

单击该组合框时,将弹出下拉列表,并显示机器中的数据库列表。是的,其中有很多数据库。几乎每篇有关PHP、Flex、Rails或其他技术的文章都会用到数据库,所以我拥有大量的数据库。
创建表视图代码
创建示例Flex应用程序的最后一步就是添加表格的下拉菜单,并在数据网格中显示选中表格的数据。该例的完整代码如清单4所示。
清单 4. flexmysql.mxml

 

<? xml version="1.0" encoding="utf-8" ?>
< mx:Application  xmlns:mx ="http://www.adobe.com/2006/mxml"  layout ="vertical"
initialize
="onInitialize()" >
< mx:Script >
<![CDATA[
import mx.collections.ArrayCollection;
private static const SERVICE_BASE:String = "http://localhost/sql/req.php";
private var loadingDatabases:Boolean = true;
private var loadingTables:Boolean = false;
public function onInitialize():void
{
loadingDatabases = true;
myservice.url = SERVICE_BASE;
myservice.send( null );
} public function onResult(event:Event):void
{
if ( loadingDatabases )
{
loadingDatabases = false;
selectedDatabase.dataProvider = myservice.lastResult..database.*;
onSelectDatabase();
}
else if ( loadingTables )
{
loadingTables = false;
var tables:Array = new Array();
for each ( var tablRecord:XML in myservice.lastResult..record )
{
for each( var tablCol:XML in tablRecord.* )
tables.push( tablCol..*.toString() );
}
selectedTable.dataProvider = tables;
onSelectTable();
} else
{
var records:Array = new Array();
for each ( var record:XML in myservice.lastResult..record )
{
var outRecord:Array = new Array();
for each( var column:XML in record.* )
outRecord[ column.name() ] = column..*.toString();
records.push( outRecord );
}
var data:ArrayCollection = new ArrayCollection( records );
dg1.dataProvider = data;
}
} public function onSelectDatabase():void
{
loadingDatabases = false;
loadingTables = true;
var url:String = SERVICE_BASE;
url += "?mode=getTables&db="+selectedDatabase.selectedLabel;
myservice.url = url;
myservice.send(null);
} public function onSelectTable():void
{
var url:String = SERVICE_BASE;
url += "?mode=getData&db="+selectedDatabase.selectedLabel;
url += "&table="+selectedTable.selectedLabel;
myservice.url = url;
myservice.send(null);
}
]]>
</ mx:Script >
< mx:HTTPService  id ="myservice"  result ="onResult(event)"  resultFormat ="e4x" >
</ mx:HTTPService >
< mx:VBox  horizontalAlign ="left" >
< mx:HBox >
< mx:Label  text ="Database:"   />
< mx:ComboBox  id ="selectedDatabase"  width ="381"  height ="21"
change
="onSelectDatabase()" >
</ mx:ComboBox >
</ mx:HBox >
< mx:HBox >
< mx:Label  text ="Table:"   />
< mx:ComboBox  id ="selectedTable"  width ="381"  height ="21"
change
="onSelectTable()" >
</ mx:ComboBox >
</ mx:HBox >
< mx:DataGrid  id ="dg1"  width ="452" >
</ mx:DataGrid >
</ mx:VBox >
</ mx:Application >


其中有一处重要修改,即添加了onSelectDatabase()函数的代码,以获取表格列表,然后将其输入到onResult()函数中,还添加了onSelectTable()函数,该函数可检索表格中的数据,并在onResult()处理器中设置数据网格。
在浏览器中运行该例时,结果如图3所示。


图3. 运行“show tables”查询之后的结果

本例中使用了nasa数据库,这是我为NASA Ames演讲而创建的数据库(我用了“火箭科学”的笑话,因为当时我的听众是一群火箭科学家)。该数据库只有一个名为mission的表,其中包含两列,分别代表每项由NASA发起但已撤消的任务名称和年份。
在数据网格中单击名称列即可按名称排序,如图4所示。

图 4. 显示mission表中的数据

然后单击年份列,以按照年份排列数据,如图5所示。

图 5. 迪斯科球式查询

在过去几年中,我们似乎并未发起任何任务。
后续步骤
至此,本例已可应用于许多场合。在前台Flex应用中,可以添加一些对用户更友好的控件,以添加、删除或更新表格。甚至可以提供数据过滤功能或者编辑功能,以修改表格中的数据。数据网格控件非常强大,可以处理现场编辑任务。也可以用在完全不同的场合,例如使用Flex绘图软件包执行数据分析和可视化工作。

总结

PHP和Flex的结合潜力无限。利用PHP可以方便地在后台发布web服务,可以单独发布,可以与HTML前台程序一起发布。PHPMyAdmin带有web服务接口扩展功能,使任何人都能以Flex、Ajax、Silverlight、桌面小部件或其他任何技术编写前台程序。Flex为PHP开发人员提供了强大的前台工具。它避开了困扰Ajax开发人员的客户端不兼容问题。Flex 2并非只能使用特定的服务器技术,因此Flex应用程序编译完成后,它就可以部署在任何场合,因为它只是一个SWF文件。可以看到,利用简单的web服务对象和强大的E4X语言扩展,就可以让Flex应用程序方便地与几乎任何一种后台程序进行通讯。

读者不妨一试,如果您使用PHP和Flex创建了有趣的程序,请告诉我,也许我们可以合写一篇文章来介绍它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值