Html5离线存储和数据同步
来源:互联网 发布:淘宝店铺客服登录 编辑:程序博客网 时间:2024/06/10 19:14
一、整体流程设计
流程细节如下:
(1)WebSQL用于存储本地数据。
(2)LocalStroage用于暂存需要同步数据。
(3)XML用于存储所有操作过程和数操作据。
(4)将localStroage的数据同步服务器(数据冲突手动操作)。
(5)通过XML将服务器数据同步本地。
(6)本地没有数据直接同步服务器。
(7)服务器没有数据直接同步本地。
二、数据结构设计
WebSQL:数据库表。格式:items(id,name,num,user)
localStroage:Json数组对象。格式:
[ {id:(new Date()).getTime(),table:'items',op:"insert",name:' ',num:' ',user:' '},
{id:(new Date()).getTime(),table:'items',op:"update",name:' ',num:' ',user:' '},
{id:(new Date()).getTime(),table:'items',op:"delete",name:' ',num:' ',user:' '}} ……]
其中,josns[0]代表同步数据的起点,josns[josns.length-1]代表数据同步的终点
XML:
<store dtatbase="Item">
<op id="0"/>
<op id="1366526718040" table="items" action="insert">
<data name="name">测试2 </data>
<data name="user"> </data>
<data name="num"> 测试2</data>
<data name="spell">T</data>
</op>
<op id="1366526728408" table="items" action="update">
<data name="name">测试3</data>
</op>
</store>
三、同步顺序图
分析说明:
(1)LastSynTime:标识用户使用情况
-1:表示用户在该浏览器中第一次使用。然后获取服务器是否有该用户信息,如果有则直接将服务器的数据更新到本地数据库。
不等于-1:表示用户已经操作过该浏览器。然后对syndata进行判断。
(2)syndata:表示需要同步的数据
-1:表示用户当前在该浏览器中没有同步数据。然后获取服务器是否有该用户信息,如果有则直接将服务器的数据更新到本地数据库。
不等于-1:表示用户在该浏览器中有同步数据。然后在进一步判断。
(3)id_start::为syndata[0].id,表示需要同步数据中第一个数据的操作时间戳。
id_end:为syndata[syndata.length-1],表示需要同步数据中最后一个数据的操作时间戳。
ID_END:为XML中最后一个操作数据的时间戳。
(1)若ID_End<id_start,,则将本地同步数据更新服务器数据库。
(2)若ID_End>id_end,则提取上一次同步操作数的最后一个操作时间戳id_end,从服务器获取id_end到ID_End的数据操作并更新到浏览器的webBD数据库。
(3)若id_start<ID_END<id_end,则id_start到ID_END为冲突数据需要用户手工矫正,并将ID_END到id_end更新服务器。
四、系统结构
五、用户界面
六、代码设计
1、服务端
1)、XML解析(dom4j)
(1)、获取XM存储的最后一个操作数据的时间戳(ID_END)
Element opElement = (Element) document.selectSingleNode("/store/op[last()]");
return opElement.attributeValue("id");
(2)、将JSON数组转化为XML:CretateOpXml(String json, String op, String table,String ID,String user)
Element rootElement = dom.getRootElement();
Element opElement = rootElement.addElement("op");
opElement.addAttribute("id", ID);
opElement.addAttribute("table", table);
if (op != "delete") {
if (op == "insert") {
opElement.addAttribute("action", "insert");
} else if (op == "update") {
opElement.addAttribute("action", "update");
}
String[] items = json.split(",");
for (String item : items) {
Element dataElement = opElement.addElement("data");
String[] content = item.split(":");
dataElement.addAttribute("name", content[0]);
dataElement.setText(content[1]);
}
} else {
opElement.addAttribute("action", "delete");
Element dataElement = opElement.addElement("data");
String[] content = json.split(":");
dataElement.addAttribute("name", content[0]);
dataElement.setText(content[1]);
}
(3)、将XML转换为SQL语句: String ParseSql(String id,String user)
StringBuffer sql = new StringBuffer();
Document document = load(fileName+user+".xml");
Element opIdElement = (Element) document.selectSingleNode("/store/op[last()]");
sql.append(opIdElement.attributeValue("id")+"|");
List list = document.selectNodes("/store/op[@id>=" + id + "]");
Iterator iter = list.iterator();
int j=0;
while (iter.hasNext()) {
Element opElement = (Element) iter.next();
String table = opElement.attributeValue("table");
Iterator<Element> dataElement = opElement.elementIterator();
StringBuffer col = new StringBuffer();
StringBuffer val = new StringBuffer();
int i = 0;
while (dataElement.hasNext()) {
Element nameElemnt = (Element) dataElement.next();
if (i == 0) {
col.append(nameElemnt.attributeValue("name"));
val.append("'" + nameElemnt.getText() + "'");
} else {
col.append("," + nameElemnt.attributeValue("name"));
val.append(",'" + nameElemnt.getText() + "'");
}
i++;
}
if (j == 0) {
if (opElement.attributeValue("action").equals("insert")) {
sql.append("incao zuosert into " + table + " (" + col.toString()+ ") values (" + val.toString() + ")");
} else if (opElement.attributeValue("action").equals("update")) {
String[] colSplit= col.toString().split(",");
String[] valSplit= val.toString().split(",");
String idUpdate=null;
StringBuffer update=new StringBuffer();
for(int ii=0;ii<colSplit.length;ii++){
if(ii==1){
update.append(colSplit[ii]+"="+valSplit[ii]);
}else if(ii>1){
update.append(","+colSplit[ii]+"="+valSplit[ii]);
}else{
idUpdate=colSplit[ii]+"="+valSplit[ii];
}
}
sql.append("update "+table+" set " + update.toString()+" where "+idUpdate);
} else {// delete
sql.append("delete from " + table + " where "+ col.toString() + "=" + val.toString());
}
}else{
if (opElement.attributeValue("action").equals("insert")) {
sql.append(";insert into " + table + " (" + col.toString() + ") values (" + val.toString() + ")");
} else if (opElement.attributeValue("action").equals("update")) {
String[] colSplit= col.toString().split(",");
String[] valSplit= val.toString().split(",");
String idUpdate=null;
StringBuffer update=new StringBuffer();
for(int ii=0;ii<colSplit.length;ii++){
if(ii==1){
update.append(colSplit[ii]+"="+valSplit[ii]);
}else if(ii>1){
update.append(","+colSplit[ii]+"="+valSplit[ii]);
}else{
idUpdate=colSplit[ii]+"="+valSplit[ii];
}
}
sql.append(";update "+table+" set " + update.toString()+" where "+idUpdate);
} else {// delete
sql.append(";delete from " + table + " where "+ col.toString() + "=" + val.toString());
}
}
j++;
}
return sql.toString();
2)、服务端数据解析(将ajax传递的JSON数组对象转换为JSON对象,同时更新数据库)
String synClientData(String userName){
Long ID=(long) 0;//Long.parseLong(OpStoreService.GetLastTime());
JSONArray array = JSONArray.fromObject(getJsonData());
StringBuffer sql=new StringBuffer();
try {
int j=0;
for (int i = 0; i < array.size(); i++) {
Map o = (Map) array.get(i);
String table=o.get("table").toString();
String clientID=o.get("ID").toString();
if(Long.parseLong(clientID)>ID){
if(o.get("op").equals("insert")){
if(j==0){
sql.append("insert into "+table+" (");
}else{
sql.append(";insert into "+table+" (");
}
Iterator iter = o.entrySet().iterator();
StringBuffer col=new StringBuffer();
StringBuffer val=new StringBuffer();
StringBuffer xml=new StringBuffer();
int k=0;
while (iter.hasNext()) {
Map.Entry<String, String> param = null;
param = (Entry<String, String>) iter.next();
if(param.getKey().equals("ID")||param.getKey().equals("op")||param.getKey().equals("table")){
continue;
}else{
if(k==0){
col.append(param.getKey());
val.append("'"+param.getValue()+"'");
xml.append(param.getKey()+":"+param.getValue());
}else{
col.append(","+param.getKey());
val.append(",'"+param.getValue()+"'");
xml.append(","+param.getKey()+":"+param.getValue());
}
}
k++;
}
j++;
OpStoreService os=new OpStoreService();
os.CretateOpXml(xml.toString(), "insert", table,clientID,userName);
sql.append(col.toString()+") values (" +val.toString()+")");
}else if(o.get("op").equals("update")){
if(j==0){
sql.append("update "+table+" set ");
}else{
sql.append(";update "+table+" set ");
}
Iterator iter = o.entrySet().iterator();
String id=null;
StringBuffer xml=new StringBuffer();
int k=0;
while (iter.hasNext()) {
Map.Entry<String, String> param = null;
param = (Entry<String, String>) iter.next();
if(param.getKey().equals("ID")||param.getKey().equals("op")||param.getKey().equals("table")){
continue;
}else{
if(param.getKey().equals("id"))
{
id=param.getValue().toString();
xml.append("id:"+id);
}else{
xml.append(","+param.getKey()+":"+param.getValue());
if(k==0){
sql.append(param.getKey()+"='"+param.getValue()+"'");
}else{
sql.append(","+param.getKey()+"='"+param.getValue()+"'");
}
k++;
}
}
}
j++;
OpStoreService os=new OpStoreService();
os.CretateOpXml(xml.toString(), "update", table,clientID,userName);
sql.append(" where id='"+id+"'");
}else{
if(j==0){
sql.append("delete from "+table+" where id='"+o.get("id").toString()+"'");
}else{
sql.append(";delete from "+table+" where id='"+o.get("id").toString()+"'");
}
OpStoreService os=new OpStoreService();
os.CretateOpXml("id:"+o.get("id").toString(), "delete", table,clientID,userName);
j++;
}
}
}
}finally{
}
return sql.toString();
}
2、浏览器
1)js数据存储结构localStorage.getItem(item,value)
username:记录登陆用户名 username+"LastSynTime":该用户本地操作数据的最后一次时间戳
username+"Syn":记录该用户需要同步的 username+"LastSyn":该用户同步操作数据的最后一次时间戳
2)用户点击同步
$("#commitSynData").bind("vclick",function(e){
if(localStorage.getItem("LastSynTime")==null){//无,若服务器有数据,则获取全部数据
LoadServAllData();
} else{//有,根据更新时间先后对比服务器和客户端,若有数据变化,将此数据发送服务器
//判断本地数据是否变化
SendLastSynTime();
}
});
function SendLastSynTime(){
$.ajax({
url:'/DiscreteCourse/DoAction_SendLastSynTime.do',
type:'POST',
data:{json:LastSynTime()},
dataType:'json',
success:function (data) {
if(data.json.trim().length<3){
}else if(data.json.trim().length==3){
LoadServAllData();
}else if(data.json.trim().length==4){
sendLoalAllData();
}else if(data.json.trim().length==13){
sendLocalPartData(data.json.trim());
}else{
var sqls=data.json.split('|');
doSql(sqls[1]);
upLastTime(sqls[0]);
}
}
});
}
2)webSQL全部更新
function doSql(sql){
var sqlItems=sql.split(";");
try {
localDB.transaction(function(transaction){
for(var i in sqlItems){
transaction.executeSql(sqlItems[i]);
}
});
} catch (e) {
updateStatus("很抱歉,数据库出错!");
}
}
七、存在的不足和优化
- Html5离线存储和数据同步
- HTML5离线存储和本地缓存
- HTML5离线存储和本地缓存
- [转]HTML5离线存储和本地缓存
- HTML5离线存储和本地缓存
- [html5]离线存储
- HTML5离线存储
- html5 离线存储
- html5离线存储入门
- html5离线存储
- [html5]离线存储
- HTML5离线存储
- html5离线存储
- HTML5:离线存储
- HTML5之离线存储
- html5离线应用存储
- HTML5:离线存储
- HTML5离线存储
- POJ1321( 棋盘问题)
- C++函数返回引用理解(二)
- 无根树转为有根数(图论) By ACReaper
- Java Web应用程序:Oozie及其使用方式
- ./configure,make,make menuconfig的区别
- Html5离线存储和数据同步
- java+eclipse
- 标准C++中的string类的用法总结
- SAX characters(char ch[],int start,int length) 数据不完整
- ffmpeg开发指南
- 2013深圳制汇节参观后记
- android中SeekBar拖动进度条的使用及事件监听
- TCp / Ip 简介
- 游戏编程入门学习笔记17——网络篇——显示本机IP