Flowable 之任务分配


提示:以下是本篇文章正文内容,Java 系列学习将会持续更新

在这里插入图片描述

一、任务分配和流程变量

1.1 任务分配

1.1.1 固定分配

固定分配就是我们前面介绍的,在绘制流程图或者直接在流程文件中通过 Assignee 来指定的方式。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.1.2 表达式分配

Flowable 使用 UEL 进行表达式解析。UEL代表Unified Expression Language,是EE6规范的一部分.Flowable支持两种UEL表达式: UEL-value 和 UEL-method。

① 值表达式

值表达式 Value expression:解析为一个值。默认情况下,所有流程变量都可以使用。(若使用Spring)所有的Spring bean也可以用在表达式里。例如
在这里插入图片描述
可以看到通过表达式处理的效果。
在这里插入图片描述

先部署流程,然后在启动流程实例的时候绑定表达式对应的值。

/**
 * 启动流程实例
 */
@Test
public void testRunProcess(){
    
    
    // 设置 assignee 的取值
    Map<String,Object> variables = new HashMap<>();
    variables.put("assignee0","张三") ;
    variables.put("assignee1","李四"); 
    // 启动流程实例,第一个参数是流程定义的id
    ProcessInstance processInstance = runtimeService
            .startProcessInstanceById("MyHolidayUI:1:4", variables);// 启动流程实例
    // 输出相关的流程实例信息
    System.out.println("流程定义的ID:" + processInstance.getProcessDefinitionId());
    System.out.println("流程实例的ID:" + processInstance.getId());
    System.out.println("当前活动的ID:" + processInstance.getActivityId());
}

在流程变量表中我们可以看到对应的流程变量信息。
在这里插入图片描述
同时在 Task 表中,可以看到流程当前的分配人是 张三,说明 UEL 表达式被解析了。
在这里插入图片描述

② 方法表达式

方法表达式 Method expression: 调用一个方法,可以带或不带参数。当调用不带参数的方法时,要确保在方法名后添加空括号(以避免与值表达式混淆)。传递的参数可以是字面值(literal value),也可以是表达式,它们会被自动解析。例如:

${printer.print()}
${myBean.addNewOrder('orderName')}
${myBean.doSomething(myVar, execution)}

myBean 是 Spring 容器中的个 Bean 对象,表示调用的是 bean 的 addNewOrder 方法。

1.1.3 监听器分配

可以使用监听器来完成很多 Flowable 的流程业务。我们在此处使用监听器来完成负责人的指定,那么我们在流程设计的时候就不需要指定 assignee。

①创建自定义监听器

public class MyTaskListener implements TaskListener {
    
    
    @Override
    public void notify(DelegateTask delegateTask) {
    
    
        System.out.println("MyTaskListener 监听器被触发了!");
        if("提交请假流程".equals(delegateTask.getName()) && "create".equals(delegateTask.getEventName())) {
    
    
            delegateTask.setAssignee("小明");
        }else {
    
    
            delegateTask.setAssignee("王经理");
        }
    }
}

②然后在 FlowableUI 中关联对应的监听器

  • create:任务创建后触发。
  • assignment:任务分配后触发。
  • Delete:任务完成后触发。
  • All:所有事件都触发。

在这里插入图片描述
效果如下:
在这里插入图片描述

③然后我们启动流程,执行查看效果
在这里插入图片描述

在 Task 表中我们可以看到对应的分配人为 小明 说明通过监听也完成了任务分配的工作了。在这里插入图片描述

回到目录…

1.2 流程变量

  流程实例按步骤执行时,需要使用一些数据。在Flowable中,这些数据称作变量(variable),并会存储在数据库中。变量可以用在表达式中(例如在排他网关中用于选择正确的出口路径),也可以在Java服务任务(service task)中用于调用外部服务(例如为服务调用提供输入或结果存储)等等。

  流程实例可以持有变量(称作流程变量 process variables);用户任务以及执行(executions)——流程当前活动节点的指针——也可以持有变量。流程实例可以持有任意数量的变量,每个变量存储为ACT_RU_VARIABLE数据库表的一行。

所有的 startProcessInstanceXXX 方法都有一个可选参数,用于在流程实例创建及启动时设置变量。例如,在 RuntimeService 中:

ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables);

也可以在流程执行中加入变量。例如,(RuntimeService):

void setVariable(String executionId, String variableName, Object value);
void setVariableLocal(String executionId, String variableName, Object value);
void setVariables(String executionId, Map<String, ? extends Object> variables);
void setVariablesLocal(String executionId, Map<String, ? extends Object> variables);

在这里插入图片描述

1.2.1 全局变量

  流程变量的默认作用域是流程实例。当一个流程变量的作用域为流程实例时,可以称为 global 变量。

注意:如: Global变量:userId(变量名)、zhangsan(变量值)

  global 变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值。

1.2.2 局部变量

  任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大, 称为 local 变量。

  Local 变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。Local 变量名也可以和 global 变量名相同,没有影响。

