0
回答
基于 CouchDB 的 RIA 程序设计与开发
注册华为云得mate10,2.9折抢先购!>>>   

本文首先介绍 CouchDB 这个面向文档的数据库系统,以及它的安装配置,并且介绍它提供的基于 REST API 的功能。其次会介绍如何将当前的 RIA 应用和它结合起来,会通过具体实例来介绍如何通过 Flex 技术和 CouchDB 结合使用。通过这篇文章让读者深入了解 CouchDB 以及如何使用它。

CouchDB 简介

CouchDB 是用 Erlang 开发的数据库系统,它不是传统的关系数据库,而是一个面向文档(Document)的数据库系统。它提供了基于 MapReduce 编程模型的视图来对文档进行查询和索引,这类似于关系数据库中 SQL 语句的功能;提供了 RESTFul JSON API,从而可以被任何允许 HTTP 请求的环境所访问,这样 CouchDB 应用可以通过浏览器中的 HTTP 请求直接与数据库交互。CouchDB 最大的意义在于它是一个面向 Web 应用的新一代存储系统。

CouchDB 是

一个文档数据库服务器,通过 RESTFul JSON API 访问;

模式(Schema)自由:并不要求文档具有某种特定的结构;

分布式的,性能稳健的,增量复制的,具有双向冲突检测和管理的;

能够查询和检索的。

CouchDB 不是

一个关系型数据库;

一个关系型数据库的替代;

一个面向对象的数据库,具体来说,基于面向对象语言的具有无缝持久层功能的数据库。

CouchDB 详解

CouchDB 特点

CouchDB 是分布式的数据库,可以把存储系统分布到多台物理的节点上,并很好地协调和同步节点之间的数据读写一致性,这得益于 Erlang 语言的并发性能。对于基于 Web 的大规模应用文档,它的分布式可以让它不必像传统的关系数据库那样分库拆表,在应用代码层进行大量的改动;

CouchDB 是面向文档的数据库,存储半结构化的数据,由于文档没有模式,很适合 CMS、电话本、地址本等应用,在这些场合,文档数据库要比关系型数据库更加方便,性能更优;

CouchDB 支持 RESTFul API,可以让用户使用 JavaScript 来操作 CouchDB 数据库,也可以 JavaScript 编写查询语句,进而于也可以和 Ajax 技术结合。

CouchDB 基本概念

文档(Documents)

一个 CouchDB 数据库的存储实际就是一系列文档的集合,这些文档没有层次结构,因此文档是 CouchDB 的核心,也是 CouchDB 的基本数据存储单元,在 CouchDB 中文档以 JSON 对象的形式保存。每个文档是一系列数据项的集合,每个数据项是一个个键值对,其中值可以是字符串、数字、日期甚至可以是序列表和关联映射,一个样例文档可 以如下表示:

"Subject": "I like Plankton"  
"Author": "Rusty"  
  "PostedDate": "5/23/2006"  
"Tags": ["plankton", "baseball", "decisions"] 
"Body": "I decided today that I don't like baseball. I like plankton."

每个文档都有自己的全局唯一的标识符和版本修订号。ID 用来标识一个文档,而修订版本号用来实现多版本并发控制。

视图(Views)

为了解决向半结构化数据中加入结构化数据的问题,CouchDB 引入了用 JavaScript 描述的视图模型。视图是 CouchDB 中文档的表现方式,是操作文档方法的集合,如过滤、组织、聚合等。视图是动态建立的,并不影响底层的文档,对于同样的文档数据你可以拥有不同的表现视图。

模式自由(Schema free)

不像用来存储高结构化,互相关联数据的关系数据库,CouchDB 被设计用来存储半结构化,基于文档的数据,CouchDB 很大程度上简化了基于文档应用程序的开发。

在关系数据库中,如果数据库原始的设计不能满足新的需求,必须重新进行设计。在 CouchDB 中,模式自由,新的文档类型可以安全地添加到旧文档类型中,视图这时候就可以用来简单地处理新文档类型。

CouchDB RESTFul API

CouchDB 提供 RESTFul API 来使用 CouchDB 的功能,并对数据库进行操作。

