1。绘制流程图首先,我们还是使用老流程图,但是在UserTask设置分配用户的时候,我们设置了多个用户,如下图所示:设置完成后,我们下载流程文件,取一个看。对应的XML文件如下:formFieldValidation="true">小伙伴可以看到UserTask中的flowable:candidateUsers="javaboy,zhangsan,lisi"表示这个UserTask由三个用户处理:javaboy,zhangsan,lisi,用户名之间用2隔开。查询任务handler接下来我们部署并启动上面的流程。具体如何部署和启动这个流程,松哥在上一篇文章中已经讲过,这里不再赘述。流程启动成功后,现在我们可以很容易的想到像上一篇那样查询javaboy需要处理的UserTask,如下:Listlist=taskService.createTaskQuery().taskAssignee("javaboy").list();for(Tasktask:list){logger.info("id:{};name:{};taskDefinitionKey:{}",task.getId(),task.getName(),task.getTaskDefinitionKey());}但是我们却发现SQL执行完成后,查询不到任何数据!为什么?我们来分析一下。经过前面几篇文章的介绍,现在大家知道了,上面的方法最终查询的是数据库中的ACT_RU_TASK表,查询SQL如下:接着我们查看ACT_RU_TASK表及其ASSIGNEE_字段,结果如下:我们发现ACT_RU_TASK表中记录的ASSIGNEE_字段值为空!其实很容易理解为null。毕竟这个UserTask可以多人处理,但是字段只有一个,无法存储。必须有其他存储方法。好吧,我不会取笑所有人。对于这种有多个候选的任务,我们应该这样查询:for(Tasktask:list){logger.info("id:{};name:{};taskDefinitionKey:{}",task.getId(),task.getName(),task.getTaskDefinitionKey());}}可以看到,这里应该会调用taskCandidateUser方法进行处理。那么这个方法查询的是哪个表呢?我们来看看上述方法最终执行的SQL,如下:==>Preparing:SELECTRU_TASKRESWHERERU_TASKRESWHERERES.ASSIGNEE_isnullandexists(selectLINK.ID_fromACT_RU_IDENTITYLINKLINKwhereLINK.TYPE_='candidate'andLINK.TASK_ID_=RES.ID_and(LINK.USER_ID_=?))orderbyRES.ID_asc:==>Parameters:javaboy(String):<==Total:1如你所见,查询这里涉及到两个表,分别是ACT_RU_TASK和ACT_RU_IDENTITYLINK。两张表联合查询发现。然后我们看一下ACT_RU_IDENTITYLINK表的内容:朋友们看到了,TYPE_是candidate,表示这个Task的候选,id为c5693038-3f42-11ed-b9e2-acde48001122的Task一共有三个candidate,并且两个表联合查询可以找出谁应该处理这个UserTask。另一个常见的需求是你已经知道要处理的流程实例,但你不知道应该由谁来处理。这时候可以通过查询ACT_RU_IDENTITYLINK表来判断一个流程实例有哪些参与者,如下:@Testvoidtest13(){for(ProcessInstancepi:list){ListidentityLinksForProcessInstance=runtimeService.getIdentityLinksForProcessInstance(pi.getId());对于(IdentityLinkidentityLink:identityLinksForProcess){logger.info("ProcessInstanceId:{},UserId:{}",identityLink.getProcessInstanceId(),identityLink.getUserId());我们来看一下上面执行的SQL,如下:可以看到,其实就是通过查询ACT_RU_IDENTITYLINK表来获取我们想要的数据。3.领取任务对于这类有candidates的任务,我们需要先领取,再进行处理。claim的本质其实就是给ACT_RU_TASK表中UserTask记录的ASSIGNEE_字段设置一个上限值。领取任务的方式如下:@Testvoidtest12(){Listlist=taskService.createTaskQuery().taskCandidateUser("javaboy").list();for(Tasktask:list){taskService.claim(task.getId(),"javaboy");}}领取完后,我们来看一下ACT_RU_TASK表中的数据,如下:可以看到,此时ASSIGNEE_字段是有值的,CLAIM_TIME字段也记录了任务的领取时间。我们看一下task声明执行的SQL,和我们想的基本一致。4、任务领取后如何处理任务,这个和我们上篇介绍的方法一样,如下:@Testvoidtest11(){Listlist=taskService.createTaskQuery().taskAssignee("javaboy").list();for(Tasktask:list){taskService.complete(task.getId());}}具体原理上一篇已经介绍过,这里不再赘述。任务执行后,ACT_RU_IDENTITYLINK表中的记录也会被删除。5.变量和监听器前面方式设置的候选任务在画流程图的时候直接硬编码,显然不是一个好的方式。如果可以通过变量传递任务的候选人,那就方便多了。5.1候选变量我们在绘制流程图时可以使用变量代替直接指定候选变量,如下所示:此时在生成的流程XML文件中,UserTask节点的handler变为如下:demo01UserTask节点表示进程的处理器由userIds变量受到控制。接下来,让我们开始这个过程。注意此时启动进程需要传入userIds变量,如下:“startEvent1”可流动:formFieldValidation="true">用英文分隔多个用户。好了,流程启动成功后,接下来的操作请参考第3、4节,这里不再赘述。5.2Listeners当然,我们也可以通过listeners为UserTask设置多个候选处理器用户。首先,我们创建一个监听器如下:@Testvoidtest01(){MapuserIds=newHashMap<>();userIds.put("userIds","javaboy,zhangsan,lisi");ProcessInstancepi=runtimeService.startProcessInstanceByKey("demo01",userIds);logger.info("id:{},activityId:{}",pi.getId(),pi.getActivityId());}然后在画流程图的时候,把UserTask分配的user删掉,然后设置监听再次UserTask:然后设置一个监听器,创建UserTask时触发:然后我们下载这个流程图对应的XML文件,如下:demo01可以看到在userTask节点中,通过extensionElements指定了一个额外的监听器,这个流程现在是可以的直接启动,启动时不需要额外的变量。流程启动成功后,接下来的操作请参考第3、4节,这里不再赘述。6.任务回滚当一个任务被认领(Claim),但我们不想处理它时,这时候我们可以将任务退回。方法如下:@Testvoidtest16(){Listlist=taskService.createTaskQuery().taskAssignee("javaboy").list();for(Tasktask:list){taskService.setAssignee(task.getId(),null);}}其实思路很简单,就是重新给task设置handler,handler为null,也就是回滚task,其他人就可以重新claim这个task了。7.修改任务候选7.1添加任务候选不是静态的,也可以动态修改。当一个进程启动时,该进程就到达了某个Task。这个时候我们要修改Task的candidate。方法如下:@Testvoidtest17(){Listlist=taskService.createTaskQuery().taskCandidateUser("javaboy").list();for(Tasktask:list){taskService.addCandidateUser(task.getId(),"wangwu");}}添加完后,查看ACT_RU_IDENTITYLINK表,发现wangwu已经添加了:7.2删除如果要删除一个候选,方法如下:@Testvoidtest18(){Listlist=taskService.createTaskQuery().taskCandidateUser("javaboy").list();for(Tasktask:list){taskService.deleteCandidateUser(task.getId(),"wangwu");}}删除成功后,相应的数据也被清空。8、查询历史数据如果某个流程执行结束了,我们还想查询参与这个流程的参与者,可以通过以下方式查询:@Testvoidtest14(){Listlist=historyService.createHistoricProcessInstanceQuery()。列表();对于(HistoricProcessInstancehistoricProcessInstance:list){Listlinks=historyService.getHistoricIdentityLinksForProcessInstance(historicProcessInstance.getId());对于(HistoricIdentityLink链接:链接){logger.info("userId:{},taskId:{},type:{},processInstanceId:{}",link.getUserId(),link.getTaskId(),link.getType(),link.getProcessInstanceId());}}}最后是在ACT_HI_IDENTITYLINK表中查询,对应的SQL如下:以上是查询一个流程的参与者。当然我们也可以查询一个Task的candidates和processors,如下:@Testvoidtest15(){对于(HistoricTaskInstancehistoricTaskInstance:list){Listlinks=historyService.getHistoricIdentityLinksFor任务(historicTaskInstance.getId());对于(HistoricIdentityLink链接:链接){logger.info("userId:{},taskId:{},type:{},processInstanceId:{}",link.getUserId(),link.getTaskId(),link.getType(),链接.getProcessInstanceId());}}}查询对应的SQL如下:和我们想的基本一致