Flowable 之任务分配

news2024/11/29 22:53:42

文章目录

  • 一、任务分配和流程变量
    • 1.1 任务分配
      • 1.1.1 固定分配
      • 1.1.2 表达式分配
        • ① 值表达式
        • ② 方法表达式
      • 1.1.3 监听器分配
    • 1.2 流程变量
      • 1.2.1 全局变量
      • 1.2.2 局部变量
      • 1.2.3 案例讲解
  • 二、候选人和候选人组
    • 2.1 候选人
      • 2.1.1 部署和启动流程
      • 2.1.2 任务的查询
      • 2.1.3 任务的拾取
      • 2.1.4 任务的退还
      • 2.1.5 任务的交接
      • 2.1.6 任务的完成
    • 2.2 候选人组
      • 2.2.1 管理用户和组
      • 2.2.2 流程的部署启动
      • 2.2.3 任务的拾取完成


提示:以下是本篇文章正文内容,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("123456@163.com");
    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的进阶学习,学习了流程中任务分配的方式,候选人和候选组拾取任务,以及四种网关的使用。之后的学习内容将持续更新!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/986851.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FRR+BFD+OSPF与BGP联动

1.拓扑设计 2.拓扑介绍 如图&#xff0c;LY集团 由核心机房与接入层网络组成&#xff0c;集团网络需要通过核心机房访问互联网&#xff0c;集团网络运行OSPF与IBGP协议&#xff1b;集团网络中接入层网络正常经过R2访问互联网&#xff0c;如果R2设备失效后&#xff0c;应立即换到…

Git版本管理

Git版本介绍 Git 是一个分布式版本控制系统&#xff0c;它被广泛用于协作软件开发和管理代码的变更。Git 的设计目标是为了处理速度快、灵活性强、数据完整性好的版本管理需求。以下是 Git 版本管理的详细介绍&#xff1a; 版本控制系统 (VCS)&#xff1a; Git 是一种版本控制…

深度ESP32 PWM教程如何在ESP32 中使用PWM

关于ESP32PWM的简要说明 ESP32 SoC 满载了非常有用的外设&#xff0c;PWM 就是其中之一。是的。ESP32 的芯片中有一个专用的 PWM 硬件模块。脉宽调制或简称PWM是一种成熟且广泛使用的供电技术。 您可以使用 ESP32 的 PWM 来驱动 LED、电机&#xff08;普通直流电机和无刷电机…

Vue2项目练手——通用后台管理项目第六节

Vue2项目练手——通用后台管理项目 用户管理页table表格获取表格数据目录列表user.jsmock.jsindex.jsUsers.vue 新增和编辑功能Users.vue 删除功能使用的组件Users.vue 用户管理页 table表格 使用的组件和前面的表格使用的一致。 获取表格数据 目录列表 user.js import Mo…

基于SpringBoot的在线拍卖系统

基于SpringBootVue的在线拍卖系统&#xff0c;前后端分离 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 【主要功能】 后台&#xff1a;用户管理、商品类型管理…

无需设计经验,也能制作出精美的房地产电子传单

在数字化时代&#xff0c;传统的纸质传单已经不能满足人们对于互动和个性化的需求。为此&#xff0c;许多房地产公司开始将目光转向H5微传单&#xff0c;这是一种通过互联网和手机浏览器来传达信息的创新方式。今天&#xff0c;我们将教你如何使用乔拓云网制作房地产微传单H5&a…

STC单片机+EC11编码器实现调节PWM输出占空比

STC单片机+EC11编码器实现调节PWM输出占空比 📌相关篇《stc单片机外部中断+EC11编码器实现计数功能》 📍《STC15单片机特有的PWM寄存器和普通定时器实现PWM输出》 🎬效果演示: 🌼 通过逻辑分析仪获取P11引脚上的信号波形,查看其对应输出的占空比。 ✨本例程基于上面两…

Laravel 模型的关联写入多对多的关联写入 ⑩③

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; THINK PHP &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f44…

vue 页面加水印

首先创建一个waterMark.js文件&#xff0c;当然文件命名可自定义&#xff0c; use strictconst watermark {}/**** param {要设置的水印的内容} str* param {需要设置水印的容器} container*/ const setWatermark (str, container) > {const id 1.23452384164.123412415…

计算机网络第一章:概述

