关于workflow:Flowable-任务如何认领回退

66次阅读

共计 8194 个字符,预计需要花费 21 分钟才能阅读完成。

@[toc]
上篇文章松哥和大家分享了 Flowable 中设置工作解决人的四种形式,不过那四种形式都是针对单个工作解决人,有的时候,一个工作节点会存在多个候选人,例如 zhangsan 提交一个工作,这个工作即能够 lisi 解决,又能够 wangwu 解决,那么针对这种多个工作候选人的状况,咱们该如何解决?明天一起来看看。

1. 绘制流程图

首先咱们还是应用之前旧的流程图,然而在为 UserTask 设置调配用户的时候,咱们设置多个用户,如下图:

设置实现后,咱们下载这个流程文件,来看下对应的 XML 文件,内容如下:

<process id="demo01" name="demo01" isExecutable="true">
  <documentation>demo01</documentation>
  <startEvent id="startEvent1" flowable:initiator="INITATOR" flowable:formFieldValidation="true"></startEvent>
  <userTask id="sid-5F901234-AFF1-480E-9D66-2D196B910BA3" flowable:candidateUsers="javaboy,zhangsan,lisi" flowable:formFieldValidation="true"></userTask>
  <sequenceFlow id="sid-71FB3A81-F753-419D-9A0A-2FC6E5361CED" sourceRef="startEvent1" targetRef="sid-5F901234-AFF1-480E-9D66-2D196B910BA3"></sequenceFlow>
  <endEvent id="sid-D0B9E5BF-8C1A-4F8F-B2C2-F423F5DC556D"></endEvent>
  <sequenceFlow id="sid-DEBE03CD-F247-4EF3-BB67-ABBA94739B0A" sourceRef="sid-5F901234-AFF1-480E-9D66-2D196B910BA3" targetRef="sid-D0B9E5BF-8C1A-4F8F-B2C2-F423F5DC556D"></sequenceFlow>
</process>

小伙伴们看到,UserTask 中的 flowable:candidateUsers="javaboy,zhangsan,lisi" 就示意这个 UserTask 由 javaboy、zhangsan 和 lisi 三个用户解决,用户名之间用 , 隔开。

2. 查问工作解决人

接下来咱们部署并启动下面这个流程,具体如何部署如何启动,这个在之前的文章中松哥曾经和大家聊过了,这里不再赘述。

当流程启动胜利之后,当初咱们很容易想到像之前文章那样,去查问 javaboy 须要解决的 UserTask,如下:

