微服务使用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;
}
}
运行后系统会依据参数生成输入控件,用户输入的数据会透传给后端的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);
}
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('启动任务并执行');
}