1.2.3 案例讲解

当部门经理进行审批任务时,他需要设置流程变量为下一步流程指明方向。
在这里插入图片描述

①部署流程。

@Test
public void deploy(){
    
    
    Deployment deploy = repositoryService.createDeployment()
            .addClasspathResource("evectionUI.bpmn20.xml")
            .name("20230904出差申请")
            .deploy();
    System.out.println("deploy.getId() = " + deploy.getId());
    System.out.println("deploy.getName() = " + deploy.getName());
    System.out.println("deploy.getCategory() = " + deploy.getCategory());
}

②启动流程实例:并且指定全局流程变量。

/**
 * 在启动流程实例的时候设置流程变量
 */
@Test
public void runProcess(){
    
    
    // 设置流程变量
    Map<String, Object> variables = new HashMap<>();
    variables.put("worker", "张三");
    variables.put("manager1", "张经理");
    variables.put("manager2", "王总经理");
    variables.put("manager3", "孙钱务");
    // 启动流程实例,第一个参数是流程定义的id
    ProcessInstance processInstance = runtimeService
            .startProcessInstanceById("evection:1:4",variables);// 启动流程实例
    // 输出相关的流程实例信息
    System.out.println("流程定义的ID:" + processInstance.getProcessDefinitionId());
    System.out.println("流程实例的ID:" + processInstance.getId());
    System.out.println("当前活动的ID:" + processInstance.getActivityId());
}

③完成 Task 任务,同时也可以指定流程变量。

/**
 * 完成任务时指定流程变量
 */
@Test
public void completeTask(){
    
    
    Task task = taskService.createTaskQuery()
            .processDefinitionId("evection:1:4")
            .taskAssignee("李四")
            .singleResult();
    // 添加流程变量
    Map<String, Object> map = task.getProcessVariables();
    map.put("num",4);
    // 完成任务
    taskService.complete(task.getId(),map);
}

当然,我们也可以在处理流程之外通过 Task 编号来修改流程变量。

/**
 * 通过当前任务设置
 */
@Test
public void currentTask(){
    
    
    Task task = taskService.createTaskQuery()
            .processDefinitionId("evection:1:4")
            .taskAssignee("王五")
            .singleResult();
    // 添加流程变量
    Map<String, Object> map = task.getProcessVariables();
    map.put("num",1);
    //  一次设置多个值 设置局部变量
    taskService.setVariables(task.getId(), map);
}

回到目录…

二、候选人和候选人组

在流程定义中在任务结点的 assignee 固定设置任务负责人,在流程定义时将参与者固定设置在.bpmn 文件中,如果临时任务负责人变更则需要修改流程定义,系统可扩展性差。针对这种情况可以给任务设置多个候选人或者候选人组,可以从候选人中选择参与者来完成任务。

2.1 候选人

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.1.1 部署和启动流程

// 部署流程
@Test
public void deploy(){
    
    
    Deployment deploy = repositoryService.createDeployment()
            .addClasspathResource("Test3.bpmn20.xml")
            .name("请求流程-候选人")
            .deploy();
    System.out.println("deploy.getId() = " + deploy.getId());
    System.out.println(deploy.getName());
}

启动流程实例,并为候选人赋值。

@Test
public void runProcess(){
    
    
    // 给流程定义中的UEL表达式赋值
    Map<String,Object> variables = new HashMap<>();
    variables.put("manager1","张经理");
    variables.put("manager2","李经理");
    variables.put("manager3","王经理");
    runtimeService.startProcessInstanceById("test3:1:40e8b336-4c84-11ee-8f39-200db0c7aa5b", variables);
}

act_ru_variable 表中有了三个候选人的变量信息:
在这里插入图片描述

2.1.2 任务的查询

根据候选人查询可拾取的任务。

@Test
void queryTaskCandidate() {
    
    
    List<Task> tasks = taskService.createTaskQuery()
            .processDefinitionId("test3:1:40e8b336-4c84-11ee-8f39-200db0c7aa5b")
            .taskCandidateUser("李经理")
            .list();
    for(Task task : tasks) {
    
    
        System.out.println("task.getId() = " + task.getId());
        System.out.println("task.getName() = " + task.getName());
    }
}

act_ru_task 表中的任务执行人还是 null,但候选人是可以查出来该任务的。
在这里插入图片描述

2.1.3 任务的拾取

候选人知道有可拾取的任务后,拾取任务。一个候选人拾取任务后,其他候选人就不能再拾取该任务了。

@Test
void claimTaskCandidate() {
    
    
    Task task = taskService.createTaskQuery()
            .processDefinitionId("test3:1:40e8b336-4c84-11ee-8f39-200db0c7aa5b")
            .taskCandidateUser("李经理")
            .singleResult();
    if(task != null) {
    
    
        taskService.claim(task.getId(), "李经理");
    }
}

拾取后,act_ru_task 表中的任务执行人也显示出来了。
在这里插入图片描述