数据库 API

  • GET /_all_dbs 返回这个服务器上所有数据库的一个列表,列表以 JSON 数组的形式表示;
  • GET /dbname 返回名为 dbname 的数据库具体信息,信息以 JSON 对象表示;
  • PUT /dbname 创建名为 dbname 的数据库,创建成功则返回 201 的 HTTP 状态码,否则返回 412 的 HTTP 状态码;
  • DELETE /dbname 删除名为 dbname 的数据库,如果删除成功,返回 200 的 HTTP 状态码,否则返回 404 的 HTTP 状态码;

文档 API

  • GET /dbname/doc_id 返回数据库 dbname 中 ID 为 doc_id 的文档内容,文档内容以 JSON 对象形式表示;
  • PUT /dbname/doc_id 在数据库 dbname 中创建 ID 为 doc_id 的文档,如果 doc_id 已存在,则会更新已有的文档,这种情况下 PUT 请求内容的文档中需要包含 _rev 字段,表示文档的修订版本号。CouchDB 使用该字段做更新时的冲突检测。更新完成后,返回 201 的 HTTP 状态码,表示更新成功,若返回 409 的 HTTP 状态码,表示有版本冲突;
  • DELETE /dbname/doc_id 在数据库 dbname 中删除 ID 为 doc_id 的文档。

CouchDB 功能优点

CouchDB 不仅是一个数据库服务器(上面的介绍我们都是在描述它作为数据库的特性),同时也是一个应用服务器(下面的示例将用到它作为应用服务器的特性)。 CouchDB 的 RESTFul API 使用 JSON 作为展现形式,CouchDB 的应用只需要编写浏览器端的代码就可以使用 JavaScript 与应用服务器进行交互,而 CouchDB 具有的附件功能可以保存基于浏览器的 HTML、JavaScript 和 CSS 代码。这样 CouchDB 不但保存了 Web 应用所需要的数据,也保存了 Web 应用的逻辑,因此只需要这个既可以做数据服务器又可以做应用服务器的 CouchDB 就可以构建完整的 Web 应用开发运行环境。

系统处理流程


图 1. 使用 CouchDB 系统处理流程
图 1. 使用 CouchDB 系统处理流程

CouchDB 开发环境安装配置

  1. 操作系统:Ubuntu 10.0.4
  2. 需要的项目:CouchDB、CouchApp
  3. 安装 CouchDB:

清单 1.CouchDB 安装步骤
				 
 sudo su 
 # 安装 CouchDB 需要的依赖包
 apt-get build-dep couchdb 
 cd /opt 

