提供离线数据编辑和数据同步 您所在的位置:网站首页 离线数据同步三部分 提供离线数据编辑和数据同步

提供离线数据编辑和数据同步

2023-11-14 01:10| 来源: 网络整理| 查看: 265

HTML版本5(HTML5)有望在2014年之前达到万维网联盟(W3C)的推荐状态。尽管它不是正式的标准,但网络浏览器供应商正在添加和营销HTML5功能。 HTML5已经在重塑Internet网站和业务线(LOB)应用程序的Web体验。 许多网站,例如Amazon Kindle Cloud Reader,已经在利用HTML5。 HTML5的两个关键功能将极大地改变LOB应用程序:脱机应用程序支持和本地持久存储。 由于HTML5不是官方标准,因此浏览器支持最多是不一致的。

在本文中,了解脱机应用程序支持以及建议HTML5标准提供的各种持久存储功能。 一个示例应用程序有助于说明这些功能。

应用范例

Contact Manager应用程序示例提供了联系人信息(姓名,地址和电话号码)的管理。 它提供了联机模式,脱机模式和简单的数据同步功能,以在切换到联机模式时将本地数据更改同步到服务器。 脱机时,数据驻留在本地持久存储中。 该应用程序在联机和脱机模式下均支持四种基本的持久存储功能-创建,读取,更新和删除(CRUD)。

建筑

图1显示了Contact Manager应用程序体系结构的概述。 服务器体系结构由两个servlet组成:业务服务和数据提供程序。 用户界面(UI)包含一个HTML文件,四个JavaScript模块以及对jQuery库最新版本的外部引用。

图1.应用程序架构概述 该图显示了应用程序架构 数据模型

数据模型由两个数据实体(联系和状态)组成, 如图2所示。 联系人表包含实际联系人数据; 状态表包含状态选择列表的字典值。

图2.数据模型 该图显示了数据模型 服务器界面

服务器接口由两个servlet组成: ContactServlet和DictionaryServlet 。 表1总结了这些servlet。 (servlet的实现以及相应的业务服务和数据提供程序不在本文讨论范围之内。)

表1. servlet的摘要 Servlet名称 操作方式 参量 描述 DictionaryServlet代码> getstates 不适用 以JavaScript对象符号(JSON)格式返回状态数组。 ContactServlet getallcontacts 不适用 返回JSON格式的联系人记录数组。 ContactServlet delete contactId要删除的联系人的ID。 删除指定的联系人记录; 返回带有布尔值标志的JSON对象,以指示操作是否成功。 "{"result": true/false"} ContactServlet save contactId要保存的联系人的ID。 (如果大于零,则是更新操作。) firstName名字字段的值。 lastName姓氏字段的值。 street1街道1字段的值。 street2街道2字段的值。 city -城市字段值。 state -该状态字段值。 zipCode邮政编码字段的值。 返回带有布尔值标志的JSON对象,以指示操作是否成功以及新的或更新的联系人ID。 "{"contactId": , "result": "} 调用服务器界面

清单1中的代码显示了如何对联系人servlet进行异步调用以检索存储在在线数据库中的联系人。 该代码使用jQuery getJSON函数来调用联系人servlet。

清单1.从服务器检索联系人 function loadOnlineContacts() { $('#contactList').empty(); $('#contactList').append('Loading contact data...'); var url = '/html5app/contact?operation=getallcontacts'; $.getJSON(url, function(data) { saveOfflineContactData(data); displayContactData(data); }); }

清单2中的代码显示了如何将新的或更新的联系人保存到服务器。 它使用jQuery ajax函数。 该代码使用HTTP POST将数据发送到联系人servlet。

清单2.将联系人保存到服务器 function postEditedContact(dataString) { postEditedContact(dataString, false); } function postEditedContact(dataString, suppressAlert) { var contactId = $('input[name="contactId"]')[0].value; $.ajax({ type: "POST", url: "/html5app/contact", data: dataString, cache: false, dataType: "json", success: function(data) { var result = data.result; if (result) { if (contactId > 0) { if (!suppressAlert) { alert("Contact was successfully updated."); } var lastModifyDate = data.lastModifyDate; $('input[name="lastModifyDate"]')[0].value = lastModifyDate; } else { if (!suppressAlert) { alert("Contact was successfully created."); } var lastModifyDate = data.lastModifyDate; $('input[name="lastModifyDate"]')[0].value = lastModifyDate; $('input[name="contactId"]')[0].value = data.contactId; } loadOnlineContacts(); hideEditForm(); } else { alert('An error occurred saving contact ' + contactId + '.'); } } }); }

最后一个功能是从在线数据库中删除一条记录。 清单3显示了如何从服务器删除记录。 该代码使用jQuery getJSON函数来调用联系人servlet。

清单3.删除服务器上的联系人 function deleteOnlineContact(contactId, suppressAlert){ var url = '/html5app/contact?operation=delete&contactId=' + contactId; $.getJSON(url, function(data) { var result = data.result; if (result) { if (!suppressAlert) { alert('Contact deleted'); } loadOnlineContacts(); } else { alert('Contact ' + contactId + 'not deleted'); } }); } 建立本地数据提供者

本地数据提供者在本地保留所有选择列表和联系数据。 HTML5规范包含一些用于持久存储的选项。 选择使用哪种技术取决于您的数据存储和浏览器支持要求。 以下各节讨论了三种持久性存储技术以及使用所有主要Web浏览器支持的持久性存储技术的本地数据提供程序的实现。

HTML5与以下三种持久存储技术相关:

localStorage -localStorage使用平面键值存储提供了简单的数据存储。 所有主要的Web浏览器,包括Apple®Safari®,Google Chrome™,Microsoft®Windows®InternetExplorer®,Mozilla®Firefox®和Opera™,都支持localStorage。 HTML5 localStorage是同步的,并且是当前唯一支持跨平台和跨浏览器的数据库存储机制。 WebSQL -WebSQL最初旨在将基于Transact-SQL的数据库引入Web浏览器。 基于与通用关系数据库(例如IBM®DB2®,Microsoft SQLServer®,Oracle®MySQL®Server和Oracle Database)的相似性,学习曲线很低。 某些浏览器(包括Safari,Chrome和Opera)都支持WebSQL。 Firefox或Internet Explorer不支持它。 据推测,由于不再开发WebSQL建议的规范,因此它将被淘汰。 索引数据库(Indexed DB) -索引数据库是一个索引层次结构键值存储,类似于许多商业云数据存储产品。 WebSQL不再支持索引数据库,而Firefox,Chrome和将来的Internet Explorer 10当前都支持索引数据库。索引数据库的应用程序编程接口(API)是异步的,并支持索引,查询和事务。 。

本文中的示例解决方案将JSON和localStorage用于持久存储,这主要是因为广泛的浏览器支持localStorage。

本地数据提供商

localStorage方法通过将联系人和字典数据序列化为JSON字符串并将其保存到localStorage来保留联系人和字典数据。 检索数据时,将其反序列化为JSON对象数组并进行相应处理。

本地保存数据

清单4显示了如何将联系人数据保存到localStorage。 JavaScript函数JSON.stringify用于序列化服务器返回到字符串的JSON数据,以便可以将其存储在localStorage中。

清单4.将数据保存到localStorage // fetch data from server ... // convert JSON data to a string var contactDataString = JSON.stringify(data); // persist contact data to localstorage localStorage.setItem("contactData", contactDataString); 本地检索数据

清单5显示了如何从localStorage检索数据。 第一步是从localStorage获取JSON字符串。 然后使用JavaScript函数eval将字符串转换为JSON对象,该函数将字符串反序列化为JSON对象数组。 使用自定义JavaScript函数displayContactData显示数据。

清单5.从localStorage读取数据 function loadOfflineContacts() { $('#contactList').empty(); $('#contactList').append('Loading contact data...'); var dataStr = localStorage.getItem("contactData"); var data = eval('(' + dataStr + ')'); displayContactData(data); } 在本地删除记录

清单6显示了如何从localStorage删除记录。

清单6.从localStorage删除一条记录 function deleteOfflineContact(contactId) { var dataStr = localStorage.getItem("contactData"); var data = eval('(' + dataStr + ')'); var recordUpdated = false; $.each(data, function(i,item){ if (item.id == contactId) { item.isDeleted=true; recordUpdated = true; return false; } }); if (recordUpdated) { dataStr = JSON.stringify(data); localStorage.setItem("contactData", dataStr); alert("Contact was successfully deleted."); loadOfflineContacts(); } }

代码:

从本地存储读取数据库并反序列化。 遍历记录,直到找到contactId记录。 将isDeleted标志设置为true 。 在数据同步功能中使用isDeleted标志。 (请参阅“ 数据同步 ”部分。) 将数据持久保存到localStorage,并刷新数据网格。 本地更新和创建记录

清单7显示了如何在localStorage中更新或创建记录。

