前提文章:
2.activiti-ui web项目集成(activiti 6.x)
activiti的流程相关基础都已具备,本文通过一个简单的例子,演示流程的全部生命周期
一.流程编辑创建
使用activiti-ui来定义流程,然后导出bpmn20.xml文件.(当然也可以使用eclipse插件或者idea插件来处理)
整体流程为上文中的请假流程:
开始节点:
有一个Initiator,作为后续驳回重新编辑的id使用.
领导审批节点,
审批人通过分组来确定
审批条件
审批通过与否,条件判断
重新调整:
受理人为发起人id,与发起节点initator相同
导出test.bpmn20.xml文件.
二.流程发布
使用RepositoryService发布.
/**
* 发布流程, 流程文件名与id相同
*
* @param id
* @param maps
* @return
* @author zj
* @date 2018年8月28日
*/
@RequestMapping("/deploy/{id}")
public String test(@PathVariable("id") String id, Map<String, String> maps) {
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment dp =repositoryService.createDeployment().key(id). addClasspathResource("/diagrams/" + id + ".bpmn20.xml").deploy();
ProcessDefinition pd= repositoryService.createProcessDefinitionQuery().processDefinitionKey(id).latestVersion().singleResult();
if (dp != null)
maps.put("msg", "流程:[" + pd.getName() + "] 发布完成 ,id:" + dp.getId());
else
maps.put("msg", "流程发布失败");
return "page/success";
}
通过url链接发布流程
三.流程的启动
启动
通过runService处理流程的启动.
/**
* 流程执行
*
* @param id
* @param action
* @param maps
* @return
* @author zj
* @date 2018年8月28日
*/
@RequestMapping("/start/{id}")
public String start(@PathVariable("id") String id, Map<String, String> maps) {
RepositoryService repositoryService = processEngine.getRepositoryService();
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("person", "张三");
User user = identityService.createUserQuery().userId("u1").singleResult();
// 用来设置启动流程的人员ID,引擎会自动把用户ID保存到activiti:initiator中
identityService.setAuthenticatedUserId("u1");
String businessKey = "";// 业务key,后续流程处理表单详细界面自定义使用
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(id, businessKey, variables);
String processInstanceId = processInstance.getId();
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionKey(id).latestVersion().singleResult();
// 下一步处理人或者处理组
// 根据流程实例ID查询 最新一步的任务
Task task= taskService.createTaskQuery().processInstanceId(processInstanceId).orderByTaskCreateTime().desc().limitTaskVariables(1).singleResult();
List<HistoricIdentityLink> identityLinks= processEngine.getHistoryService().getHistoricIdentityLinksForTask(task.getId());
String groups="";
String users="";
for (HistoricIdentityLink historicIdentityLink : identityLinks) {
if(historicIdentityLink.getGroupId()!=null)
groups+= historicIdentityLink.getGroupId()+",";
if(historicIdentityLink.getUserId()!=null)
users+= historicIdentityLink.getUserId()+",";
}
maps.put("msg",
"启动成功!启动用户" + user.getFirstName() + user.getLastName() + " " + user.getId() + "<br/>" + " 下一步处理:<br/>"
+" 用户组:"+groups+" <br/> 用户:"+ users + "<br/> ProcessDefinition:" + pd.getName() + " " + pd.getId() + " <br/> "
+ " ProcessInstance:" + processInstance.getId());
return "page/success";
}
然后一样通过url启动
查看
根据processinstanceid 查看流程
流程已经提交,相当于已经发起了一个请假申请.目前等待领导审批,因为流程定义的时候为领导组或领导组2.
所以这两个组的用户可以查看到待办任务.
四.待办任务
// 根据用户id查询其待办任务
List<Task> t2 = taskService.createTaskQuery().taskCandidateOrAssigned(userid).list();
String rst = packageTableData(t2);
这里封装了下待办的字段,查询流程及相关信息
Task t = (Task) o;
//待办节点
jo.put("name", t.getName());
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
.processDefinitionId(t.getProcessDefinitionId()).singleResult();
List<HistoricIdentityLink> hlinks = historyService
.getHistoricIdentityLinksForProcessInstance(t.getProcessInstanceId());
String startUser = "";
for (HistoricIdentityLink historicIdentityLink : hlinks) {
if (historicIdentityLink.getType().equals("starter")
&& historicIdentityLink.getUserId() != null) {
User u = identityService.createUserQuery().userId(historicIdentityLink.getUserId())
.singleResult();
startUser += u.getFirstName() + " " + u.getLastName() + "";
}
}
jo.put("assige", t.getAssignee());
jo.put("startUser", startUser);
jo.put("pname", pd.getName() + " :" + pd.getVersion());
jo.put("id", t.getId());
jo.put("iid", t.getProcessInstanceId());
jo.put("prodid", t.getProcessDefinitionId());
我们使用一个页面来模拟查询用户的待办任务
@RequestMapping("/tasklist/{userid}")
public String tasklist(@PathVariable("userid") String userid, Map<String, String> maps) {
User user = identityService.createUserQuery().userId(userid).singleResult();
maps.put("user", user.getFirstName() + " " + user.getLastName());
maps.put("uid", userid);
Group gp = identityService.createGroupQuery().groupMember(userid).singleResult();
maps.put("group", gp.getName());
return "page/list";
}
页面上使用bootstraptable显示界面
可以看到待办任务,这里 当前处理人为空,因为我们流程中选择的为用户组,所以两个指定组中的用户都能收到任务。
这里实际上是可以直接处理任务的,但是没有任务处理人的话,后续查询任务历史的时候比较麻烦。
所以这里有一个签收的概念,签收后实际动作为补上任务处理人,相当于独占,组中其他人就无法处理这个任务了.
五.任务签收
调用API,比较简单
@RequestMapping("/claim/{userid}/{taskid}/")
public String claim(@PathVariable("taskid") String id, @PathVariable("userid") String userid,
Map<String, String> maps) {
Task task = taskService.createTaskQuery().taskId(id).singleResult();
// 签收当前任务,在任务表中记录当前处理人,以便后续查询
taskService.claim(id, userid);
maps.put("msg", "签收完成");
return "page/success";
}
界面上通过按钮触发,l2用户签收
签收完成后,补上了当前处理人,则这个时候组里面的其他用户就看不到待办任务了.
六.任务的处理
签收完成,进行任务的处理,驳回或者通过。
这里也是模拟,传入我们流程定义的时候的参数 agree即可控制流程的走向.
@RequestMapping("/complete/{userid}/{taskid}/{action}")
public String complete(@PathVariable("taskid") String id, @PathVariable("userid") String userid,
@PathVariable("action") String action, Map<String, String> maps) {
Task task = taskService.createTaskQuery().taskId(id).singleResult();
// 当前处理人 模拟
identityService.setAuthenticatedUserId(userid);
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("agree", action);
// 存储特殊的与任务关联的变量值 -将审批通过与否与taskid关联起来,存储在 act_hi_varinst时保留taskid
taskService.setVariableLocal(id, "agree", action);
taskService.complete(id, variables);
maps.put("msg", "流程处理完成,参数:" + action);
return "page/success";
}
驳回
页面上传入false,及驳回.
这个时候,我们再看u1用户的待办流程及当前流程的状态图:
可以看到流程走到了重新调整的节点,又到了发起人那里处理.
调整提交
然后我们调整提交后,再用l2用户审批通过,
可以看到,走到人事审批了。
七.已办任务
到这里基本上流程的过程都演示完成了。
还差一个个人已办流程的呈现,
可以通过historyService的来查询act_hi_actinst数据,根据当前任务及任务完成状态查询
@RequestMapping("/done/{userid}")
@ResponseBody
public String done(@PathVariable("userid") String userid, Map<String, String> maps) {
// 根据用户id查询其已完成的任务
List<HistoricTaskInstance> t2 = historyService.createHistoricTaskInstanceQuery().taskAssignee(userid).finished().list();
String rst = packageTableData(t2);
return rst;
}
已办任务
如下:可以查询办理了两次,第一次没通过,第二次通过
act_hi_varinst参数表缺失taskid问题
这里发现一个问题,在数据库中act_hi_varinst表 无法查询到第一次审批不通过的参数 agree,怎么都只有最后一次的参数。
参数都只与processInstanceId关联了.
研究后发现,可以如下修改,将指定参数与任务id关联
// 存储特殊的与任务关联的变量值 -将审批通过与否与taskid关联起来,存储在 act_hi_varinst时保留taskid
taskService.setVariableLocal(id, "agree", action);
这样重新测试一个单子后发现数据有记录了。
第一次的单子 35035参数没有任务id,
第二次的单子35058都是先驳回,重新提交再通过,这次agree参数都存储了下来,第一次false,第二次true.
至此,简单流程基本都跑通了,正式的流程开发需要补充每个任务的具体处理页面及补充业务数据表单独管理即可.
源码
2019.1.2
github全系列源码示例已经发布,欢迎fork~.
https://github.com/kxjl168/activiti
本文基于CC BY-NC-ND 4.0 许可协议发布,作者:野生的喵喵。 固定链接: 【activiti简单流程示例 (activit 6.x)】 转载请注明
相关文章: