微服务使用JS脚本实现,支持模块化管理、高并发访问、数据库访问,主要用于扩展后端服务,或者创建其他独立的业务逻辑。 可用于实现移动端和服务端访问请求,以及通用的业务处理和数据查询服务,一个视频看懂微服务。点击这里查看实战demo。架构图如下所示:
// 调用接口call_demo,参数分别为'name'和123,返回值为ret function main() { var ret = callMicroService('call_demo', ['name', 123]); console.log('ret:' + ret); }
// 接口call_demo对应的脚本, name和value为移动端传入的参数 function main(name = '', value = 1) { console.log('name:' + name + ' value:' + value); return name + value; }
// 调用服务端接口call_demo,参数为["name", 123],clientKey和accessToken请替换成自己的鉴权参数 https://aznfz.com/api/call_micro_service?clientKey=xxxxx&accessToken=yyyyy&name=call_demo&isDev=true& params=%5B%22name%22%2C%20123%5D
// 接口call_demo对应的脚本, name和value为移动端传入的参数 function main(name = '', value = 1) { console.log('name:' + name + ' value:' + value); return name + value; }
业务参数元数据: [{"name":"值","id":"value","type":"int","defaultValue":12,"description":"测试"}, {"name":"设备","id":"uuid","type":"select","defaultValue":"{\"scriptName\":\"call_demo\", \"functionName\":\"getDevice\"}","description":""}] // 业务对应的脚本如下:(注意,函数参数必须与业务参数一致) function main(value=1, uuid='') { console.log('param value:' + value + ' uuid:' + uuid); var users = userList(); console.log('users:' + users); for (var u of users) { console.log('u:' + u); var devices = deviceList(u.openId); console.log('用户:' + u.username + ' 设备:' + devices); } // 获取管理员的设备 var devices = deviceList(''); console.log('管理员设备:' + devices); } function getDevice() { var list = deviceList(rsOpenId); var ret = []; for (var item of list) { ret.push({name: item.name, value: item.uuid}); } console.log('ret', ret); return ret; }
function getDevice() { var list = deviceList(rsOpenId); var ret = []; for (var item of list) { ret.push({name: item.name, value: item.uuid}); } console.log('ret', ret); return ret; } function getAccount(uuid) { console.log('getAccount uuid:', uuid); var ret = [{name:'全部', value: ""}]; var arr = []; if (strIsNotEmpty(uuid)) { arr = dbQuery('test', '*', [`uuid='${uuid}'`]); } else { arr = dbQuery('test', '*', [`id>0`]); } for (var item of arr) { ret.push({name: item.name, value: item.name}) } console.log('arr:', arr); return ret; } function confirmAdd(itemIds, params) { console.log('add=====> itemIds', itemIds, 'params', params); var obj = {}; for (var p of params) { obj[p.name] = p.value } console.log('obj:' + obj) var ret = dbInsert('test', obj); console.log('ret:' + ret); } function confirmDelete(itemIds, params) { console.log('confirm delete', itemIds, params); var b = false; for (var id of itemIds) { b = dbDelete('test', [`id=${id}`]); } return b; } function confirmEdit(itemIds, params) { console.log('confirm edit', itemIds, params) var sets = []; for (var item of params) { if (item.name == 'device') { item.name = 'uuid'; } var s = item.name + '='; if (item.type == 'string') { s+='"'; s += item.value; s += '"'; } else { s += item.value; } sets.push(s); } var b = false; console.log('sets:', sets); for (var id of itemIds) { b = dbUpdate('test', sets, [`id=${id}`]); } console.log('b:', b); return b; } function confirmProcess(itemIds, params) { console.log('confirmProcess:' + itemIds + ' params:' + params) } function query(fetchCountOnly, conditions, startIndex, itemCount) { console.log('fetchCountOnly:' + fetchCountOnly + ' conditions:' + conditions + ' startIndex:' + startIndex + ' itemCount:' + itemCount); var params = []; for (var item of conditions) { if ((item.name == 'uuid' || item.name == 'name') && strIsNotEmpty(item.value)) { params.push(`${item.name}="${item.value}"`); } } console.log('params:' + params); if (fetchCountOnly) { var qRet = dbQuery('test', 'count(id) as count', params); console.log('qRet:' + qRet); return qRet[0].count; } else { var qRet = dbQuery('test', '*', params, '', startIndex, itemCount); console.log('qRet:' + qRet); return qRet; } }
function confirmAdd(itemIds, params) { console.log('add=====> itemIds', itemIds, 'params', params); var obj = {}; for (var p of params) { obj[p.name] = p.value } var ret = dbInsert('test', obj); console.log('ret:' + ret); }2.数据查询函数原型:function query(fetchCountOnly, conditions, startIndex, itemCount){},fetchCountOnly表示是否仅仅获取符合查询条件的数据个数;conditions为用户输入的查询条件,比如:[{"name":"device","value":"abc"},{"name":"isDev","value":"true"}] ;startIndex和itemCount分别表示获取数据的起始游标位置和数据条数;返回数据为对象数组,例:[{"id":1, "name":"kate"},{"id":2, "name":"tom"}]。
function query(fetchCountOnly, conditions, startIndex, itemCount) { console.log('fetchCountOnly:' + fetchCountOnly + ' conditions:' + conditions + ' startIndex:' + startIndex + ' itemCount:' + itemCount); var params = []; for (var item of conditions) { if ((item.name == 'uuid' || item.name == 'name') && strIsNotEmpty(item.value)) { params.push(`${item.name}="${item.value}"`); } } console.log('params:' + params); if (fetchCountOnly) { var qRet = dbQuery('test', 'count(id) as count', params); console.log('qRet:' + qRet); return qRet[0].count; } else { var qRet = dbQuery('test', '*', params, '', startIndex, itemCount); console.log('qRet:' + qRet); return qRet; } }3.查询参数:指查询数据时用户指定的参数,组成查询条件(1中的conditions),支持字符串、整数、布尔、浮点、选项等,当执行服务时会让用户输入具体查询参数。text类型:返回的数据对应项包含text才返回,选项类型:返回数据对应项等于选择值才返回;重点介绍下选项类型(select),默认值主要支持两种方式:1)直接硬编码,name1:value1,name2:value2 ,name为显示值,value为实际值。比如“微信:1,支付宝:2”;2)通过后端微服务获取,{"functionName":"getDevice"},这里的functionName为后端微服务脚本中的函数名。如果有多个查询条件,并且多个条件间有关联,则需要使用next和previous来指定查询参数的id,{"functionName":"getDevice", "next":"account"} {"functionName":"getAccount","previous": "device"},表示device参数的值会影响(决定)account参数
function getDevice() { var list = deviceList(rsOpenId); var ret = []; for (var item of list) { ret.push({name: item.name, value: item.uuid}); } console.log('ret', ret); return ret; } // 这里的uuid为device中选择设备的uuid function getAccount(uuid) { console.log('getAccount uuid:', uuid); var ret = [{name:'全部', value: ""}]; var arr = []; if (strIsNotEmpty(uuid)) { arr = dbQuery('test', '*', [`uuid='${uuid}'`]); } else { arr = dbQuery('test', '*', [`id>0`]); } for (var item of arr) { ret.push({name: item.name, value: item.name}) } console.log('arr:', arr); return ret; }4.列:指显示数据时的表格列,注意列id要与数据查询处理函数返回数据对象的key一致,否则无法显示; 5.数据操作:指对数据item的操作,比如删除、编辑、执行等。每个数据操作可以指定脚本和函数用于具体处理,处理函数原型为 function fn(itemIds, params){},itemIds为数组,当前操作数据的id;params为数组,透传参数。介绍最重要的两个配置,按钮和内容 按钮指在对话框底部显示的按钮,常用取消和确定两个。内容指在对话框中显示的内容,可以显示输入控件和文本。1)按钮,[{"name":"取消"}, {"name":"确定", "functionName":"confirmDelete"}],functionName表示最后处理操作的函数。图标,详情请参考bootstrap 比如:trash表示删除,edit表示编辑,play表示执行,stop表示停止,search表示查询等等。2)内容,可以直接显示字符串,比如:是否确定删除?;也可以显示参数输入控件,[{"name":"名称","type":"string", "id":"name","sync":true},{"name":"值","type":"int","sync":true, "id":"value"}],注意sync表示初始化时是否同步显示数据项中的内容,一般用于编辑数据。
function confirmDelete(itemIds, params) { console.log('confirm delete', itemIds, params); var b = false; for (var id of itemIds) { b = dbDelete('test', [`id=${id}`]); } return b; } function confirmEdit(itemIds, params) { console.log('confirm edit', itemIds, params) var sets = []; for (var item of params) { if (item.name == 'device') { item.name = 'uuid'; } var s = item.name + '='; if (item.type == 'string') { s+='"'; s += item.value; s += '"'; } else { s += item.value; } sets.push(s); } var b = false; console.log('sets:', sets); for (var id of itemIds) { b = dbUpdate('test', sets, [`id=${id}`]); } console.log('b:', b); return b; }6.批操作:批操作适用于多选清空,配置和操作一样,只是itemIds里包含选择的多个数据项id
// url、minInterval,maxInterval为业务处理服务透传过来的参数 function main(url, minInterval, maxInterval) { console.log('url:' + url + ' minInterval:' + minInterval + ' maxInterval:' + maxInterval); var devices = deviceList(); for (var device of devices) { // 仅调度在线手机 if (device.onlineState == 1) { // 在手机上执行移动端名为"test"的脚本,这里的url参数会直接透传给移动端脚本的main函数参数。 console.log('exe script'); scriptExe('test', device.uuid, [url], true); console.log('sleep'); // 在minInterval和maxInterval之间随机延时一段时间 sleep(Math.random() * (maxInterval - minInterval) + minInterval); } } }
// url参数的值,是上面的微服务脚本通过调用scriptExe函数透传过来的。 function main(url) { console.log('url:' + url); toast('启动任务并执行'); }