一.因特网概述 1.1网络、互联网(互连网)和因特网 网络由若干结点和连接这些结点的链路组成&#xff0c;可以是有线链路&#xff0c;也可以是无线链路 互连网&#xff1a;多个网络通过路由器互连起来&#xff0c;这样就构成了一个覆盖范围更大的网络&#xff0c;即互连网。因此…

spring注解@Component、@controller、@service、@repository

使用之前需要在spring.xml配置文件中配置 只有扫描正确&#xff0c;且应标记注解的类正确标记过后&#xff0c;spring容器才会帮组我们创建并且管理bean对象 Component注解 作用&#xff1a;把普通pojo实例化到spring容器中&#xff0c;相当于之前xml配置文件中的 &#xff…

【数据结构】链表C++编写的,它定义了一个链表,并实现了一些基本的链表操作,如创建新节点、插入节点、清空链表、输出链表以及查找节点

// 引入标准输入输出流库&#xff0c;用于输出操作 #include <iostream> // 引入标准库中的stdlib&#xff0c;包含了rand()函数和其他相关函数 #include <cstdlib> // 引入标准库中的time&#xff0c;包含了time()函数和其他相关函数 #include <ctim…

【Linux】高级IO --- Reactor网络IO设计模式

人其实很难抵制诱惑&#xff0c;人只能远离诱惑&#xff0c;所以千万不要高看自己的定力。 文章目录 一、LT和ET模式1.理解LT和ET的工作原理2.通过代码来观察LT和ET工作模式的不同3.ET模式高效的原因&#xff08;fd必须是非阻塞的&#xff09;4.LT和ET模式使用时的读取方式 二…

正反向代理理解

正向代理&#xff08;Forward Proxy&#xff09;和反向代理&#xff08;Reverse Proxy&#xff09;是两种用于网络通信的代理服务器&#xff0c;它们分别用于不同的场景和目的。 正向代理&#xff08;Forward Proxy&#xff09;&#xff1a; 正向代理是位于客户端和目标服务器…

球谐函数在环境光照中的使用原理

在三维空间中如何对场景光照进行球谐函数展开 图形学论文解析与复现【Spherical Harmonic Lighting:The Gritty Details】 首先&#xff0c;对场景中某像素点的漫反射光照进行计算。 L ( p , w o ) ∫ Ω L ( w i ) n ⋅ w i d w i L(p,w_o) \int_{\Omega}L(w_i)n\cdot w_i…

cad打印样式丢失怎么处理?

一提到CAD软件&#xff0c;我相信很多朋友都特别熟悉&#xff0c;因为在工作中很多的图纸设计都有它的功劳&#xff0c;经常从事cad设计的朋友对于cad打印样式都非常地精通了&#xff0c;在打印样式里包括了图纸的颜色、线条等&#xff0c;由于各种原因cad打印样式丢失了&#…

自行实现字符串转浮点数函数atof()

【重复造轮子的原因】 尽管atof是标准C中自带的函数,用于将字符串转为浮点数,但是在某些环境下有可能没法使用的(例如CUDA环境中,没有atof函数,但是math.h可以使用),因此自行实现。 【通过的测试用例】 【实现的代码】 #include <stdio.h> #include <math.h…

linux(rhel7)内核参数优化

内核参数 Linux sysctl.d 配置内核参数 rhel7中sysctl.d和sysctl.conf的执行顺序 执行顺序&#xff1a; sysctl.d > /etc/sysctl.conf sysctl.d的执行顺序&#xff1a; /etc/sysctl.d/run/sysctl.d/usr/local/lib/sysctl.d/usr/lib/sysctl.d/lib/sysctl.d/ 对于不同目录下…

交换排序——冒泡排序、快速排序

交换排序就是通过比较交换实现排序。分冒泡排序和快速排序两种。 一、冒泡排序&#xff1a; 1、简述 顾名思义就是大的就冒头&#xff0c;换位置。 通过多次重复比较、交换相邻记录而实现排序&#xff1b;每一趟的效果都是将当前键值最大的记录换到最后。 冒泡排序算法的原…

如何关闭一个tcp连接 阻塞和等待的区别 b树查找的过程

如何关闭一个 TCP 连接 可能大家第一反应是「杀掉进程」不就行了吗&#xff1f; 是的&#xff0c;这个是最粗暴的方式&#xff0c;杀掉客户端进程和服务端进程影响的范围会有所不同&#xff1a; • 在客户端杀掉进程的话&#xff0c;就会发送 FIN 报文&#xff0c;来断开这个客…