通过 CouchDB 在移动和固定设备上创建脱机 web 应用程序

移动应用程序的最大挑战之一是数据同步。此问题的有趣解决方案是使用 NoSQL 数据库 CouchDB。CouchDB(面向文档的数据库)可替代 SQL 数据库。通过 CouchDB 您可以在移动设备上使用云功能,脱机处理在本地数据存储上的本地部署应用程序,以及在再次上线时与其余的云一起共享数据。在本文中,通过创建并部署示例应用程序来了解 CouchDB 概念。

Dietmar Krueger, IT 架构师, IBM

http://www.ibm.com/developerworks/i/p-kdietmar.jpgDietmar Krueger 在 Application Innovation Services 工作,这是 IBM Global Business Services 的一条服务线。他已从事面向对象软件开发 17 年。Dietmar 对敏捷软件开发、轻量级架构和动态类型编程语言充满热情。



2011 年 12 月 12 日

介绍

基于分布式数据库的 SQL 同步机制,例如 HTML5 浏览器中嵌入的机制,会导致复杂的工作。Apache CouchDB 具有内在的同步基础。(要获得更多有关 CouchDB 同步的信息,请参考 参考资料。)在本文中,通过查看典型的使用方案来了解 CouchDB 概念和技术细节。您将创建并部署一个简单库存管理应用程序的原型。

虽然在我以前的 developerWorks 文章 “使用 HTML5 创建移动设备上的离线 Web 应用程序” 中介绍了基于 HTML5 概念的类似应用程序,但是并没有处理同步。在本文中,通过使用 CouchDB 环境的存储和标准同步工具,我迁移了应用程序。您可以从下面的 下载表 中下载本文中使用的源代码。

概述

图 1 显示了来自 使用 HTML5 创建移动设备上的离线 Web 应用程序 的 CouchDB 和 HTML5/SQL 解决方案的示例应用程序体系结构主要组件的概述。两个解决方案都包含 HTML、JavaScript、本地数据存储和远程数据存储。

图 1. 脱机 CouchDB 应用程序的核心元素
此图显示了脱机 CouchDB 应用程序的核心元素,显示了本地和远程元素。这些元素会在下面讲述。
HTML 页面
HTML5 和 CouchDB 应用程序的核心。它具有模型角色并包含已显示的数据和默认呈现信息。页面的 HTML 元素被组织在 HTML 文档对象模型(Document Object Model,DOM)树的层次结构中。

用户发起的事件会导致常规的请求-响应周期,具有页面加载并执行关联的 JavaScript 函数。值得注意的是,这些应用程序包括单一的 HTML 页面,无需通过请求-响应周期加载进一步的 HTML 页面。整个操作都是在一个页面上。

JavaScript
包含 HTML5 和 CouchDB 应用程序的控制器功能。通过针对 JavaScript 功能的事件处理程序绑定 HTML 元素。JavaScript 可访问包含所有用户界面元素的应用程序的 HTML DOM 树并使用它作为计算的数据输入。处理的结果可以通过修改 HTML 页面提供给用户。
本地数据存储
HTML5 应用程序的 SQL 数据库基于模式并使用联接来合并来自多个表的数据。CouchDB 应用程序的数据存储没有模式— 以 JSON 文档形式存储并检索文档。无需使用联接来汇集数据。

为管理数据,SQL 数据库使用 SQL 查询。CouchDB 具有 RESTful 方法:每一个文档都是一个具有用于请求的 HTTP 方法的 RESTful 资源。

远程数据存储
应用程序基础设施包括相互复制的数据存储节点的网络。在关系 SQL 数据库的世界中,需要编写或管理复杂的复制基础设施。

在 NoSQL CouchDB 体系结构中,提供了一个默认的复制框架。实际上执行冲突文档的合并是特定于应用程序的功能(请参考 参考资料)。这是 CouchDB 最强大的功能之一。

示例应用程序

