微服务使用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":"param","id":"p","type":"int","defaultValue":12,"description":"测试"}] // 业务对应的脚本如下:(注意,函数参数必须与业务参数一致) function main(p=1) { console.log('param:' + p); 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); }
/* [{ "id": 1, "name": "a", "value": "postman" }, { "id": 2, "name": "ab", "value": "freeman" }, { "id": 3, "name": "b", "value": "policeman" }, { "id": 4, "name": "c", "value": "bad guy" }] */ // 用于获取需要显示的表格数据,查询脚本的参数必须是如下格式:fetchCountOnly表示是否仅获取数据总数,conditions表示json数组格式的查询条件,startIndex表示游标值,itemCount表示一页的最大个数 function main(fetchCountOnly, conditions, startIndex, itemCount) { var jsonConditions = JSON.parse(conditions); var data = JSON.parse(getCustomData('query_data')); var ret = data; if (jsonConditions && jsonConditions.length > 0) { ret = []; for (var item of jsonConditions) { if (item.name == 'name') { for (var d of data) { if (d.name.includes(item.value)) { ret.push(d); } } } } } if (fetchCountOnly) { // 返回符合条件的数据个数 return ret.length; } else { // 返回符合条件的格式化数据 return ret; } } // 删除数据操作脚本, 脚本的参数必须如下所示,item表示选中后将要操作的数据项 function deleteItem(item) { var data = JSON.parse(getCustomData('query_data')); var index = 0; for (var d of data) { if (d.id == item.id) { break; } ++index; } data.splice(index, 1); return setCustomData('query_data', data + ''); }
function getDevice() { var list = deviceList(rsOpenId); var ret = [{name: 'te', value: 'uuiiiiid'}, {name: 'ff', value: 'egwgggggg'}]; for (var item of list) { ret.push({name: item.name, value: item.uuid}); } console.log('ret', ret); 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') { 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 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') { 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; } }2.查询参数:指查询数据时用户指定的参数,组成查询条件(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); var ret = []; var arr = []; if (strIsNotEmpty(uuid)) { arr = dbQuery('test', '*', [`uuid='${uuid}'`]); } else { ret.push({name:'全部', value: 0}); arr = dbQuery('test', '*', [`id>0`]); } for (var item of arr) { ret.push({name: item.account, value: item.id}) } console.log('arr:', arr); return ret; }3.列:指显示数据时的表格列,注意列id要与数据查询处理函数返回数据对象的key一致,否则无法显示; 4.数据操作:指对数据item的操作,比如删除、编辑、执行等。每个数据操作可以指定脚本和函数用于具体处理,处理函数原型为 function fn(itemIds, params){},itemIds为数组,当前操作数据的id;params为数组,透传参数。介绍最重要的两个配置,按钮和内容 按钮指在对话框底部显示的按钮,常用取消和确定两个。内容指在对话框中显示的内容,可以显示输入控件和文本。1)按钮,[{"name":"取消"}, {"name":"确定", "functionName":"confirmDelete"}],functionName表示最后处理操作的函数。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; }5.批操作:批操作适用于多选清空,配置和操作一样,只是itemIds里包含选择的多个数据项id 6.增加操作:用于需要添加数据的情况,配置和操作一样,只是itemIds里包含选择的多个数据项id。处理函数为后端脚本函数用于处理具体的添加操作。 运行后系统会依据参数生成输入控件,用户输入的数据会透传给后端的confirmAdd函数
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); }
// url、minInterval,maxInterval为业务处理服务透传过来的参数 function main(url, minInterval, maxInterval) { var devices = deviceList(); for (var device of devices) { // 仅调度在线手机 if (device.onlineState == 1) { // 在手机上执行移动端名为"test"的脚本,这里的url参数会直接透传给移动端脚本的main函数参数。 scriptExe('test', device.uuid, [url], true); // 在minInterval和maxInterval之间随机延时一段时间 sleep(Math.random() * (maxInterval - minInterval) + minInterval); } } }
// url参数的值,是上面的微服务脚本通过调用scriptExe函数透传过来的。 function main(url) { console.log('url:' + url); }