[align=center][size=large][b]Pure JS (4.3): pure.db.js 的实现(基于 MongoDB Rhino Driver)[/b][/size][/align]
接着之前的两篇文章,让我们来看看 pure.db.js 的实现细节,以及一些 MongoDB Driver 的相关内容。
[align=center][size=medium][b]1. MongoDB Java Driver[/b][/size][/align]
MongoDB Java Driver 可以到这里下载:
[url]https://github.com/mongodb/mongo-java-driver/downloads[/url]
用法如下:
看起来不错。我们可以直接通过 importClass 将 driver 相关的类导入进来。但这种语法形式还是太 “Java Way”了。
何必用 put 、 get 来操作 DBObject ?能够直接用 JS Object 作为参数和返回值不是更好吗?
接下来,就让我们看看实现了这一转换的开源项目 MongoDB Rhino 。
[align=center][size=medium][b]2. MongoDB Rhino[/b][/size][/align]
MongoDB Rhino 是 Google Code 上的一个开源项目,项目主页:
[url]http://code.google.com/p/mongodb-rhino/[/url]
它提供了强大的 BSON.to(..) 和 BSON.from(...) 方法,以实现 JavaScript 对象与 BSON 类的 Java 对象的互转,
用法如下:
不过它是为标准 Rhino 设计的,为了将它应用于 Java 7 内置的 Rhino ,需要下载源代码,修改 import 的 package,并去掉JSON 类 (与 Java 7 自带的 JSON 类冲突了)。
附件中是修改后的 MongoDB Rhino Driver 源码 (需要 Java 7 支持)。
上面的示例中的 JSON.to(...) 需要替换为 Java 7 中的 JSON.stringify(...)。
[align=center][size=medium][b]3. pure.db.js[/b][/size][/align]
MongoDB Rhino 仍然有一个缺点,就是每次使用时都需要调用 BSON.from(...) 和 BSON.to(...)。
有没有办法对输入、输出参数进行统一处理?
可能有人已经想到 proxy 模式或 AOP 之类的办法了。
实际上,通过 Rhino JavaScript 引擎提供的利器 “__noSuchMethod__” (类似于 Ruby 中的 method_missing)就可以很容易地为 Java 对象创建一个 proxy。
这也是解决 Java 对象与 JavaScript 对象不兼容的常用策略。
我们无法像操作普通的 JavaScript Object 那样,将 JavaScript 函数附加到 Java 对象上,或者将Java 对象的方法赋值给一个 JavaScript 变量;
但通过 “__noSuchMethod__” 的桥接作用,我们可以把对 JavaScript 对象(proxy)的方法的调用委托给 Java 对象,然后像操作普通的 JavaScript Object 那样扩展这个 proxy 对象。
pure.db.js 就是按照这种思路实现的 (这个文件位于 Pure JS 工程中的 scripts/lib 下,可以在前一篇的附件中找到)。
其用法如下:
参数和返回值都是 JS Object,是不是更为简洁了?
这里为 DBColletion 构造了一个 proxy,对输入的参数和返回的结果进行了统一处理,使得它的对外接口完全是JS Object 的形式。
pure.db.js 的代码结构如下:
proxy 的实现实际上是创建了一个 “空” 对象,仅包含一个函数:“__noSuchMethod_”。
将所有的函数调用委托为 Java 对象,但对参数和返回值进行了统一的处理。
proxy 的实现如下:
[code]
proxy = function(target) {
return {
__noSuchMethod__: function(name, args) {
// 函数名以 '$',表示将返回值转为数组
var cursor = true;
if (name.indexOf('$') === 0) {
cursor = false;
name = name.substr(1);
};
// 将别名转换为真实的方法名
name = aliases[name] || name;
// 将 object 类型的参数转换为 DBObject
for (var i = 0; i < args.length; ++i) {
if (typeof args[i] === 'object') {
args[i] = BSON.to(args[i]);
}
}
// 执行被代理的 Java 对象的对应方法
var ret = target[name].apply(target, args);
// 将 DBCursor 转为 JavaScript 数组(或保留原有形式,但创建 proxy)
if (ret instanceof DBCursor) {
ret = cursor ? proxy(ret) : BSON.from(ret.toArray());
// 将 DBObject 转为 JavaScript Object
} else if (ret instanceof DBObject) {
ret = BSON.from(ret);
}
return ret;
}
};
};
[/code]
以上就是 pure.db.js 的实现思路了。经过这层包装,我们可以更方便地使用 JavaScript 操作 MongoDB ;就像之前的例子中提到的那样,我们可以直接使用从前端传递过来的 JavaScript 对象与数据库交互了。当然最好还是先对客户端的输入进行做必要的检查。
接着之前的两篇文章,让我们来看看 pure.db.js 的实现细节,以及一些 MongoDB Driver 的相关内容。
[align=center][size=medium][b]1. MongoDB Java Driver[/b][/size][/align]
MongoDB Java Driver 可以到这里下载:
[url]https://github.com/mongodb/mongo-java-driver/downloads[/url]
用法如下:
// 连接 MongoDB 并获取 collection
Mongo m = new Mongo();
DBCollection coll = db.getCollection("testCollection")
// 构造查询条件并获得返回值
BasicDBObject query = new BasicDBObject();
query.put("i", 71);
cur = coll.find(query);
// 遍历输出查询结果
while(cur.hasNext()) {
System.out.println(cur.next());
}
看起来不错。我们可以直接通过 importClass 将 driver 相关的类导入进来。但这种语法形式还是太 “Java Way”了。
何必用 put 、 get 来操作 DBObject ?能够直接用 JS Object 作为参数和返回值不是更好吗?
接下来,就让我们看看实现了这一转换的开源项目 MongoDB Rhino 。
[align=center][size=medium][b]2. MongoDB Rhino[/b][/size][/align]
MongoDB Rhino 是 Google Code 上的一个开源项目,项目主页:
[url]http://code.google.com/p/mongodb-rhino/[/url]
它提供了强大的 BSON.to(..) 和 BSON.from(...) 方法,以实现 JavaScript 对象与 BSON 类的 Java 对象的互转,
用法如下:
// 连接 MongoDB 并获取 collection
var connection = new Mongo();
var db = connection.getDB('mydatabase');
var collection = db.getCollection('mycollection');
// 构造查询条件并获得返回值
var query = { name: /aRegularExpresison/i };
var document = BSON.from(collection.findOne(BSON.to(query)));
// 输出查询结果
java.lang.System.println(JSON.to(document))
不过它是为标准 Rhino 设计的,为了将它应用于 Java 7 内置的 Rhino ,需要下载源代码,修改 import 的 package,并去掉JSON 类 (与 Java 7 自带的 JSON 类冲突了)。
附件中是修改后的 MongoDB Rhino Driver 源码 (需要 Java 7 支持)。
上面的示例中的 JSON.to(...) 需要替换为 Java 7 中的 JSON.stringify(...)。
[align=center][size=medium][b]3. pure.db.js[/b][/size][/align]
MongoDB Rhino 仍然有一个缺点,就是每次使用时都需要调用 BSON.from(...) 和 BSON.to(...)。
有没有办法对输入、输出参数进行统一处理?
可能有人已经想到 proxy 模式或 AOP 之类的办法了。
实际上,通过 Rhino JavaScript 引擎提供的利器 “__noSuchMethod__” (类似于 Ruby 中的 method_missing)就可以很容易地为 Java 对象创建一个 proxy。
这也是解决 Java 对象与 JavaScript 对象不兼容的常用策略。
我们无法像操作普通的 JavaScript Object 那样,将 JavaScript 函数附加到 Java 对象上,或者将Java 对象的方法赋值给一个 JavaScript 变量;
但通过 “__noSuchMethod__” 的桥接作用,我们可以把对 JavaScript 对象(proxy)的方法的调用委托给 Java 对象,然后像操作普通的 JavaScript Object 那样扩展这个 proxy 对象。
pure.db.js 就是按照这种思路实现的 (这个文件位于 Pure JS 工程中的 scripts/lib 下,可以在前一篇的附件中找到)。
其用法如下:
// 连接 MongoDB 并获取 collection
var users = pure.db.get('users');
// 构造查询条件并获得返回值
var user = coll.get({ name: 'user1' });
// 输出查询结果
println(JSON.stringify(user));
参数和返回值都是 JS Object,是不是更为简洁了?
这里为 DBColletion 构造了一个 proxy,对输入的参数和返回的结果进行了统一处理,使得它的对外接口完全是JS Object 的形式。
pure.db.js 的代码结构如下:
pure.db = function() {
// 获取配置文件中指定的 DB
var db = new Mongo().getDB(config.db.name),
// 根据习惯设置的别名
aliases = { get: 'findOne', list: 'find' },
// proxy 方法(实现略)
proxy = function(target) { ... };
return {
get: function(name) {
// 请注意:这里为 DBCollection 创建了一个 proxy
return proxy(db.getCollection(name));
},
eval: function(func) {
// 如果参数是一个 Function,则将它转为 string
if (func instanceof Function) {
func = '(' + func + '())';
}
// 执行 DB.eval(...),实际参数为 string
db.eval(func);
},
// 其他函数,一律使用 __noSuchMethod__ 委托到 DBCollection 上
__noSuchMethod__: function(name, args) {
return db[name].apply(db, args);
}
};
}();
proxy 的实现实际上是创建了一个 “空” 对象,仅包含一个函数:“__noSuchMethod_”。
将所有的函数调用委托为 Java 对象,但对参数和返回值进行了统一的处理。
proxy 的实现如下:
[code]
proxy = function(target) {
return {
__noSuchMethod__: function(name, args) {
// 函数名以 '$',表示将返回值转为数组
var cursor = true;
if (name.indexOf('$') === 0) {
cursor = false;
name = name.substr(1);
};
// 将别名转换为真实的方法名
name = aliases[name] || name;
// 将 object 类型的参数转换为 DBObject
for (var i = 0; i < args.length; ++i) {
if (typeof args[i] === 'object') {
args[i] = BSON.to(args[i]);
}
}
// 执行被代理的 Java 对象的对应方法
var ret = target[name].apply(target, args);
// 将 DBCursor 转为 JavaScript 数组(或保留原有形式,但创建 proxy)
if (ret instanceof DBCursor) {
ret = cursor ? proxy(ret) : BSON.from(ret.toArray());
// 将 DBObject 转为 JavaScript Object
} else if (ret instanceof DBObject) {
ret = BSON.from(ret);
}
return ret;
}
};
};
[/code]
以上就是 pure.db.js 的实现思路了。经过这层包装,我们可以更方便地使用 JavaScript 操作 MongoDB ;就像之前的例子中提到的那样,我们可以直接使用从前端传递过来的 JavaScript 对象与数据库交互了。当然最好还是先对客户端的输入进行做必要的检查。