清单7.更新localStorage中的一条记录 function updateLocalContact() { var dataStr = localStorage.getItem("contactData"); var data = eval('(' + dataStr + ')'); var contactId = $('input[name="contactId"]')[0].value; var recordUpdated = false; if (contactId > 0) { $.each(data, function(i,item){ if (item.id == contactId) { item.isDirty=true; item.firstName = $('input[name="firstName"]')[0].value; item.lastName = $('input[name="lastName"]')[0].value; item.street1 = $('input[name="street1"]')[0].value; item.street2 = $('input[name="street2"]')[0].value; item.city = $('input[name="city"]')[0].value; item.state = $('select[name="state"]')[0].value; item.zipCode = $('input[name="zipCode"]')[0].value; recordUpdated = true; return false; } }); } else { var newContactId = 0; var nextId = 0; while(newContactId == 0) { var found = false; nextId = nextId - 1; $.each(data, function(i,item){ if (item.id == nextId) { found = true; return false; } }); if (!found) { newContactId = nextId; } } var lastModifyDate = ""; var newContact = {"street2": $('input[name="street2"]')[0].value, "id":newContactId, "street1":$('input[name="street1"]')[0].value, "lastName":$('input[name="lastName"]')[0].value, "isDirty":true, "zipCode":$('input[name="zipCode"]')[0].value, "state":$('select[name="state"]')[0].value, "lastModifyDate": lastModifyDate, "isDeleted":false, "firstName":$('input[name="firstName"]')[0].value, "city":$('input[name="city"]')[0].value}; var nextIndex = data.length; data[nextIndex] = newContact; recordUpdated=true; } if (recordUpdated) { dataStr = JSON.stringify(data); localStorage.setItem("contactData", dataStr); alert("Contact was successfully updated."); } hideEditForm(); }

如清单7所示,您:

从localStorage读取数据库并反序列化。 如果要保存的记录的contactId不为零(发生更新),则遍历记录直到找到contactId记录。 然后相应地进行更新。 或者,如果记录是新记录( contactId不为零),则查找下一个未使用的负contactId 。 将其分配给新记录。 将新记录追加到数据库。

然后将数据序列化为JSON字符串并保存到localStorage。 服务器同步期间将分配一个有效的(大于零) contactId 。 否定ID是用于将记录标识为新记录的临时ID。

重要的是要知道localStorage:

限制为5MB。 (当需要更多数据存储时,应使用索引DB。) 所有主要的网络浏览器都支持。 仅适用于字符串值。

下一步是使用HTML5构建UI。

使用HTML5构建UI

该示例Contact Manager应用程序具有一个只有一个页面的简单UI。 它支持编辑和删除每个记录,并提供创建新记录的功能。 级联样式表(CSS)和动态HTML(通过jQuery)用于根据需要隐藏和显示创建/编辑子表单。

为了提供一致的用户体验,无论是联机还是脱机都使用同一页面; 唯一的区别是执行操作时将调用哪个数据提供程序。 图3显示了该应用程序。

图3. Contact Manager应用程序 该图显示了Contact Manager应用程序 JavaScript模块

该应用程序包含四个自定义JavaScript模块:

core.js提供了常见JavaScript函数,并由其他模块使用。 formEvents.js提供了表单和按钮事件处理程序。 它根据联机或脱机状态将数据库操作分派给正确的数据提供者。 onlinedb.js提供了在线时与服务器通信的功能。 offlinedb.js提供本地数据存储功能。

所有模块还使用最新版本的jQuery库来遍历数据,发出异步Web请求和动态HTML。 客户端使用JSON与服务器通信。

离线应用程序清单

HTML5脱机功能提供了对静态文件和资源的缓存。 脱机应用程序清单文件(.appcache)是用于为Web应用程序启用脱机应用程序支持的关键文件。 清单文件定义以下信息:

离线时哪些资源和页面可用。 哪些资源仅在线可用。 显示后备页面以显示离线时不可用的资源。

清单文件由三部分组成: CACHE , NETWORK和FALLBACK 。 CACHE下的页面和资源在本地缓存。 NETWORK下的页面和资源从不缓存,仅在联机时可用。 如果请求的页面脱机不可用,则显示FALLBACK指定的页面。 NETWORK部分中的星号( * )确保所有其他页面和servlet仅在联机时可用。 如果缺少* ,则servlet调用将失败(甚至在线)。 清单8显示了Contact Manager的清单文件。

清单8.离线应用程序清单 CACHE MANIFEST # Revision 1 CACHE: default.html list.html scripts/core.js scripts/localdb.js scripts/onlinedb.js scripts/formEvents.js http://code.jquery.com/jquery-1.7.2.min.js NETWORK: * FALLBACK: / offline.html

