从Domino公式@DBLookup Web化谈如何实现通用函数

我以前实现的@DBLooup AJAX版,都是通过URL带参数,执行后台代理,并返回结果的方式。最近在实现一个应用模块时,看到我们公司同事的实现方式,觉得比我的更好一些,但有些缺陷。特此将代码贴出来供大家参考。具体的JS代码如下:
function dblookup(view,skey,column){ 
    try{
        var url = getPath()+"/"+view+"?readviewentries&restricttocategory="+skey;
        objHTTP = new ActiveXObject("Microsoft.XMLHTTP");
        //下面用get方法,在get方法中,代理取传过去的参数是用doc.query_string(0)
        objHTTP.open("GET", vurl, false, "", "");
        objHTTP.setRequestHeader("If-Modified-Since","0");
        objHTTP.send(false);
        //此处调用的是同步方法
        resp = objHTTP.responseXML.documentElement;
        objHTTP = null;
        var ss="";
        if (resp.hasChildNodes()) {
            NodeList = resp.getElementsByTagName("viewentry")
            for (var k=0;k
                NodeList1=NodeList(k).getElementsByTagName("entrydata");
                mynode=NodeList1(column-1).firstChild;
                mynode1=mynode.firstChild;
                ss= mynode1.nodeValue;
                break;
              }
          }else{
                ss="";
          }
    }catch(e){
        ss="";
    }
    return ss;
}

以上代码在使用URL请求视图时,使用restricttocategory进行分类限制,这样可以得到以skey为分类的视图,再通过返回的XML文档,对其进行解析得到视图中第一份文档指定列(column)中的值,并返回给调用者;

如果你想返回多个文档的指定列值,将:
                ss= mynode1.nodeValue;
                break;
      修改为:
                ss+=";"+mynode1.nodeValue;
      即可。但需要注意,视图缺省只返回20个文档,相关设置在服务器文档中设置。需要返回超过20个文档时,你可以在请求的URL中加入count参数来指定需要返回文档的个数。

此函数缺点不利于扩展,假如dblookup函数已在项目中或产品模块实施,但现在需要将其功能进行扩展,加入跨库和跨服务器功能时,如果修改dblookup函数参数,则肯定会影响到现在项目中或产品模块中相关的JS代码,对升级或更新造成了不少的工作量,这些工作量又是重复的。这种情况下通常选择的是新增另一个函数,如dblookup_pro,这样会使封装的JS文件多一些冗余代码,从而增加JS文件尺寸。当然你会说,增加一个函数并不会增加JS文件多少尺寸,但你想想,都抱着这个心态,JS中这扩展点,那补充点。经过长期团队成员的修改和项目积累,会使用封装的JS文件会越来越大,到达一种冗余代码过多,但又不得不用的状态。所以我一直强调在设计通用代码时,一定要适当考虑代码容错和以后的功能扩展对现有代码的影响。这样会给今后代码维护带来非常小的工作量,虽然前期在写代码考虑的事情非常多,但你如果习惯了这种代码编写风格,会规范你的代码,提高你代码的质量,这不是每位程序员所追求的吗?

但以上代码看似正常,能运行很好。但并没有容错代码,如HTTP请求失败,视图不存在怎么办?从代码上看返回的是空值,但这个是正确的返回结果吗?但如果出现以下情况,就会出现不可估量问题:

在提交文档时,如果调用dblookup,会有可能因为网络延时造成,未返回结果就已提交文档了。如下代码片断:
......
document.forms[0].UserCN.value = dblookup(‘vwAllUsers’,'SquallZhong',2);
document.forms[0].submit();

以上代码有可能让UserCN的值为空,如果在WebQuerySave()事件中有读UserCN域的值对文档进行处理,会造成程序上的运行错误。

对dblookup进行改进后,代码如下:


function dblookup() {
    //返回字符串
    var ret = null;
    //视图别名
    var vn = arguments[0];
    if (vn == null || vn == "") {
        alert("/u8bf7/u6307/u5b9a/u89c6/u56fe/u522b/u540d/uff01");
        return ret;
    }
    //关键字
    var key = arguments[1];
    if (key == null || key == "") {
        alert("/u8bf7/u6307/u5b9a/u5173/u952e/u5b57/uff01");
        return ret;
    }
    //指定列名
    var col = arguments[2];
    if (col == null || col == "") {
        alert("/u8bf7/u6307/u5b9a/u5217/u503c/uff01");
        return ret;
    }
    //回调函数
    var func = arguments[3];
    //指定数据库路径,数据库路径请使用Apps/DB.nsf。
    //不论在WINDOW平台还是LINUX平台,在Domino平台中可使用"/"通用,并兼容URL格式
    var dbpath = arguments[4];
    //如果未指定数据库路径,则取当前路径
    if (dbpath == null || dbpath == "") {
        dbpath = getPath();
    }
    //将数据库路径中""转换为"/"
    dbpath = dbpath.replace("//", "/");
    //指定数据库所在服务器名称,如AS1/ACME
    var svr = arguments[5];
    try {
        var url = "";
        if (svr == null || svr == "") {
            url = "/" + dbpath + view + "?readviewentries&restricttocategory=" + skey;
        } else {
            //如果为跨DOMINO服务器请求,使用后台代理处理跨服务器请求
            url = "/vgoresource.nsf/dblookup?openagent&login";
            url += "&vn=" + vn;
            url += "&key=" + key;
            url += "&col=" + col;
            url += "dbpath=" + dbpath;
            url += "svr=" + svr;
        }
        // 避免IECache,添加时间戳
        url += "&__t=" + Math.random();
        var objHTTP = null;
        if (window.XMLHttpRequest) {
            // 创建 Mozilla/FireFox平台的 XMLHttpRequest 对象
            objHTTP = new XMLHttpRequest();
        } else {
            if (window.ActiveXObject) {
            // 创建 IE/Windows 平台的XMLHttp对象
                objHTTP = new ActiveXObject("Microsoft.XMLHTTP");
            }
        }
        objHTTP.open("GET", url, false);
        objHTTP.onreadystatechange = function () {
            if (objHTTP.readyState == 4) {
                if (objHTTP.status == 200) {
                    //如果有回调函数
                    if (callback != null) {
                        var resp = objHTTP.responseXML.documentElement;
                        if (resp.hasChildNodes()) {
                            var NodeList = resp.getElementsByTagName("viewentry");
                            for (var k = 0; k < NodeList.length; k++) {
                                NodeList1 = NodeList(k).getElementsByTagName("entrydata");
                                mynode = NodeList1(column - 1).firstChild;
                                mynode1 = mynode.firstChild;
                                ret = mynode1.nodeValue;
                            }
                        } else {
                            ret = null;
                        }
                        callback(ret);
                    } else {
                        //如果没有回调函数,直接返回文本
                        return objHTTP.responseText;
                    }
                } else {
                    return null;
                }
            }
        };
        objHTTP.send(null);
    } catch (e) {
        return null;
    }
}

经过整改后的代码,可实现:
dblookup(view,keystring,column-num[,callback-function[,dbpath[,servername]]])
view:视图别名
keystring:关键字查询
column-num:指定列数
callback-function:回调函数(可选)
dbpath:指定数据库路径(可选),缺省为当前数据库
servername:指定Domino服务器名称(可选),缺省为当前服务器;注:指定服务器名称时,请不要使用CN=Apps/O=ACME,这样在URL地址相加时会认为是两个参数,所以指定服务器名称时请使用Apps/ACME
方括号中为可选参数。这样可兼容以前项目所使用的dblookup(view,keystring,column-num),不需要维护已有WEB应用中调用的格式,也能实现回调函数处理功能/跨库/跨服务器功能。
有了回调函数功能,可避免在AJAX请求未完成之前,执行下面的代码,从而提高了代码的容错性,如下列代码:
.......
function savedoc() {
    //查询是否已定义过,并回调继续提交函数
    var key = f.StServerName.value + "!!" + f.StDBPath.value;
    key = key.split("//").join("/");
    dblookup("ArchivePolicyViewByFullDBPath", key.toLowerCase(), 1, submitdoc);
}
function submitdoc() {
    var ret = arguments[0];
    var f = document.forms[0];
    if (ret == null) {
        f.submit();
    } else {
        alert("此数据库的归档策略已定义,请重新输入数据库路径!");
        f.StDBPath.select();
        f.StDBPath.focus();
    }
}

后续问题考虑:

1.dblookup函数中处理是使用XML文档解析方式,如果你使用的Domino服务器是7.0以上版本,建议使用JSON来处理数据,这样效率要比XML解析效率高。如果使用JSON来处理数据,需要将视图输出格式修改为JSON输出,只需要将以下代码:
url = "/" + dbpath + view + "?readviewentries&restricttocategory=" + skey;
修改为:
url = "/" + dbpath + view + "?readviewentries&outputformat=json&restricttocategory=" + skey;
注:还需要修改对JSON数据的解析方式

2.此函数功能,并未实现根据关键字查询相应文档所指定的域名,如果哪位朋友有兴趣可以实现一下。

3.Domino中视图设置,视图中第一列必须为分类列,如果第一列不是分类列,是查不出结果的。如下图:
image

4.对于封装的JS文件,建议对其进行混淆和压缩,来提高Javascript的安全性和JS在网络中的传输速度。

参考资料:

1.JS混淆压缩工具:http://blog.csdn.net/SquallZhong/archive/2008/11/29/3410592.aspx