List<Task> list = taskService.createTaskQuery().taskAssignee("javaboy").list();
for (Task task : 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!

为 null 这个其实也好了解,毕竟这个 UserTask 有多集体能够解决,然而只有一个字段,没法贮存,必定有其余存储形式。

好啦,不和大家卖关子了,这种有多个候选人的工作,咱们应该依照如下形式来查问:

@Test
void test12() {List<Task> list = taskService.createTaskQuery().taskCandidateUser("javaboy").list();
    for (Task task : list) {logger.info("id:{};name:{};taskDefinitionKey:{}", task.getId(), task.getName(), task.getTaskDefinitionKey());
    }
}

小伙伴们看到,这里应该调用 taskCandidateUser 办法进行解决。那么这个办法查问的是哪张表呢?咱们来看下下面办法最终执行的 SQL,如下:

: ==>  Preparing: SELECT RES.* from ACT_RU_TASK RES WHERE RES.ASSIGNEE_ is null and exists(select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TYPE_ = 'candidate' and LINK.TASK_ID_ = RES.ID_ and ( LINK.USER_ID_ = ?) ) order by RES.ID_ asc
: ==> Parameters: javaboy(String)
: <==      Total: 1

小伙伴们看到,这里的查问波及到两张表,别离是 ACT_RU_TASKACT_RU_IDENTITYLINK,两张表联结查问查出来的,那咱们来看看 ACT_RU_IDENTITYLINK 表的内容:

小伙伴们看到,TYPE_ 为 candidate 的就示意这个 Task 的候选人,id 为 c5693038-3f42-11ed-b9e2-acde48001122 的 Task 一共有三个候选人,两张表联结查问,才能够查到这个 UserTask 该由谁来解决。

另外一种常见的需要就是,曾经晓得了要解决的流程实例了,然而不晓得应该由谁来解决,此时通过查问 ACT_RU_IDENTITYLINK 表就能够确定一个流程实例都有哪些参与者,如下:

@Test
void test13() {List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().list();
    for (ProcessInstance pi : list) {List<IdentityLink> identityLinksForProcessInstance = runtimeService.getIdentityLinksForProcessInstance(pi.getId());
        for (IdentityLink identityLink : identityLinksForProcessInstance) {logger.info("ProcessInstanceId:{},UserId:{}",identityLink.getProcessInstanceId(),identityLink.getUserId());
        }
    }
}

咱们来看看下面这个执行的 SQL,如下:

能够看到,其实就是通过查问 ACT_RU_IDENTITYLINK 表获取咱们想要的数据。

3. 认领工作

对于这种有候选人的工作,咱们须要先认领,再解决。认领的实质,其实就是给 ACT_RU_TASK 表中,这个 UserTask 记录的 ASSIGNEE_ 字段设置上值。

认领工作的形式如下:

@Test
void test12() {List<Task> list = taskService.createTaskQuery().taskCandidateUser("javaboy").list();
    for (Task task : list) {taskService.claim(task.getId(),"javaboy");
    }
}

认领之后,咱们再来看 ACT_RU_TASK 表中的数据,如下:

能够看到,此时 ASSIGNEE_ 字段就有值了,同时 CLAIM_TIME 字段也记录了工作的认领工夫。

再来看看工作认领执行的 SQL,基本上和咱们所想的统一。

4. 解决工作

认领后的工作该如何解决,这个就和咱们上篇文章中介绍的形式统一了,如下:

@Test
void test11() {List<Task> list = taskService.createTaskQuery().taskAssignee("javaboy").list();
    for (Task task : list) {taskService.complete(task.getId());
    }
}

具体原理上篇文章中曾经介绍过了,这里就不再赘述了。

工作执行实现后,ACT_RU_IDENTITYLINK 表中的记录也会随之删除。

5. 变量与监听器

后面这种形式设置的工作候选人咱们是在绘制流程图的时候间接硬编码的,这显然不是一个好方法。如果能通过变量来传递工作的候选人,就会不便很多。

5.1 候选人变量

咱们能够在绘制流程图的时候,用变量代替间接指定候选人,形式如下:

此时,生成的流程 XML 文件中,UserTask 节点的解决人也就变成了上面这个样子:

<process id="demo01" name="demo01" isExecutable="true">
  <documentation>demo01</documentation>
  <startEvent id="startEvent1" flowable:formFieldValidation="true"></startEvent>
  <userTask id="sid-5F901234-AFF1-480E-9D66-2D196B910BA3" flowable:candidateUsers="${userIds}" flowable:formFieldValidation="true"></userTask>
  <sequenceFlow id="sid-71FB3A81-F753-419D-9A0A-2FC6E5361CED" sourceRef="startEvent1" targetRef="sid-5F901234-AFF1-480E-9D66-2D196B910BA3"></sequenceFlow>
  <endEvent id="sid-D0B9E5BF-8C1A-4F8F-B2C2-F423F5DC556D"></endEvent>
  <sequenceFlow id="sid-DEBE03CD-F247-4EF3-BB67-ABBA94739B0A" sourceRef="sid-5F901234-AFF1-480E-9D66-2D196B910BA3" targetRef="sid-D0B9E5BF-8C1A-4F8F-B2C2-F423F5DC556D"></sequenceFlow>
</process>

UserTask 节点中的 flowable:candidateUsers="${userIds}" 就示意流程的解决人由 userIds 变量管制。

好了,接下来咱们来启动流程,留神,此时启动流程须要传递 userIds 变量,如下:

@Test
void test01() {Map<String, Object> userIds = new HashMap<>();
    userIds.put("userIds", "javaboy,zhangsan,lisi");
    ProcessInstance pi = runtimeService.startProcessInstanceByKey("demo01",userIds);
    logger.info("id:{},activityId:{}", pi.getId(), pi.getActivityId());
}

多个用户之间,用英文 , 隔开。

好了,流程启动胜利后,接下来的操作参考 3、4 大节,这里我就不再赘述了。

5.2 监听器

当然,咱们也能够通过监听器来为 UserTask 设置多个候选解决人用户,首先咱们创立一个监听器如下:

public class MyUserTaskListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {delegateTask.addCandidateUser("javaboy");
        delegateTask.addCandidateUser("zhangsan");
        delegateTask.addCandidateUser("lisi");
    }
}

而后在绘制流程图的时候,删除掉 UserTask 调配的用户,而后从新为 UserTask 设置一个监听器:

而后设置一个在创立 UserTask 的时候触发的监听器:

