jszk:用js写一个zookeeper简易web控制台

使用node.js下的zookeeper客户端访问组件库,写一个 web的控制台,非常简单。比起java的ZooInspector,还有其他一些node下的zk的web控制台,有哪些优势?轻量,部署依赖少,可以单机,可以扔在服务器上多用户访问;依赖少,早起一些node下的zk的控制台,使用了node-zookeeper,这是是一个包装c实现库;这里使用了node-zookeeper-client库,这是一个纯js的zk客户端组件库,更为轻量。

使用express搭建web服务

环境安装,库安装略过;
app.js

const express = require('express')const bodyParser = require('body-parser')const api = require('./src/api')const port = 8123app = express()app.use(bodyParser.json({limit: '50mb'}))app.use(express.static('public'))app.use('/api', api)app.listen(port, '127.0.0.1', () => console.log(`Server running: http://localhost:${port}`))

访问zk的API

const express = require('express')const zookeeper = require('node-zookeeper-client')const Long = require('long')const router = express.Router()let zkConnections = {};router.post('/zk', async (req, res) => { switch(req.body.act){ case 'connect': { let client = await zkClient(req.body.address) zkListChildren(client, '/', res) break } case 'list': { let client = await zkClient(req.body.address) zkListChildren(client, req.body.path, res) break } case 'getData': { let client = await zkClient(req.body.address) zkGetData(client, req.body.path, res) break } case 'addNode': { let client = await zkClient(req.body.address) zkAddNode(client, req.body.path, res) break } case 'removeNode': { let client = await zkClient(req.body.address) zkRemoveNode(client, req.body.path, res) break } case 'setData': let client = await zkClient(req.body.address) zkSetData(client, req.body.path, req.body.data, res) break default: res.send('') }})async function zkClient(address){ let client = zkConnections[address] if(client){ let state = client.getState() if(state === zookeeper.State.SYNC_CONNECTED){ return Promise.resolve(client) }else{ client.close() delete zkConnections[address] return await zkClient(address) } }else{ client = zookeeper.createClient(address) zkConnections[address] = client console.log('new connetion: %s', address) client.connect() client.on('state', state => { console.log(state) }) return new Promise((resolve, reject) => { client.once('connected', ()=>{ resolve(client) }) }) }}function zkGetData(client, path, res) { client.getData(path, (err, data, stat) => { if(err){ console.log('%s', err) } let s = {} stat.specification.forEach(i => { s[i.name] = i.type === 'long' ? Long.fromBytes(stat[i.name]).toString() : stat[i.name] }); res.send({data: (data && data.length > 0) ? data.toString('utf8') : '', stat: s}) })}function zkListChildren(client, path, res) { client.getChildren(path, (err, children, stat) => { if(err){ console.log('%s', err) } res.send(children) })}function zkRemoveNode(client, path, res) { client.remove(path, -1, (err)=>{ if(err){ console.log('%s', err) res.send('fail') }else{ res.send('success') } })}function zkAddNode(client, path, res){ client.create(path, null, null, zookeeper.CreateMode.PERSISTENT, (err) =>{ if(err){ console.log('%s', err) res.send('fail') }else{ res.send('success') } })}function zkSetData(client, path, data, res){ client.setData(path, Buffer.from(data), -1, (error, stat) => { if (error) { console.log(error.stack); res.send('fail') }else{ res.send('success') } })}module.exports = router

使用Vue.js搭建前端

这里vue使用简单的方式,可以参考不使用Webpack的Vue传统前端使用方式(一)。

说说主要的几个点。

使用CDN引入js库

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js" integrity="sha256-ngFW3UnAN0Tnm76mDuu7uUtYEcG3G5H1+zioJw3t+68=" crossorigin="anonymous"></script>

使用了以下前端组件:

  • boostrap前端css/html框架
  • nanoscroller 滚动条
  • vue 前端mvvm框架
  • axios http请求库

使用js加载js

这个方法可以实现使用js加载js到html中,而且是同步的;

async function loadjs(src) { if(src instanceof Array){ return Promise.all(src.map(i => loadjs(i))) } let script = document.createElement('script') script.setAttribute('type', 'text/javascript') script.src = src; document.getElementsByTagName('body')[0].appendChild(script) return new Promise(resolve => { script.onload = () => { return resolve('ok') } })}

用法:

await loadjs([ 'js/vue_com.js', 'js/vue_zk.js'])

vue实现tree组件

Vue.component('tree', { template: ` <ul v-show="show"> <li v-for="node in nodes"> <span :class="[node.leaf ? 'leaf' : (node.show ? 'down-arrow' : 'right-arrow'), 'hand']" @click="loadAndToggleExpand(node)"></span> <a href="_javascript:;" @click="nodeClick($event, node)">{{node.text}}</a> <tree :nodes="node.children" :show="node.show" @nodeClick="childNodeClick" @load="childNodeLoad"> </li> </ul> `, props: ['nodes', 'show'], data(){ return {} }, methods:{ loadAndToggleExpand(node){ if(node.show === null){ this.$emit('load', node) }else{ node.show = !node.show } }, nodeClick(e, node){ this.$emit('nodeClick', node) }, childNodeClick(node){ this.$emit('nodeClick', node) }, childNodeLoad(node){ this.$emit('load', node) } } });

主界面及操作表单

详细代码不贴了,可以直接访问仓库: https://github.com/ccor/zk-browser

主界面主要是左侧树形目录,右侧的数据显示和操作区;

主要实现了经典的程序员的四门功课:增删改查。一般来说,基本够用了。

相关推荐

相关文章