此部分提供示例应用程序 MyHomeStuff 的概述,其提供简单库存管理以便跟踪您自己的物品。它的功能相当于 HTML5 版本。图 2 显示了 Windows® 上的 Firefox® 浏览器中的应用程序。

图 2. Windows 上的 Firefox 浏览器中的库存管理系统
库存管理系统的截屏,显示 Overview 部分、用于输入多个项目的 Details 以及 Replicate 部分。下面的文本具有更多信息。

Android™ web 浏览器上的应用程序显示如下。

图 3. Android 上的库存管理系统
库存管理系统的截屏,具有与上图相同的数据,但是位于较小的 Android 屏幕上。

该应用程序允许您跟踪自己的物品。屏幕上方的清单给出了所有已输入物品的概述,如书籍。通过在清单上选择物品,物品的详细信息(数量和名称)会显示在中间的表单上。通过使用 Update 按钮可变更已选物品的详细信息,或通过 Delete 按钮将已选物品从应用程序中删除。通过在表单上输入物品的数量和名称并选择 Create,可创建新的物品。

用户可启动屏幕下方的复制过程。该过程通过输入源和目标 CouchDB 的 URL 并激活 Replicate 按钮来操作。目标 CouchDB 可以是现有的远程或本地数据库。

HTML 详细信息

HTML 页面包含声明、外部 JavaScript 文件的引用以及形成应用程序基础结构的必要 HTML 元素。清单 1 显示了该代码。

清单 1. HTML 代码
<!DOCTYPE html>
<html>
  <head>
  	<title>MyHomeStuff2</title>
  	<script src="/_utils/script/jquery.js"></script>
  	<script src="/_utils/script/jquery.couch.js"></script>
  	<script src="script.js"></script>
  </head>
  <body>
  
    <h3>Overview</h3>
    <ul id="itemData" ></ul>

    <h3>Details</h3>
    <form name="itemForm">
        <input type="hidden" name="id" id="idId" />
        <input type="hidden" name="rev" id="revId"/>
        <label for="amount">Qty: </label>
        <input type="text" name="amount" id="amountId" size = 3/>
        <label for="name">Name: </label>
        <input type="text" name="name" id="nameId" size=12 />
        <br><br>
        <input type="button" id="createId" value="create" />
        <input type="button" id="updateId" value="update" />
        <input type="button" id="deleteId" value="delete" />
    </form>
   
    <h3>Replicate</h3>
    <form>
        <label for="sourceDBId">Source: </label>
        <input id="sourceDBId" type="text"></input>
        <br><br>
        <label for="targetDBId">Target: </label>
        <input id="targetDBId" type="text"></input>
        <br><br>
        <input id="replicateId" type="button" value="replicate"></input>
   </form>
   
  </body>
</html>

因为 jQuery 库用于 JavaScript 部分,HTML 页面不包含事件处理程序属性。从 JavaScript 代码绑定(单击)事件处理程序到 HTML 表单操作。

JavaScript 库 (jquery.couch.js)用于与 CouchDBs 进行交互。通过使用简单的 JavaScript,其简化了通信。例如,您使用 db.saveDoc(aTask),而不是为 RESTful CRUD 操作建立通信(例如,PUT /tutorial/task/4 ...)。

为了开发更先进的应用程序,您应该使用 CouchApp 框架。CouchApp 包括一组可以简化开发 CouchDB 应用程序的脚本(要获得更多信息,请参考 参考资料)。

JavaScript 详细信息

JavaScript 代码包括三个主要块:

  • 初始化函数
  • db (crud) 与视图刷新函数
  • 复制函数

第一个块包括数据存储和视图的初始化代码,如清单 2 所示。

清单 2. JavaScript refreshItems 代码
var db = $.couch.db(getCurrentDBName());

function getCurrentDBName() {
    return window.location.pathname.split("/")[1];
}

$(document).ready(function() {
    //1. init stuff
    refreshItems();
    $('#sourceDBId').val(db.name);
    $('#targetDBId').val(db.name + "-copy");
    
    //2. event handler crud stuff
    ...
});