使用脱机应用程序时,重要的是要了解:

脱机应用程序清单文件扩展名.appcache必须映射到text/cache-manifest多用途Internet邮件扩展名(MIME)类型。 在Apache Tomcat中,通过将mime-mapping条目添加到服务器的 web.xml文件(而不是Web应用程序的web.xml文件)中来执行此操作。 如果MIME类型不正确,大多数浏览器会默默地忽略脱机应用程序清单。 如果存在脱机应用程序清单文件,则始终使用本地缓存的资源(即使在线)。 仅当脱机应用程序清单文件发生更改时才更新本地资源,通常是通过更改清单文件中的注释中的修订号来进行的。 在更改应用程序清单文件之前,对HTML或CSS资源的更改不会反映在Web浏览器中。 支持离线使用的任何页面都必须具有以下内容: 在线或离线

使用JavaScript,您可以使用navigator.onLine布尔值检测应用程序是在线还是离线。 如果应用程序在线,则返回True。

表单事件(在线/离线处理)

在联系人管理器中,联机或脱机使用相同的表单。 使该解决方案起作用的关键在于按钮和表单事件处理程序。 检查navigator.onLine以确定要调用的操作(本地或联机)。 清单9显示了一个联系人数据加载示例。

清单9.加载数据(在HTML BODY的onLoad事件中) if (navigator.onLine) { // selection list needs to be populated prior to synchronizing data // the list is updated from the online dictionary later populateOfflineStates(); setStatusText("Synchronizing contact data with server..."); synchronizeContacts(); setStatusText("Loading dictionary data from server..."); populateOnlineStates(); setStatusText("Loading contact data from server..."); loadOnlineContacts(); } else { alert('You are currently offline.'); populateOfflineStates(); setStatusText("Loading contact data from local storage..."); loadOfflineContacts(); } 数据同步

在线时,所有CRUD操作都将servlet用于创建,修改和删除操作。 联机数据库更改时,本地缓存也会更新。

脱机时,所有CRUD操作都使用本地数据提供程序来保留更改。 与服务器重新连接后:

本地创建的所有记录都将保留到服务器。 在本地修改的所有记录都会在服务器上更新。 在本地删除的所有记录都将在服务器上删除。

清单10显示了完整的同步方法。 在同步期间,相同的联机功能用于创建,更新和删除操作。 第一步是使用jQuery $.each函数遍历本地记录。

使用isDirty属性标记在本地更新或创建的isDirty 。 如果保存操作的唯一记录ID为负(即未由MySQL数据库分配),则将其标识为新操作。 使用isDeleted属性标记在本地删除的记录。

清单10.将离线更改同步到服务器 var recordsUpdated = 0; var recordsCreated = 0; var recordsDeleted = 0; $.each(data, function(i,item){ if (item.isDeleted) { deleteOnlineContact(item.id, true); recordsDeleted++; } else if (item.isDirty && !item.isDeleted) { $('input[name="contactId"]')[0].value = item.id; $('input[name="firstName"]')[0].value = item.firstName; $('input[name="lastName"]')[0].value = item.lastName; $('input[name="street1"]')[0].value = item.street1; $('input[name="street2"]')[0].value = item.street2; $('input[name="city"]')[0].value = item.city; $('select[name="state"]')[0].value = item.state; $('input[name="zipCode"]')[0].value = item.zipCode; var dataString = $("#editContactForm").serialize(); postEditedContact(dataString, true); if (item.id > 0) { recordsUpdated++; } else { recordsCreated++; } } }); var msg = "Synchronization Summary\n\tRecords Updated: " + recordsUpdated + "\n\tRecords Created: " + recordsCreated +"\n\tRecords Deleted: " + recordsDeleted; alert(msg);

使用getcontacts操作从数据库中获取最新数据并显示出来。 其他用户所做的任何更改都会反映出来。 然后,数据将在本地保留,以确保离线时可用。

结论

在本文中,示例应用程序展示了一种在线和离线支持的良好模式。 通过将单个HTML页面用于联机和脱机模式,并基于联机/脱机状态调用表单事件处理程序中的相应联机/脱机数据提供程序,从而维护了一致的用户体验。

数据同步算法提供了良好的基础; 它处理同步记录的脱机创建,删除和修改。 但是,它不是可用于生产的代码。 例如,当同一条记录在本地由另一个用户在服务器上修改时,它不会处理冲突。

翻译自: https://www.ibm.com/developerworks/web/library/wa-html5db/index.html



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有