2.1.4 任务的退还

@Test
void unclaimTaskCandidate() {
    
    
    Task task = taskService.createTaskQuery()
            .processDefinitionId("test3:1:40e8b336-4c84-11ee-8f39-200db0c7aa5b")
            .taskAssignee("李经理")
            .singleResult();
    if(task != null) {
    
    
        taskService.unclaim(task.getId());
    }
}

退还后,act_ru_task 表中的任务执行人又变为 null。
在这里插入图片描述

2.1.5 任务的交接

如果我获取了任务,但是不想执行,那么我可以把这个任务交接给其他的用户。

@Test
void taskCandidate(){
    
    
    // 李经理 --> 王经理
    Task task = taskService.createTaskQuery()
            .processDefinitionId("test3:1:40e8b336-4c84-11ee-8f39-200db0c7aa5b")
            .taskAssignee("李经理")
            .singleResult();
    if(task != null) {
    
    
        taskService.setAssignee(task.getId(), "王经理");
    }
}

交接前,act_ru_task 表中的任务执行人为 “李经理”。
在这里插入图片描述
交接后,act_ru_task 表中的任务执行人为 “王经理”。
在这里插入图片描述

2.1.6 任务的完成

由被指派的任务执行人 assignee 完成任务。

@Test
void complete() {
    
    
    Task task = taskService.createTaskQuery()
            .processDefinitionId("test3:1:40e8b336-4c84-11ee-8f39-200db0c7aa5b")
            .taskAssignee("王经理")
            .singleResult();
    if(task != null) {
    
    
        taskService.complete(task.getId());
    }
}

流程结束,act_ru_task 表中的信息被清空。
在这里插入图片描述

回到目录…

2.2 候选人组

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2.1 管理用户和组

①创建用户

@Test
void createUser() {
    
    
    User user = identityService.newUser("诸葛亮");
    user.setFirstName("亮");
    user.setLastName("孔明");
    user.setEmail("[email protected]");
    user.setPassword("123456");
    identityService.saveUser(user);
}

在 act_id_user 表中可以看到创建的用户信息。

②创建组

@Test
void createGroup() {
    
    
    Group group = identityService.newGroup("group2");
    group.setName("生产部");
    group.setType("type2");
    identityService.saveGroup(group);
}

在 act_id_group 表中可以看到创建的组信息。
在这里插入图片描述

③将用户分配给组

@Test
void userGroup() {
    
    
    Group group = identityService.createGroupQuery()
            .groupId("group2")
            .singleResult();
    User user = identityService.createUserQuery()
            .userId("诸葛亮")
            .singleResult();
    identityService.createMembership(user.getId(), group.getId());
}

在 act_id_membership 表中可以看到用户和组的关系了。

2.2.2 流程的部署启动

部署流程定义:

@Test
public void deploy(){
    
    
    Deployment deploy = repositoryService.createDeployment()
            .addClasspathResource("Test4-候选人组.bpmn20.xml")
            .name("请求流程-候选人组")
            .deploy();
    System.out.println("deploy.getId() = " + deploy.getId());
    System.out.println(deploy.getName());
}

启动流程实例:需要将候选组ID添加到运行时变量表中。

@Test
void runProcess(){
    
    
    List<Group> groups = identityService.createGroupQuery().list();
    Group group1 = groups.get(0);
    Group group2 = groups.get(1);
    Map<String,Object> variables = new HashMap<>();
    variables.put("g1", group1.getId());
    variables.put("g2", group2.getId());
    runtimeService.startProcessInstanceById("test4:1:44ae7634-4bb2-11ee-9fc5-200db0c7aa5b", variables);
}

2.2.3 任务的拾取完成

任务的查询和拾取:根据登录的用户查询对应的组,再根据组查询可以拾取的任务。

@Test
void queryTaskCandidateGroup() {
    
    
    String userId = "赵云";
    Group group = identityService.createGroupQuery().groupMember(userId).singleResult();
    Task task = taskService.createTaskQuery()
            .processDefinitionId("test4:1:44ae7634-4bb2-11ee-9fc5-200db0c7aa5b")
            .taskCandidateGroup(group.getId())
            .singleResult();
    if(task != null) {
    
    
        taskService.claim(task.getId(), userId);
    }
}

完成任务。

@Test
void complete() {
    
    
    Task task = taskService.createTaskQuery()
            .processDefinitionId("test4:1:44ae7634-4bb2-11ee-9fc5-200db0c7aa5b")
            .taskAssignee("赵云")
            .singleResult();
    if(task != null) {
    
    
        taskService.complete(task.getId());
    }
}

回到目录…


总结:
提示:这里对文章进行总结:
本文是对flowable的进阶学习,学习了流程中任务分配的方式,候选人和候选组拾取任务,以及四种网关的使用。之后的学习内容将持续更新!!!

猜你喜欢

转载自blog.csdn.net/qq15035899256/article/details/132711421