当前位置: 首页 > 后端技术 > Java

如何领取和回滚Flowable任务?

时间:2023-04-02 09:49:53 Java

@[toc]在上一篇文章中,宋哥给大家分享了四种在Flowable中设置taskhandler的方法,但这四种方法都是针对单个taskhandler的。有时,一个任务节点中会有多个任务节点。比如张三提交了一个任务,lisi和wangwu都可以处理,那么应该怎么处理这种多任务候选的情况呢?今天来看看吧。1.绘制流程图首先,我们还是用老流程图,但是在UserTask设置分配用户的时候,我们设置了多个用户,如下图:设置完成后,我们下载流程文件,看对应的XML文件内容如下:="INITATOR"flowable:formFieldValidation="true">朋友们看到了,UserTask="javaboy中的flowable:candidateUsers,zhangsan,lisi”表示这个UserTask是由三个用户javaboy,zhangsan,lisi处理的,用户名之间用2隔开。查询taskhandler接下来我们部署启动上面的流程,具体如何部署Howtostart,松哥在上一篇已经和大家聊过了,这里不再赘述。流程启动成功后,现在我们可以很容易的想到和上一篇一样查询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_的ASSIGNEE_字段值为空!很容易理解它是空的。毕竟这个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的候选有3个,并且两个表联合查询可以找出谁应该处理这个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节点中的flowable:candidateUsers="${userIds}"表示进程handler由userIds变量控制。接下来我们开始流程,注意此时需要传入userIds变量来开始流程,如下:@Testvoidtest01(){MapuserIds=newHashMap<>();userIds.put("userIds","javaboy,zhangsan,lisi");ProcessInstancepi=runtimeService.startProcessInstanceByKey("demo01",userIds);logger.info("id:{},activityId:{}",pi.getId(),pi.getActivityId());}多个用户之间,用英文隔开,好了,流程启动成功后,接下来的操作参考第3节和第4节,这里不再赘述。5.2Listener当然,我们也可以通过listener为UserTask设置多个候选处理器用户。首先,我们创建一个监听器,如下所示:delegateTask.addCandidateUser("张三");delegateTask.addCandidateUser("lisi");}}然后画流程图的时候,把UserTask分配的user删掉,然后重新给UserTask设置一个监听器:然后设置一个UserTask创建时触发的监听器:然后我们下载这个流程图对应的XML文件,如下:>list=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.getHistoricIdentityLinksForTask(historicTaskInstance.getId());对于(HistoricIdentityLink链接:链接){logger.info("userId:{},taskId:{},type:{},processInstanceId:{}",link.getUserId(),link.getTaskId(),link.getType(),链接.getProcessInstanceId());}}}查询对应的SQL如下:和我们想的基本一样。这就是今天松哥给大家分享的如何设置Flowable多任务候选的方式~当然还有其他的方式,我们下篇继续~

最新推荐
猜你喜欢