# 从http://couchdb.apache.org/downloads.html下载最新的 CouchDB 包。

 # wget <url> 
 tar xvzf apache-couchdb-x.xx.x.tar.gz 
  cd apache-couchdb-x.xx.x 

 ./configure --prefix= --with-js-lib=/usr/lib/xulrunner-devel-x.x.x.x/lib 
      --with-js-include=/usr/lib/xulrunner-devel-x.x.x.x/include 

 # 测试安装
 make check 

 # 编译并安装 CouchDB 
 make && make install 
 # 修改 /etc/passwd,将 home directory 该为 /usr/local/var/lib/couchdb/, couchdb 的用户在编译和
 # 安装时已被添加

 # 将文件的所有权从 root 改为 couchdb 用户,并且改变权限
 chown -R couchdb: /usr/local/var/{lib,log,run}/couchdb /usr/local/etc/couchdb 
 chmod 0770 /usr/local/var/{lib,log,run}/couchdb/ 
 chmod 664 /usr/local/etc/couchdb/*.ini 
  chmod 775 /usr/local/etc/couchdb/*.d 

 # 启动 couchdb 
 cd /etc/init.d 
 ln -s /usr/local/etc/init.d/couchdb couchdb 
 /etc/init.d/couchdb start 
 # 在系统启动时启动 couchdb 
 update-rc.d couchdb defaults 

 # 在 firefox 中输入 http://127.0.0.1:5984/ 检查 couchdb 是否可以运行,显示结果如下:
 # {"couchdb":"Welcome","version":"1.0.1"} 
			

安装 CouchApp


清单 2 CouchApp 安装步骤
				 
 #CouchApp 需要 Python 2.5x 或者更高版本
 curl -O http://python-distribute.org/distribute_setup.py 
 sudo python distribute_setup.py 
 easy_install pip 

 # 安装或更新 CouchApp 最新版本
 pip install couchapp 

CouchDB 部署

CouchDB 的应用程序可以通过 CouchApp 部署。CouchApp 有两条基本的命令,分别是 generate 和 push。Generate 用于创建一个应用,所创建的应用有完善的目录结构,下面的示例使用这个目录结构;push 用于将文件系统保存到 CouchDB 的设计文档中。如下面的示例创建一个名为 couchdbtest 的应用,并将它的内容保存到名为 apple 的 CouchDB 数据库上。

  1. 生成样例应用 couchdbtest

    命令:couchapp generate couchdbtest



    图 2. 生成应用的目录结构
    图 2. 生成应用的目录结构

  2. 部署应用 couchdbtest 到 CouchDB Server apple 上

    命令:couchapp push apple



    图 3. 应用部署成功的状态
    图 3. 应用部署成功的状态

    之后可以通过在浏览器中输入以下网址访问刚创建的应用:

    http://127.0.0.1:5984/apple/_design/couchdbtest/index.html

一个入门的例子 Flex 应用和 CouchDB 结合

Flex 作为一款强大的矢量动画编辑工具,它涵盖了支持 RIA(Rich Internet Applications) 的开发和部署的一系列技术组合,并且在 RIA 富客户端应用中占据霸主地位。它推出了面向对象的编程脚本 ActionScript 3.0,并且建立起类似于 Java Swing 的类库和相应 compoment。Flex 通过 Java 或 .NET 等非 Flash 途径,解释 .mxml 文件组织 compoments,并生成相应的 .swf 文件。

Flex 较之 Flash 更适合开发者,Flash 天生是为 designer 设计的,而 Flex 用非常简单的 .mxml 来描述界面,跟 jsp/asp/php 程序人员使用的 .(x/d)html 非常相似,而且 mxml 更加规范化、标准化;Flex 的目标是让程序人员更快更简单地开发 RIA 应用。在多层开发模型中,Flex 应用属于表现层。

前面我们讲解了 CouchDB 的特点,基本概念和安装部署,在这个应用中选择 Flex 作为表现层来展开我们的示例程序,以进一步理解 CouchDB 应用的开发过程。

新建 Flex Project


图 4. 新建项目
图 4. 新建项目

图 5. 目录结构
图 5. 目录结构

修改 Sample.mxml 文件

Sample 将 CouchDB 的 service 以 HTTPService 的方式暴露,通过 GET 方法调用 API /apple/2rb128 以获得 apple 数据库中 id 为 2rb128 的文档内容。

程序以 Button 触发索引数据库事件,将从数据库中取得的数据显示在 DataGrid 中。DataGrid 中有两个 column:key 和 value,分别对应于从数据库中得到数据的键和值。在处理触发事件中,主要完成对 JSON 对象的解析:将字符串形式的 JSON 对象转换成类似于 Map 的键值对形式,然后将这个类 Map 的 ArrayCollection 绑定到 DataGrid 中,则 ArrayCollection 的动态变化能够实时映射到 DataGrid 的视图显示中。


清单 3.Sample.mxml
				 
 <?xml version="1.0" encoding="utf-8"?> 
 <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> 
	 <mx:Script> 
		 <![CDATA[ 
  import  mx.collections.ArrayCollection; 
    import  mx.rpc.events.ResultEvent; 
    [  Bindable  ] 
    
 /* 变量 dataArr 作为组件 dataGrid 的 dataProvider,存放包含键值对的对象
     * 变量 text 用来保存 request 返回的文本形式
     * 变量 itemStr 则 dataArr 中对象的 String 形式
     * 将 text 文本分割为一个个 String 对象保存入 itemStr 中,然后将 itemStr 中的对象
     * 一个个封装成键值对对象
    */ 
  public var  dataArr:ArrayCollection =  new  ArrayCollection(); 
  public var  text:String; 
  public var  itemStr:ArrayCollection =  new  ArrayCollection(); 
			
			
    //getDBInfo 作为 button 点击的事件处理函数,用于发送 HTTP 请求
  private function  getDBInfo():  void 
			 { 
    getdbp.cancel(); 
    getdbp.send(); 
			 } 
			
    /*resultHandler 作为对 HTTP 请求返回结果的处理函数,完成 JSON 对象在 dataGrid 中的
 * 显示
    */ 
  private function  resultHandler(event:ResultEvent):  void 
			 { 
    dataArr.removeAll(); 
             /* 将请求返回的结果分割为一个个以键值对为内容的单位,存储于集合 itemStr 
 * 中
             */ 
    text = event.result.toString(); 
  var  beginIndex:int = text.indexOf(  "{"  ); 
  var  endIndex:int = text.indexOf(  "}"  ); 
  var  textCharStr:String = text.substring(beginIndex+1, endIndex); 
  var  count:int = 0; 
  for  (  var  i:int =0;i<textCharStr.length;i++) 
    { 
  if  (textCharStr.charAt(i)==  ","  ) 
	    { 
		    count++; 
	    } 
    } 
  var  index:int = 0; 
  var  startFlag:int = -1; 
  var  endFlag:int = 0; 
  var  icount:int = 0; 
  while  (index < textCharStr.length) 
    { 

  if  (textCharStr.charAt(index)==  ","  ) 
	    { 
		    icount++; 
		    endFlag = index; 
  var  tmp:String = textCharStr.substring(startFlag+1, endFlag); 
		    itemStr.addItemAt(tmp,icount-1); 
		    startFlag = endFlag; 
	    } 
					
  if  (index == textCharStr.length-1) 
	    { 
		    endFlag = textCharStr.length; 
  var  temp:String = textCharStr.substring(startFlag + 1, endFlag); 
		    itemStr.addItemAt(temp,icount); 
	    } 
	    index++; 
    } 				
				
  /* 将存储于 itemStr 中的一个个元素转变为存储键和值对象,存储于集合 
 *dataArr 中
             */ 
  for  (  var  i:int = 0;i<count+1;i++) 
    { 
  var  tmpStr:String = String(itemStr.getItemAt(i)); 
  var  flag:int = tmpStr.indexOf(  ":"  ); 
  var  key:String = tmpStr.substring(0,flag); 
  var  value:String = tmpStr.substring(flag+1,tmpStr.length); 
  if  (key.indexOf(  "\""  )!=-1&&key.lastIndexOf(  "\""  )!=-1) 
	    { 
  key = key.substring(key.indexOf(  "\""  )+1,key.lastIndexOf(  "\""  )); 
	    } 
  if  (value.indexOf(  "\""  )!=-1&&value.lastIndexOf(  "\""  )!=-1) 
	    { 
  value = value.substring(value.indexOf(  "\""  )+1,value.lastIndexOf(  "\""  )); 
	    } 
  var  pare:Object = {key:key, value:value}; 
	    dataArr.addItem(pare); 
    } 
				
			 } 
		 ]]> 
	 </mx:Script> 
	
         <! — Flex 使用 <mx:HTTPService> 标签发送 POST 和 GET 请求外部数据 --> 
		 <mx:HTTPService id="getdbp" method="GET"
		 url="/apple/2rb128"
		 result="resultHandler(event)"
		 /> 
		
		
	 <mx:VBox > 
	 <mx:Button label="GetDBInformation" click="getDBInfo()"/> 
     <mx:DataGrid id="dataGrid" dataProvider="{dataArr}" height="260" width="200" > 
			 <mx:columns> 
    <mx:DataGridColumn headerText="key" dataField="key" /> 
    <mx:DataGridColumn headerText="value" dataField="value" /> 
			 </mx:columns> 
		 </mx:DataGrid> 
	 </mx:VBox> 
	
 </mx:Application> 

以 Flex Application 的方式运行 Sample.mxml

CouchDBSample 工程的 bin-debug 目录下生成 Sample.html, Sample.swf 等文件,将这些文件拷贝到项目 couchdbtest 的 _attachments 目录下


图 6. 待部署文件
图 6. 待部署文件

将 couchdbtest 的内容再次部署到 CouchDB Server apple 中

命令:couchapp push apple

在浏览器中访问地址:http://127.0.0.1:5984/apple/_design/couchdbtest/index.html


图 7. 访问界面
图 7. 访问界面

点击按钮 GetDBInformation 将获得 apple 数据库中名为 2rb128 的文档中内容:


图 8.DB 中信息显示
图 8.DB 中信息显示

结束语

本文对 CouchDB 的特点,安装部署,以及基于 FLEX 的简单应用做了一个详细的介绍,要做大规模应用级别的开发还需要深入研究,相信通过本文的介绍,可以帮助你快速的基于这种全新的数据库进行 WEB 开发。

代码下载: IBM developerWorks


举报
IBMdW
发帖于7年前 0回/561阅
顶部