function refreshItems() {
    $("ul#itemData").empty();
      
    db.view("myDesign/myView", {
        success: function(data){
            data.rows.map(function(row) {
            $('ul#itemData').append('<li id="'+row.value._id+'">'
                +row.value.amount
                +" x "
                +row.value.name
                +'</li>');
                     
            $('#'+row.value._id).click(function() {
                $('#idId').val(row.value._id);
                $('#revId').val(row.value._rev);
                $('#amountId').val(row.value.amount);
                $('#nameId').val(row.value.name);
                return false;
            });
            });
        },
        error: function(req, textStatus, errorThrown){alert('Error '+ textStatus);}
        });
}

在上面的代码中:

  • 创建 CouchDB 实例。从当前的 URL 中提取数据库名称。
  • 在初始化 DOM 以后调用文档 ready 函数。首先,其调用 refreshItems 函数并用源和目标数据库的名称填充复制表单的字段。
  • refreshItems 函数查询现有的记录并用该数据填充 HTML 页面,如下:
    • 从 DOM 树中删除旧数据。
    • 查询 CouchDB。查询并报告 CouchDB 的主要工具是视图。

      通过成功处理程序和错误处理程序函数执行查询。视图函数使用 HTTP GET 进行 RESTful 查询。视图包含映射函数,其将具有名称和金额字段的每个文档转换为键值对,其中 ID 为键,文档为值(请参考视图 myView 中映射函数的 部署 部分)。

    • 成功处理程序为每一个值创建一个 HTML 清单元素并将其添加到清单中。为每一个清单元素添加事件单击处理程序以便通过填充选择的字段对单击作出响应。
    • 错误处理程序通过警告对话框显示问题。

事件处理程序位于 refreshItems 函数的第二部分,其包含了按钮栏和更新、删除以及创建的清单。清单 3 显示了 update 的代码。(Createdelete 具有相似的结构,因此不在此处显示。您可以从下面的 下载表 中下载示例应用程序的所有源代码。)

清单 3. JavaScript update 代码
...
    //event handler crud stuff
...
    $('input#updateId').click(function(e) {
         
       if ($('#idId').val().length == 0) {
           return;
       }
       
       var aTask = {
           _id: $('#idId').val(),
           _rev: $('#revId').val(),
           amount: $('#amountId').val(),
           name:$('#nameId').val()
       }
       db.saveDoc(aTask, { success: function(resp) {
           refreshItems();
       }});
    });
...

在上面的代码中:

  • 读取并验证表单的字段值。
  • 如果值是有效的,则创建 JSON 对象且使用 HTTP PUT 执行更新调用来进行更新操作。
  • 在通过成功处理程序刷新的 HTML 页面中显示查询结果。

复制函数的代码非常密集,如清单 4 所示。

清单 4. JavaScript 复制代码
$('#replicateId').click(function() {
    var sourceDB = $('#sourceDBId').val();
    var targetDB = $('#targetDBId').val();
    $.couch.replicate(sourceDB, targetDB, {
        success: function(data){alert('Replication was performed');},
        error: function(req, textStatus, errorThrown){alert('Error '+ textStatus);}
    });
});

在上面的代码中:

  • 读取复制表单的字段值。
  • 执行复制调用。
  • 复制结果显示为警告框,通过成功或错误处理程序激活。

部署

如果您在计算机上安装了 CouchDB,您就可以运行示例。对于 Linux®、Windows、Mac® 和 Android(2.1 或更高;请注意在撰写本文时,Android 端口是 0.50 alpha 版)来说,CouchDB 具有不同的安装程序。此外,您可以使用托管服务。我成功地尝试了 CouchOne 的免费托管(请参考 参考资料)。

