很久没玩 activiti 了再摸起来都有点陌生了,梳理了一下要点如下:
1. d2js 作为业务端发起流程。
d2js.exports.vocationRequest =
d2js.vocationRequest = function(params){
try{
$V(this, params, {
reason : T.string,
duration : T.int
});
this.startProcess('请假', params);
this.session.message = 'vocation request success'
} catch(e){
logger.error('error', Error.toJava(e));
this.session.message = e + '';
}
this.response.sendRedirect(this.request.getHeader('referer'));
}
流程一般都是由业务系统发起的,这里假定为 d2js。
startProcess 封装了 activiti.runtimeService.startProcessInstanceByKey,其中第一个参数是已部署流程的流程名,第二个参数是变量。这些变量在流程的表达式里可以访问。
2. 流程引擎在 startProcess 或任务完成后自动进入下一个任务。
2.1 任务在设计器里可以指定 assignee,如果没有指定,应由 d2js 代码认领。
d2js.exports.listCandidateTasks = d2js.listCandidateTasks = function(users, groups){ sql{. select t.id_, t.name_, t.description_, t.task_def_key_, t.execution_id_,t.proc_inst_id_, t.create_time_, t.task_def_key_ from activiti.act_ru_task t , activiti.act_ru_identitylink l where t.assignee_ is null and (l.user_id_ = any(:users) or l.group_id_ = any(:groups)) and t.id_ = l.task_id_ order by t.id_ .} return this.query(sql, {users: $ARRAY('varchar', users || []), groups: $ARRAY('varchar', groups || [])}); }
d2js.exports.setAssignee = d2js.setAssignee = function(taskId){ activiti.taskService.setAssignee(taskId, this.session.user.id); }
d2js.exports.claim = d2js.claim = function(params){ try{ application.activiti.taskService.claim(params.task, this.session.user.id); this.session.message = 'claim success' } catch(e){ this.session.message = e + ''; } this.response.sendRedirect(this.request.getHeader('referer')); }
setAssignee 和 claim 是等效的,claim 看起来更偏业务。(claim 可能不支持重入,这里不考证了)
2.2 Assignee 可以查看自己的任务。
d2js.exports.listAssignedTasks = d2js.listAssignedTasks = function(params){ sql{. select t.id_, t.name_, t.description_, t.task_def_key_, t.execution_id_,t.proc_inst_id_, t.create_time_, t.task_def_key_ from activiti.act_ru_task t where t.assignee_ = ? .} return this.query(sql, [this.session.user.id + '']); }
3. 当 assignee 在现实世界处理完任务后,将处理结果提交并结束任务。结束任务在业务系统触发,而不是在规则引擎。
d2js.exports.handleRequest = d2js.handleRequest = function(params){ try{ var result = {approved: params.result == 'approved', managerMotivation: params.managerMotivation}; application.activiti.taskService.complete(params.task, result.toJava()); this.session.message = 'handle success' } catch(e){ this.session.message = e + ''; } this.response.sendRedirect(this.request.getHeader('referer')); }
4. 当规则引擎收到处理结果后,对处理结果进行判验,根据判验结果进入下一个分支。
如图,d2js 通过completeTask 发来的变量可在连线的条件表达式中直接使用。
要之,在 d2js 和 activiti 配合时,业务系统不负责流向,规则引擎不负责业务,通常一个 bpmn 和一个 d2js 配合,前者如同指挥,后者如同乐队,配合完成演出。业务系统的 user id 权限等不需要暴露给规则引擎,二者没有太深耦合。