您好,欢迎访问一九零五行业门户网

用nodejs访问ActiveX对象,以操作Access数据库为例_javascript技巧

起因
有人提问“如果用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能解析jscript和vbscript两种脚本,无疑为方便维护选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
复制代码 代码如下:
var util = 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('exec error: ' + error);
}
});
如例我们可以拿到控制台的输出内容stdout!
2、数据库访问相关activex,adodb.connection
参考:http://msdn.microsoft.com/en-us/library/windows/desktop/aa746471%28v=vs.85%29.aspx
复制代码 代码如下:
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
};
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编解码
复制代码 代码如下:
function 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=adtypetext
adostream.open();
adostream.write(temp.nodetypedvalue);
adostream.position = 0;
adostream.type = 2; // 1=adtypebinary 2=adtypetext
var result = adostream.readtext(-1); // -1=adreadall
adostream.close();
adostream = null;
xmldom = null;
return result;
}
总结
调用流程
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 var fieldname = fields[i];
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)){ // cscript
void function(){
//from http://tangram.baidu.com/api.html#baidu.json
var 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 item = source[i];
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 }
/**
* 日期序列化
* @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/409468
function 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=adtypetext
adostream.open();
adostream.write(temp.nodetypedvalue);
adostream.position = 0;
adostream.type = 2; // 1=adtypebinary 2=adtypetext
var result = adostream.readtext(-1); // -1=adreadall
adostream.close();
adostream = null;
xmldom = null;
return result;
}
wscript.stdout.write('');
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('');
}();
} else { // nodejs
void function(){
function json4stdout(stdout){
if (!stdout) return;
var result = null;
string(stdout).replace(/([\s\s]+)/, 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
其它类似信息

推荐信息