在安装 CouchDB 以后,容器就可以按一些步骤输入已下载的应用程序。

  1. 为应用程序和数据创建数据库。
    • 单击 Create Database ...
    • 在 Create New Database 对话框中,输入 Database Name 字段(例如 stuff_db)并单击 Create
  2. 使用数据(用于测试目的)创建文档。
    • 单击 New Document
    • 单击 Add Field
    • 在 Field 中输入 name 并在 Value 中输入 table

      通过绿色复选标记或 tab 键确认。

    • 单击 Add Field
    • 在 Field 中输入 amount 并在 Value 中输入 3。确认。
    • 单击 Save Document

      现在,第一个数据已经准备好进行查询。

  3. 创建一个视图并将其保存为设计文档。
    • 选择 Overview --> stuff_db
    • 选择 View: Temporary view... (从左上部的下拉清单)。
    • 输入映射函数:
      function(doc) {
        if (doc.name && doc.amount)
        {
          emit(doc._id, doc);
        }}

      对于数据库中包含具有非空值的名称和金额字段的每个文档来说,将在视图中创建一个结果行。行的键是文档的 ID;值就是文档本身。

    • 单击 Run 进行测试。结果是已输入文档的键值对。
    • 单击 Save As...
    • 在 Save View As... 对话框中,使用 _design/myDesign 填充 Design Document 字段,使用 myView 填充 View Name: 字段,单击 Save

      现在您拥有了存储 CouchDB 应用程序的设计文档。

  4. 查询视图。
    • 在浏览器中输入以下内容:
      http://127.0.0.1:5984/stuff_db/_design/myDesign/_view/myView
    • 它将显示输入的数据,如下所示:
      {"total_rows":1,"offset":0,"rows":[
      {"id":"c9938dc172b31a34ef4f0d7f3f000d5d",
      "key":"c9938dc172b31a34ef4f0d7f3f000d5d",
      "value":{"_id":"c9938dc172b31a34ef4f0d7f3f000d5d",
      "_rev":"3-d107f491d254b01c0135fd1e8dd13e0a",
      "table":null,"name":"table","amount":3}}
      ]}

      (由于格式原因,行被人为中断。)

  5. 使用
    http://127.0.0.1:5984/_utils/document.html?stuff_db/_design/myDesign

    打开新的设计文档并向设计文档上传附件(用于添加应用程序函数)。
    • 通过 Fileindex.html,选择 Upload Attachment,然后单击 Upload
    • 通过 Filescript.js,选择 Upload Attachment,然后单击 Upload
    • 单击 Save Document
  6. 通过选择来自具有
    http://127.0.0.1:5984/stuff_db/_design/myDesign/index.html

    的设计文档的 _attachments 字段的 index.html 值打开应用程序
  7. 在应用程序中输入并更改一些数据。

在成功安装应用程序以后,通过使用复制机制您可以将其部署到不同的 CouchDB 数据库。

  1. 为简化问题,请在相同的 CouchDB 节点上创建新的数据库(例如 new-stuff-db)。
  2. 输入现有 CouchDB 数据库的 URL。在 Source 字段输入源数据库的名称 (stuff_db),并在 Target 字段输入目标 URL (new-stuff-db)。
  3. 单击 replicate。将复制具有数据和程序代码的整个数据库。

    用相同的方法可以将新输入的数据简单地从复制传回到原始数据库。

  4. 尝试将 CouchDB 数据库复制到远程 CouchDB 节点。

    例如,如果您在 CouchOne 主机上注册子域 mysubdomain,并创建名为 mydatabase 的数据库,则您将使用的目标 URL 是:

    http://mysubdomain.couchone.com/mydatabase

总结

您在本文中了解了通过 CouchDB 创建脱机应用程序的技术观点。一个简单的库存管理应用程序的原型演示了使用 JSON 存储和标准同步工具的 CouchDB 技术。


下载

描述名字大小
本文源代码OfflineCouchDBAppSrc.zip3KB

参考资料

学习

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development
ArticleID=780636
ArticleTitle=通过 CouchDB 在移动和固定设备上创建脱机 web 应用程序
publish-date=12122011