2.WEB性能优化及考虑:http://blog.csdn.net/SquallZhong/archive/2008/08/25/2826429.aspx



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 选取视图的列的内容 @Trim @DbColumn 6 2. 隐藏判断常用的命令 6 3. 判断当前用户是否是“某个组”的成员,然后来显示和隐藏 6 4. 在Lotus Domino 中显示图 6 5. 链接JS文件 6 6. 删除文档的方法 7 7. $$return 域的使用 8 8. 将表单设计为视图或导航器模板 9 9. 为 Web 定制“表单已处理”确认信息 10 10. 定制出错信息 11 11. $$HtmlHead几种常用的技巧 11 12. Domino Designer 模板表 12 13. 角色判断 13 14. 判断文档是否正在被修改 13 15. 在只读的方式下返回($$return 13 16. 刷新表单 14 17. 怎样在文档里存照片? 14 18. 后台lotusscript如何取得前台表单中复选框所选择的项目列表(b/s结构) 15 19. 试图的列公式:附件下载 15 20. 有没有好一点的分页处理代码 16 21. 同一用户重复登录 18 22. Return to sender 19 23. Agent to copy values from 1 form to another 在同一个数据库中进行 22 24. 超越OLE – 通过COM结合MS Office与Notes应用 23 25. 读写关系数据库资料 28 26. 视图---excel,表单---word 32 27. 关于Web上的检索问题 35 28. 如何使用Notes与关系数据库进行信息交互? 37 29. 如何在IE里面实现notes中的 对话框列表? 39 30. LotusDomino环境下编写Web浏览器多数据库检索程序 40 31. WINAPI函数 44 32. 用PowerBuilder访问Lotus Notes数据库 55 33. 如何在表单中加入计数器 58 34. 实现两个数据库间的数据追加 C/S 结构 60 35. 如何防止他人使用旧id和旧口令访问Domino服务器? 61 36. 在你的WEB站点上使用DOMINO群集 62 37. 在你的DOMINO WEB站点中插入.SWF文件 73 38. DOMINO R5的域搜索功能在WEB上的实现 77 39. Display Rich Text fields in a view 86 40. Auto-Launch a file attachment 87 41. Showing a response count without showing the responses 89 42. 常用的几个按钮收集 91 43. 在WEB上从视图删除文档技巧 93 44. 在Domino Designer中使用XML数据 96 45. 在Domino Designer上执行XML 100 46. Show single category view, the next stage 107 47. Checkboxes in a list box 108 48. Formatting a Notes view in HTML table for WEB 109 49. Jump to the end of a view (web agent) 111 50. Disabling actions until a page finishes loading 114 51. Web-based, fully customizable search 115 52. 从复选框中删除文档Deleting selected docs on Web 120 53. Debugging LotusScript Agents 121 54. Displays the contents of the Subject field in the first document in theExamples view. 124 55. Example: GetLastDocument method 125 56. Examples: GetNextDocument method 125 57. Example: GetFirstDocument method 126 58. Examples: FTSearch method 127 59. Examples: DeleteDocument method 128 60. Example: Deleting a document 129 61. Example: Creating a document 129 62. Examples: Locating documents within a view or folder 130 63. Example: Adding a document 135 64. Export to Excel 136 65. 连接ODBC 138 66. 特效 140 67. notes和Excel交换数据 141 68. NOTES的ODBC:(LS:DO) 142 69. Managing JavaScript "popup" windows 第一稿 144 70. HEAD元素使用集锦 147 71. 主页javascript特效19则 148 72. 关于创建、删除、编辑、打开和保存文档URL 命令 156 73. Domino URL 命令 158 74. 在打开有下面这段代码的页面时将会跳出一个468x60大小的小窗口 160 75. javascript的容错脚本 161 76. Web search with JavaScript 162 77. 如何防止他人使用旧id和旧口令访问Domino服务器 164 78. Fixing the Domino CheckBox Bug 165 79. Managing JavaScript "popup" windows 172 80. Quick, easy, foolproof field level help 175 81. Quick edit document link 176 82. Managing JavaScript "popup" windows 178 83. Svg: Pie-Eyed 181 84. Recebt Entries 182 85. Xin Calendar Mods 183 86. 答复文档 186 87. 公式语言 187 88. Resuable way to get URL parameters into fields 199 89. JSHeader 使用 201 90. JavaScript 帮助 201 91. Examples: Collecting documents by searching 207 92. 关于DOcumentContext 的属性 209 93. About data types 关于lotus Domino 的数据类型 210 94. CLng function 212 95. Using the DOM to replace "No documents found" 213 96. What you need and want to know about errors 217 97. Processing multiple documents from a view 221 98. Forcing attachments to always download 225 99. ODBCExample: GetValue method 247 100. ODBCResultSet class 248 101. Create a "Login" anchor link 251 102. 分类视图的开发技巧 253 103. 公式语言 255 104. Copy documents from one database to another 267 105. 定制搜索表单 268 106. UserName的属性及使用 275 107. Dynamic Content for Popup Windows 277 108. Shortcut when printing from a Java Agent 278 109. Lotus Script: Write # statement 279 110. Lotus Script: Input # statement 280 111. 使用代理生成 XML 284 112. 使用视图生成 XML 286 113. 执行算术运算 288 114. Keep URLs simple by making them relative 292 115. Quick, easy, foolproof field level help 294 116. Hiding attachments (without noscript tag!) 295 117. Listing search results in groups 296 118. 如何在表单中加入计数器? 300 119. 怎样限制一个WEB用户只有登陆才能使用数据库 302 120. Complete control when printing HTML from an agent 304 121. Simple multi-lingual forms using Domino 306 122. Stop double form submissions 308

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值