node-zookeeper-dubbo,执行下面的命令安装,我使用的是dubbox,需要修改一下源码:
npm install node-zookeeper-dubbo --save
1 修改后node-zookeeper-dubbo/libs/encode.js
/**
* Created by panzhichao on 16/8/18.
*/
'use strict';
const Encoder = require('hessian.js').EncoderV2;
const DEFAULT_LEN = 8388608; // 8 * 1024 * 1024 default body max length
function Encode(opt) {
this._opt = opt;
const body = this._body(opt._method, opt._args);
const head = this._head(body.length);
return Buffer.concat([head, body]);
}
Encode.prototype._head = function (len) {
const head = [0xda, 0xbb, 0xc2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let i = 15;
if (len > DEFAULT_LEN) {
throw new Error(`Data length too large: ${len}, max payload: ${DEFAULT_LEN}`);
}
while (len >= 256) {
head.splice(i--, 1, len % 256);
len >>= 8;
}
head.splice(i, 1, len);
return new Buffer(head);
}
Encode.prototype._body = function (method, args) {
const body = new Encoder();
body.write(this._opt._dver || '2.5.3.6');
body.write(this._opt._interface);
body.write(this._opt._version);
body.write(this._opt._method);
// add by dzm at 2017-01-13
if (args && args.length) {
body.write(args.length);
} else{
body.write(0);
}
//
// body.write(this._argsType(args)); note by dengzm at 2017-01-16
// end
if (args && args.length) {
for (var i = 0, len = args.length; i < len; ++i) {
body.write(args[i]);
}
}
// edit by dzm at 2017-01-13 调整attachments的位置到
body.write(this._attachments());
return body.byteBuffer._bytes.slice(0, body.byteBuffer._offset);
}
Encode.prototype._argsType = function (args) {
if (!(args && args.length)) {
return '';
}
const typeRef = {
boolean: 'Z', int: 'I', short: 'S',
long : 'J', double: 'D', float: 'F'
};
let parameterTypes = '';
let type;
for (var i = 0, l = args.length; i < l; i++) {
type = args[i]['$class'];
parameterTypes += type && ~type.indexOf('.')
? 'L' + type.replace(/\./gi, '/') + ';'
: typeRef[type];
// note by dzm at 2017-01-12
// if (type.charAt(0) === '[') {
// parameterTypes += '[L' + type.slice(1).replace(/\./gi, '/') + ';';
// } else {
// parameterTypes += type && ~type.indexOf('.')
// ? 'L' + type.replace(/\./gi, '/') + ';'
// : typeRef[type];
// }
}
console.log('parameterTypes is ' + JSON.stringify(parameterTypes));
return parameterTypes;
}
Encode.prototype._attachments = function () {
const implicitArgs = {interface: this._opt._interface, path: this._opt._interface, timeout: this._opt._timeout}
this._opt._version && (implicitArgs.version = this._opt._version)
this._opt._group && (implicitArgs.group = this._opt._group);
return {
$class: 'java.util.HashMap',
$ : implicitArgs
}
}
exports.Encode = Encode;
2 更改node-zookeeper-dubbo/libs/register.js
/**
* Created by panzhichao on 16/6/30.
*/
'use strict';
const url = require('url');
const os = require('os');
const CREATE_MODES = {
/**
* The znode will not be automatically deleted upon client's disconnect.
*/
PERSISTENT: 0,
/**
* The znode will not be automatically deleted upon client's disconnect,
* and its name will be appended with a monotonically increasing number.
*/
PERSISTENT_SEQUENTIAL: 2,
/**
* The znode will be deleted upon the client's disconnect.
*/
EPHEMERAL: 1,
/**
* The znode will be deleted upon the client's disconnect, and its name
* will be appended with a monotonically increasing number.
*/
EPHEMERAL_SEQUENTIAL: 3
};
function isLoopback(addr) {
return /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/
.test(addr) ||
/^fe80::1$/.test(addr) ||
/^::1$/.test(addr) ||
/^::$/.test(addr);
}
function ip() {
const interfaces = os.networkInterfaces();
return Object.keys(interfaces).map(function (nic) {
const addresses = interfaces[nic].filter(function (details) {
return details.family.toLowerCase() === 'ipv4' && !isLoopback(details.address);
});
return addresses.length ? addresses[0].address : undefined;
}).filter(Boolean)[0];
}
function consumer() {
const self = this;
const paths = [];
const host = ip();
const dependencies = self.dependencies;
let serv; //临时存储服务
const info = {
protocol: 'consumer',
slashes : 'true',
host : '',
query : {
application: self.application.name,
category : 'consumers',
check : 'false',
dubbo : self.dubboVer,
interface : '',
revision : '',
version : '',
side : 'consumer',
timestamp : (new Date()).getTime()
}
};
for (const s in dependencies) {
if (dependencies.hasOwnProperty(s)) {
serv = dependencies[s];
}
info.host = `${host}/${serv.interface}`;
info.query.interface = serv.interface;
info.query.revision = serv.version;
info.query.version = serv.version;
// edit by dzm at 2017-01-17 解决dubbox注册的问题
if (serv.group){
info.query.group = serv.group;
}
// end edit
paths.push(`/${self._root}/${serv.interface}/consumers/${encodeURIComponent(url.format(info))}`);
}
for (let i = 0, l = paths.length; i < l; i++) {
(function (path) {
self.client.exists(path, function (err, stat) {
if (err) {
console.log(err.stack);
return;
}
if (stat) {
console.log('Node exists.');
return;
}
self.client.create(path, CREATE_MODES.EPHEMERAL, function (err, node) {
if (err) {
console.error('Reg consumer failed:' + err.stack);
}
});
});
})(paths[i]);
}
}
exports.consumer = consumer;
3 node调用代码示例
我采用的是express框架,所以下面的代码只是我路由代码,其他的不用改。
var express = require('express');
var router = express.Router();
const nzd=require('node-zookeeper-dubbo');
const opt={
application:{name:'wcnapi'},
// register:'192.168.5.128:2181,192.168.5.128:2182,192.168.5.128:2183',
register:'192.168.5.172:2181,192.168.5.173:2181',
dubboVer:'2.8.4',
root:'dubbo',
dependencies:{
WcnService:{interface:'com.test.wcn.api.service.WcnService',version:'1.0.0',timeout:6000}
}
}
const Dubbo = new nzd(opt);
// const Dubbo=new nzd(opt);
/* 微信系统接口 */
router.get('/getLoginQrcode', function(req, res, next) {
var arg1={$class:'java.lang.String',$:'1300000067'};
Dubbo.WcnService.getLoginQrcode(arg1).then(function(data){
res.send(data);
}).catch(function(err){
res.send(err);
})
});
router.get('/test/1', function(req, res, next) {
var arg1={$class:'java.lang.String',$:'1300000067'};
var arg2={$class:'java.lang.Integer',$:1};
var arg3={$class:'java.lang.Integer',$:10};
Dubbo.WcnService.testApi(arg1,arg2,arg3).then(function(data){
res.send(data);
}).catch(function(err){
res.send(err);
})
});
router.get('/test03', function(req, res, next) {
var arg = {
$class:'com.test.wcn.dto.TestDto',
$:{
id:{$class:'java.lang.String',$:'0101'},
name:{$class:'java.lang.String',$:'0101'},
age:{$class:'java.lang.Integer',$:10},
sex:{$class:'java.lang.Boolean',$:true}
}
}
Dubbo.WcnService.test03(arg).then(function(data){
res.send(data);
}).catch(function(err){
res.send(err);
})
});
module.exports = router;
4 应用到实际生产环境的用法
上面只是一个基本的用法,但是如果实际投产还是要设计一下;
第一步 express路由分离
app.js中的代码
var routes = require('./routes/routes');
var app = express();
routes(app);
routes.js的代码
// dubbo接口配置
const nzd=require('node-zookeeper-dubbo');
var config = require('../libs/config');
const opt={
application:config.dubbo.application,
register:config.dubbo.register,
dubboVer:config.dubbo.dubboVer,
root:config.dubbo.root,
dependencies:{
CmsService:{interface:'com.test.cms.api.service.CmsService',version:'1.0.0',timeout:6000},
WcnService:{interface:'com.test.wcn.api.service.WcnService',version:'1.0.0',timeout:6000}
}
}
const Dubbo = new nzd(opt);
//
var infoRoutes = require('./page/infoRoutes');
var indexRoutes = require('./page/indexRoutes');
var dubbo = require('./dubbo');
module.exports = function(app){
dubbo(app,Dubbo);
// 首页
indexRoutes(app);
}
第二步 引入dubbo的接口
// 内容管理接口系统
var cms = require('./dubbo/cms');
// 微信接口系统
var wcn = require('./dubbo/wcn');
// //
module.exports = function(app,Dubbo){
cms(app,Dubbo);
wcn(app,Dubbo);
}
第三步 dubbo接口的通用设计
下面定义的cms.js,同时支持http服务以及dubbo服务。既可以对外调用,又可以对内。
let dubbox;
function _queryArticleList(columnId,page,rows, callback){
dubbox.CmsService.queryArticleList(columnId,page,rows).then(function(data){
let resp = {success:true,msg:''};
resp.data = data;
callback(resp);
}).catch(function(err){
let resp = {success:false,msg:err};
callback(resp);
})
}
function _queryContent(articleId,callback){
dubbox.CmsService.queryContent(articleId).then(function(data){
let resp = {success:true,msg:''};
resp.data = data;
callback(resp);
}).catch(function(err){
let resp = {success:false,msg:err};
callback(resp);
})
}
/*输出区域*/
module.exports = function(app,Dubbo){
dubbox = Dubbo;
// 获取文章列表
app.get('/cms/queryArticleList', function(req, res, next) {
let columnId={$class:'java.lang.String',$:req.query.columnId};
let page={$class:'java.lang.Integer',$:parseInt(req.query.page)};
let rows={$class:'java.lang.Integer',$:parseInt(req.query.rows)};
_queryArticleList(columnId,page,rows,function(resp){
res.send(resp);
})
});
app.get('/cms/queryContent', function(req, res, next) {
let articleId={$class:'java.lang.String',$:req.query.articleId};
_queryContent(articleId,function(resp){
res.send(resp);
})
});
}
module.exports.queryArticleList = _queryArticleList;
module.exports.queryContent = _queryContent;