设为首页 收藏本站
查看: 763|回复: 0

[经验分享] 用nodejs访问ActiveX对象,以操作Access数据库为例。

[复制链接]

尚未签到

发表于 2017-2-22 09:51:37 | 显示全部楼层 |阅读模式
起因有人提问“如果用nodejs访问sql server?”
找了找资料,发现有两类解决方法,使用第三方nodejs插件:https://github.com/orenmazor/node-tds、使用ADODB.ConnectionActiveX对象
参考:
http://stackoverflow.com/questions/857670/how-to-connect-to-sql-server-database-from-javascript
http://stackoverflow.com/questions/4728385/connecting-to-a-remote-microsoft-sql-server-from-node-js


如果用ActiveX那么在Windows下nodejs将会无所不能,类似写asp。那它们怎么通信?得动手试试


经过
思路
nodejs通过cscript.exe(windows脚本进程)间接访问ActiveX
cscript能解析jscriptvbscript两种脚本,无疑为方便维护选jscript开发。
参考:http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/cscript_overview.mspx?mfr=true


需解决的问题
1、跨进程通信
新版的nodejs里增加了对子进程的操作,跨进程通信不是问题。
http://nodejs.org/docs/latest/api/all.html#child_Processes
varutil=require('util'),
exec=require('child_process').exec,
child;


child=exec('cat*.js bad_file | wc -l',
function(error,stdout,stderr){
console.log('stdout:'+stdout);
console.log('stderr:'+stderr);
if(error!==null){
console.log('execerror: '+error);
}
});
如例我们可以拿到控制台的输出内容stdout

2、数据库访问相关ActiveX,ADODB.Connection
参考:http://msdn.microsoft.com/en-us/library/windows/desktop/aa746471%28v=vs.85%29.aspx
varconnection=newActiveXObject("ADODB.Connection");
varresult='ok';
try{
connection.Open("Provider=Microsoft.Jet.OLEDB.4.0;DataSource="+params.accessfile);
connection.Execute(params.sql);
}catch(ex){
result=ex.message;
}
return{
result:result
};

connection.Open(connectionString),链接字符串参数可以设置访问sql server。
参考:http://www.connectionstrings.com/sql-server-2005


3、为方便维护,特别将cscript和nodejs的脚本合并,用typeof exports判断当前运行环境。


4、字符编码cscript代码使用ascii编码
非ascii码字符进行“\uHHHH”Unicode编码。


5、命令行字符需转义,双引号、百分号在命令行有特殊意义。
参数传递使用base64编码,避免冲突
cscript环境MSXML2.DOMDocument可以做base64编解码
functionbase64Decode(base64){
varxmldom=newActiveXObject("MSXML2.DOMDocument");
varadostream=newActiveXObject("ADODB.Stream");
vartemp=xmldom.createElement("temp");
temp.dataType="bin.base64";
temp.text=base64;


adostream.Charset="utf-8";
adostream.Type=1;//1=adTypeBinary 2=adTypeText
adostream.Open();
adostream.Write(temp.nodeTypedValue);
adostream.Position=0;
adostream.Type=2;//1=adTypeBinary 2=adTypeText
varresult=adostream.ReadText(-1);//-1=adReadAll
adostream.Close();
adostream=null;
xmldom=null;
returnresult;
}

总结
调用流程
1、创建子进程,传递经过编码的参数;
2、子进程处理完毕将数据JSON格式化输出到控制台;(子进程自动结束)
3、读取控制台的数据,执行回调函数。


优势
1、使nodejs拥有访问ActiveX对象的能力;
2、实现简单,开发维护方便。


劣势
1、只能运行在Windows平台;
2、数据编解码会消耗更多cpu;
3、每次调用需要创建一个子进程重新连接。(可改进)


总结
1、具有一定实用性;
2、跨进程通信性能可继续探索。



  

  模块代码:

var Access = {create: function(params){var fso = new ActiveXObject("Scripting.FileSystemObject");var result = 'ok';if (!fso.FileExists(params.accessfile)){var adoxcatalog = new ActiveXObject("ADOX.Catalog");try {adoxcatalog.Create("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + params.accessfile);} catch(ex) {result = ex.message;return;}adoxcatalog = null;} else {result = 'exists';}return {result: result};},existsTable: function(params){var connection = new ActiveXObject("ADODB.Connection");var result = 'ok', exists = false;try{connection.Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + params.accessfile);var recordset = connection.OpenSchema(20/*adSchemaTables*/);recordset.MoveFirst();while (!recordset.EOF){if (recordset("TABLE_TYPE") == "TABLE" && recordset("TABLE_NAME") == params.tablename){exists = true;break;}recordset.MoveNext();}recordset.Close();recordset = null;} catch(ex){result = ex.message;}return {"result": result,"exists": exists};},execute: function(params){var connection = new ActiveXObject("ADODB.Connection");var result = 'ok';try{connection.Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + params.accessfile);connection.Execute(params.sql);} catch(ex){result = ex.message;}return {result: result};},query: function(params){var connection = new ActiveXObject("ADODB.Connection");var result = 'ok', records = [];try{connection.Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + params.accessfile);var recordset = new ActiveXObject("ADODB.Recordset");recordset.Open(params.sql, connection);var fields = [];var enumer = new Enumerator(recordset.Fields);for (; !enumer.atEnd(); enumer.moveNext()){fields.push(enumer.item().name);}recordset.MoveFirst();while (!recordset.EOF) {var item = {};for (var i = 0; i < fields.length; i++){var fieldname = fields;item[fieldname] = recordset(fieldname).value;}records.push(item);recordset.MoveNext();}recordset.Close();recordset = null;} catch(ex){result = ex.message;}return {result: result,records: records};}};if (/^u/.test(typeof exports)){ // cscriptvoid function(){//from http://tangram.baidu.com/api.html#baidu.jsonvar JSON = {stringify: (function () {/*** 字符串处理时需要转义的字符表* @private*/var escapeMap = {"\b": '\\b',"\t": '\\t',"\n": '\\n',"\f": '\\f',"\r": '\\r','"' : '\\"',"\\": '\\\\'};/*** 字符串序列化* @private*/function encodeString(source) {if (/["\\\x00-\x1f]/.test(source)) {source = source.replace(/["\\\x00-\x1f]/g, function (match) {var c = escapeMap[match];if (c) {return c;}c = match.charCodeAt();return "\\u00" + Math.floor(c / 16).toString(16) + (c % 16).toString(16);});}return '"' + source + '"';}/*** 数组序列化* @private*/function encodeArray(source) {var result = ["["], l = source.length,preComma, i, item;for (i = 0; i < l; i++) {item = source;switch (typeof item) {case "undefined":case "function":case "unknown":break;default:if(preComma) {result.push(',');}result.push(JSON.stringify(item));preComma = 1;}}result.push("]");return result.join("");}/*** 处理日期序列化时的补零* @private*/function pad(source) {return source < 10 ? '0' + source : source;}/*** 日期序列化* @private*/function encodeDate(source){return '"' + source.getFullYear() + "-" + pad(source.getMonth() + 1) + "-" + pad(source.getDate()) + "T" + pad(source.getHours()) + ":" + pad(source.getMinutes()) + ":" + pad(source.getSeconds()) + '"';}return function (value) {switch (typeof value) {case 'undefined':return 'undefined';case 'number':return isFinite(value) ? String(value) : "null";case 'string':return encodeString(value).replace(/[^\x00-\xff]/g, function(all) {return "\\u" + (0x10000 + all.charCodeAt(0)).toString(16).substring(1);});case 'boolean':return String(value);default:if (value === null) {return 'null';}if (value instanceof Array) {return encodeArray(value);}if (value instanceof Date) {return encodeDate(value);}var result = ['{'],encode = JSON.stringify,preComma,item;for (var key in value) {if (Object.prototype.hasOwnProperty.call(value, key)) {item = value[key];switch (typeof item) {case 'undefined':case 'unknown':case 'function':break;default:if (preComma) {result.push(',');}preComma = 1;result.push(encode(key) + ':' + encode(item));}}}result.push('}');return result.join('');}};})(),parse: function (data) {return (new Function("return (" + data + ")"))();}}//http://blog.csdn.net/cuixiping/article/details/409468function base64Decode(base64){var xmldom = new ActiveXObject("MSXML2.DOMDocument");var adostream = new ActiveXObject("ADODB.Stream");var temp = xmldom.createElement("temp");temp.dataType = "bin.base64";temp.text = base64;adostream.Charset = "utf-8";adostream.Type = 1; // 1=adTypeBinary 2=adTypeTextadostream.Open();adostream.Write(temp.nodeTypedValue);adostream.Position = 0;adostream.Type = 2; // 1=adTypeBinary 2=adTypeTextvar result = adostream.ReadText(-1); // -1=adReadAlladostream.Close();adostream = null;xmldom = null;return result;}WScript.StdOut.Write('<json>');var method = Access[WScript.Arguments(0)];var result = null;if (method){result = method(JSON.parse(base64Decode(WScript.Arguments(1))));}WScript.StdOut.Write(JSON.stringify(result));WScript.StdOut.Write('</json>');}();} else { // nodejsvoid function(){function json4stdout(stdout){if (!stdout) return;var result = null;String(stdout).replace(/<json>([\s\S]+)<\/json>/, function(){result = JSON.parse(arguments[1]);});return result;}var util = require('util'), exec = require('child_process').exec;for (var name in Access){exports[name] = (function(funcname){return function(params, callback){console.log([funcname, params]);exec(util.format('cscript.exe /e:jscript "%s" %s "%s"', __filename,funcname,(new Buffer(JSON.stringify(params))).toString('base64')),function (error, stdout, stderr) {if (error != null) {console.log('exec error: ' + error);return;}console.log('stdout: ' + stdout);callback && callback(json4stdout(stdout));});}})(name);}}();}
调用代码:var access = require('./access.js');var util = require('util');var accessfile = 'demo.mdb';access.create({ accessfile: accessfile }, function(data){console.log(data);});access.existsTable({ accessfile: accessfile, tablename: 'demo' }, function(data){if (data.result == 'ok' && !data.exists){access.execute({accessfile: 'demo.mdb',sql: "CREATE TABLE demo(id Counter Primary key, data Text(100))"});}});access.execute({accessfile: 'demo.mdb',sql: util.format("INSERT INTO demo(data) VALUES('zswang 路过!%s')", +new Date)}, function(data){console.log(data);});access.query({accessfile: 'demo.mdb',sql: "SELECT * FROM demo"}, function(data){console.log(data);});
最新代码:http://code.google.com/p/nodejs-demo/source/browse/#svn%2Ftrunk%2Fdatabase

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-345537-1-1.html 上篇帖子: 使用nodejs将html5 canvas base64编码图片保存为文件 下篇帖子: NodeJS: express 3.0 开发过程中把user放入session小记
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表