而后咱们下载这个流程图对应的 XML 文件,如下:

<process id="demo01" name="demo01" isExecutable="true">
  <documentation>demo01</documentation>
  <startEvent id="startEvent1" flowable:initiator="INITATOR" flowable:formFieldValidation="true"></startEvent>
  <userTask id="sid-5F901234-AFF1-480E-9D66-2D196B910BA3" flowable:formFieldValidation="true">
    <extensionElements>
      <flowable:taskListener event="create" class="org.javaboy.flowableidm.MyUserTaskListener"></flowable:taskListener>
    </extensionElements>
  </userTask>
  <sequenceFlow id="sid-71FB3A81-F753-419D-9A0A-2FC6E5361CED" sourceRef="startEvent1" targetRef="sid-5F901234-AFF1-480E-9D66-2D196B910BA3"></sequenceFlow>
  <endEvent id="sid-D0B9E5BF-8C1A-4F8F-B2C2-F423F5DC556D"></endEvent>
  <sequenceFlow id="sid-DEBE03CD-F247-4EF3-BB67-ABBA94739B0A" sourceRef="sid-5F901234-AFF1-480E-9D66-2D196B910BA3" targetRef="sid-D0B9E5BF-8C1A-4F8F-B2C2-F423F5DC556D"></sequenceFlow>
</process>

能够看到,在 userTask 节点中,通过 extensionElements 指定了额定的监听器。

好啦,这个流程当初就能够间接启动了,启动时也不须要额定的变量。

流程启动胜利后,接下来的操作参考 3、4 大节,这里我就不再赘述了。

6. 工作回退

当一个工作认领(Claim)之后,然而又不想解决,此时咱们能够将工作退回。形式如下:

@Test
void test16() {List<Task> list = taskService.createTaskQuery().taskAssignee("javaboy").list();
    for (Task task : list) {taskService.setAssignee(task.getId(), null);
    }
}

其实思路很简答,就是从新为工作设置解决人,且解决人为 null,这就是将工作回退了,接下来其他人能够从新认领该工作了。

7. 批改工作候选人

7.1 减少

工作候选人也不是变化无穷的,也能够动静批改,当一个流程启动之后,流程曾经走到某一个 Task 了,此时咱们想要批改该 Task 的候选人,也是能够的,形式如下:

@Test
void test17() {List<Task> list = taskService.createTaskQuery().taskCandidateUser("javaboy").list();
    for (Task task : list) {taskService.addCandidateUser(task.getId(),"wangwu");
    }
}

增加实现后,查看 ACT_RU_IDENTITYLINK 表,咱们发现 wangwu 曾经增加进来了:

7.2 删除

如果想要删除一个候选人,形式如下:

@Test
void test18() {List<Task> list = taskService.createTaskQuery().taskCandidateUser("javaboy").list();
    for (Task task : list) {taskService.deleteCandidateUser(task.getId(), "wangwu");
    }
}

删除胜利之后,ACT_RU_IDENTITYLINK 表中对应的数据也就被革除掉了。

8. 查问历史数据

如果一个流程执行完结了,咱们还想查问这个流程已经波及到的参与者,能够通过如下形式查问:

@Test
void test14() {List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().list();
    for (HistoricProcessInstance historicProcessInstance : list) {List<HistoricIdentityLink> links = historyService.getHistoricIdentityLinksForProcessInstance(historicProcessInstance.getId());
        for (HistoricIdentityLink link : links) {logger.info("userId:{},taskId:{},type:{},processInstanceId:{}",link.getUserId(),link.getTaskId(),link.getType(),link.getProcessInstanceId());
        }
    }
}

这里最终其实就是去 ACT_HI_IDENTITYLINK 表中查问,对应的 SQL 如下:

下面这是查问一个流程的参加人,当然咱们也能够查问一个 Task 的候选人与解决人,如下:

@Test
void test15() {List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().list();
    for (HistoricTaskInstance historicTaskInstance : list) {List<HistoricIdentityLink> links = historyService.getHistoricIdentityLinksForTask(historicTaskInstance.getId());
        for (HistoricIdentityLink link : links) {logger.info("userId:{},taskId:{},type:{},processInstanceId:{}", link.getUserId(), link.getTaskId(), link.getType(), link.getProcessInstanceId());
        }
    }
}

查问对应的 SQL 如下:

和咱们所想的基本一致。

好啦,这就是松哥明天和大家分享的如何给 Flowable 设置多个工作候选人的形式~

当然,还有其余方法,下篇文章咱们持续~

正文完
 0