flowable
文章目录
- 流程引擎的发展
- idea插件Flowable BPMN visualizer
- 流程设计器
- FlowableUI
- 身份管理应用程序
- bpmn.js
- BpmnModel
- 流程图绘制
- 流程部署
- 发起审批流程
- Java中部署Flowable
- 使用bpmn文件部署
- springboot整合flowable
- 部署流程实例
- 启动流程实例
- 流程审批
- 流程的挂起和激活
- 流程实例的挂起和激活
- 任务分配
- 任务类型
- 服务任务
- 流程变量
- **1. 变量作用域**
- **2. 全局变量(Process Variables)**
- **3. 局部变量(Local Variables)**
- **4. `RuntimeService` 局部变量的特点**
- **5. 让变量在任务完成后消失**
- **✅ 方法 1:使用 `TaskService` 设置任务局部变量**
- **✅ 方法 2:手动删除 `RuntimeService` 局部变量**
- **✅ 方法 3:在任务监听器中删除变量**
- **6. 关键区别总结**
- 历史变量
- 身份服务
- 候选人
- 拾取操作
- 归还操作
- 指派
- 候选人组
- 管理用户和组
- 候选人组应用
- 网关服务
- 排他网关
- 并行网关
- 包容网关
- 事件网关
- 事件
- 定时器事件
- 启动事件
- 中间事件
- 边界事件
- 消息事件
- 启动事件
- 中间事件
- 边界事件
- 错误事件
- 开始事件
- 边界事件
- 结束事件
- 信号事件
- 开始事件
- 中间事件
- 边界事件
- 其它事件
- 终止结束事件
- 取消结束事件
- 补偿事件
- 其它
- flowable的ProcessEngine、*Service注入失败
- event definitions only allowed on start event if subprocess is an event subprocess
- 元素 'boundaryEvent' 中必须包含属性 'attachedToRef'。
- 所有表信息
- 1. **流程定义相关表**
- 2. **部署相关表**
- 3. **流程实例相关表**
- 4. **任务相关表**
- 5. **历史数据表**
- 6. **变量相关表**
- 7. **身份/用户/组表(可选模块)**
所有相关flowable的,建议路径纯中文目录,包括flowable设计命名、部署等
流程引擎的发展
idea插件Flowable BPMN visualizer
用于在开发环境中提供对BPMN(Business Process Model and Notation,业务流程模型和符号)文件的可视化支持。
流程设计器
FlowableUI
Flowable UI 是 Flowable 平台提供的用户界面组件,用于管理和监控业务流程。
- 下载
下载地址:https://github.com/flowable/flowable-engine/releases
- 解压
下载后解压,在flowable根目录下有个wars目录,里面有ui的war包,
- 启动
启动war包flowable-ui.war
默认的信息
端口:8080
地址:http://localhost:8080/flowable-ui/#/
用户名:admin
密码:test
- flowable-ui的配置
配置相关信息都在war包——WEB-INF——classes——flowable-default.preproties中
身份管理应用程序
用来管理用户和授权。
- 权限控制
前四个对应的是首页四个模块
在某个应用中授权一个用户,这个用户才可以访问对应模块,用户登陆以后,只能看到有权限的模块。
zhangsan只被授权了modeler应用,所以只能看到这个模块
bpmn.js
一个开源的、轻量级的JavaScript库,用于在Web应用中嵌入BPMN图形化设计功能,支持高度定制和跨平台兼容。
官网:https://bpmn.io/toolkit/bpmn-js/walkthrough/
BpmnModel
可以不借助流程设计器来定义流程图,可以通过BpmnModel对象来自定义流程图
流程图绘制
- 新建流程图
- 绘制界面
- 绘制一个简单的审批流程
默认只有一个开始的节点,点击节点会出现一些基础的选项,点击选项,会在当前节点后面拼接你选择的节点。
画完以后,加一个结束的节点。
- 设置属性
选中任何一个节点,下面属性面板会显示对应的属性,如果不选中节点,则显示全局的。选中后可编辑当前节点名称,指定审批人等
- 指定审批人
身份存储中可以选择在前面添加过的用户
- 保存
每个节点都配置好信息后,左上角保存
流程部署
- 创建应用程序
创建后默认是空的
- 编辑模型
点击编辑包含的模型,选择绘制好的流程图
都弄好以后,点击保存
- 发布
找到保存好的应用,点进来,点击右上角的发布
部署后在首页的位置可以看到
发起审批流程
这两个很类似,点击进入
- 任务和流程
任务:当前自己需要进行的流程任务。
流程:和自己相关的流程任务,包括自己处理过的。
- 启动流程
- 查看任务
流程第一个节点配置的是张三审批,所以张三能看到,李四看不到
- 审批
- 流程图
显示图可以查看当前流程的审批状态,蓝色的是流程已完成的,绿色的是未完成的
Java中部署Flowable
- 创建Java项目,引入依赖
<dependencies><dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.7.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.9</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>2.0.9</version></dependency></dependencies>
使用bpmn文件部署
- 下载bpmn2文件
- 创建数据库
只创建数据库,不用创建表。
项目启动的时候,如果表结构不匹配(如表不存在或版本过低),会自动创建缺失的表或更新现有表结构,配置这个属性setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE)
即可。 - 部署
测试方法部署流程
package com.wzw;import org.flowable.engine.ProcessEngine;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;
import org.flowable.engine.repository.Deployment;
import org.junit.jupiter.api.Test;public class FlowableTest {private static final String url = "jdbc:mysql://localhost:3306/flowable?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";@Testpublic void test() {//流程引擎的配置对象,关联相关的数据源ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration().setJdbcUrl(url).setJdbcDriver("com.mysql.cj.jdbc.Driver").setJdbcUsername("root").setJdbcPassword("root")//检查数据库是否已经存在,如果表结构不匹配(如表不存在或版本过低),会自动创建缺失的表或更新现有表结构.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);//获取流程引擎对象ProcessEngine processEngine = cfg.buildProcessEngine();//获取仓库服务对象RepositoryService repositoryService = processEngine.getRepositoryService();//部署流程Deployment deploy = repositoryService.createDeployment()// 也可以一次部署多个//.addClasspathResource("process/01/flow2.bpmn20.xml").addClasspathResource("process/01/flow1.bpmn20.xml").name("部署流程").deploy();System.out.println("------------------deployId:"+deploy.getId());}
}
执行以后,如果没有表,就会自动创建,结果显示部署成功
执行成功后,会有很多表,
-
act_ge_bytearray
流程信息在act_ge_bytearray
中
-
act_re_deployment
部署信息在act_re_deployment
表中,存储部署信息,记录每次流程部署的元数据
-
act_re_procdef
存储流程定义的元数据,记录每个流程版本的详细信息。
springboot整合flowable
- 配置文件,配置数据源、端口、flowable
server:port: 8001spring:application:name: flowableDemodatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/flowable?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: rootpassword: roottype: com.alibaba.druid.pool.DruidDataSourcehikari:minimum-idle: 5idle-timeout: 600000maximum-pool-size: 10auto-commit: truepool-name: MyHikariCPmax-lifetime: 1800000connection-timeout: 30000connection-test-query: SELECT 1
flowable:async-executor-activate: true #是否开启异步任务database-schema-update: true #数据库是否更新
logging:level:org.flowable: debug
- flowable的
database-schema-update的参数
- true:自动创建缺失的表并更新现有表结构(开发环境常用)。
- create:仅创建缺失的表,不修改已有表结构(避免数据丢失风险)。
- false(默认):不自动更新表结构,若表结构不匹配则直接报错。
- none:同 false,完全不检查表结构。
部署流程实例
package com.wzw;import jakarta.annotation.Resource;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class FlowableDemoApplicationTests {@Autowiredprivate ProcessEngine processEngine;@Resourceprivate RepositoryService repositoryService;/*** 通过ProcessEngine 和 RepositoryService 都可以* ProcessEngine 是 Flowable 中的核心引擎组件,它负责执行流程定义、管理流程实例、任务和历史记录等。* RepositoryService 负责与流程定义相关的操作,例如部署、查询流程定义等。它是 Flowable 引擎的一部分,并通过 ProcessEngine 提供。*/@Testvoid contextLoads() {// RepositoryService repositoryService = processEngine.getRepositoryService();Deployment deploy = repositoryService.createDeployment().addClasspathResource("process/01/flow1.bpmn20.xml").name("spring部署流程").deploy();System.out.println("------deploy:"+deploy.getId());}}
成功
启动流程实例
/*** 启动流程实例* 两种方式,* 1.通过流程定义id启动* 2.通过业务key启动* 流程定义id*/@Testvoid start(){//业务key创建流程图的时候定义的
// String businessKey="";//通过流程定义key 启动流程实例
// runtimeService.startProcessInstanceByKey(businessKey);//流程定义表中的idString processId="flow1:1:4";//通过流程定义id 启动流程实例ProcessInstance processInstance = runtimeService.startProcessInstanceById(processId);}
启动成功,表act_ru_task中查看当前待办信息。
每启动一个流程实例,都会在表act_hi_procinst中维护一条记录。
- 流程定义和流程实例的关系。
- 流程定义 是流程的蓝图,流程实例 是基于流程定义的实际运行。
- 一个流程定义可以启动多个流程实例。
- 流程定义存储在 ACT_RE_PROCDEF,流程实例存储在 ACT_RU_EXECUTION(运行时)或 ACT_HI_PROCINST(历史)。
- 启动流程实例时,必须指定流程定义的 key 或 ID。
流程审批
- 查询指定用户的待办信息
/*** 根据用户查询待办信息*/@Testvoid findTask(){//任务实例相关通过taskservice来实现TaskService taskService = processEngine.getTaskService();//查询待办信息,act_ru_task表的记录List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan") //指定办理人 act_ru_task.assignee_等于zhangsan的数据.list();list.forEach(task -> {System.out.println(task.getId());});}
查到的结果和数据库一致
- 审批
/*** 任务审批*/@Testvoid completeTask(){//完成任务taskService.complete("2506");}
审批完成后,审批节点已经由人事审批变成了经理审批,审批人也变成了经理审批对应的人员。
如果最后一个节点也审批通过,整个审批流程就结束了,act_ru_task表中就不会存在这个审批流程的数据。
流程的挂起和激活
/*** 流程的挂起和激活*/@Testvoid suspendAndActivate(){//根据id查询挂起激活的状态ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId("flow1:1:4").singleResult();//是否挂起状态boolean suspended = processDefinition.isSuspended();if(suspended){//如果是挂起状态,就激活log.warn("流程已经挂起,现在激活");repositoryService.activateProcessDefinitionById("flow1:1:4");}else {//如果是激活状态,就挂起log.warn("流程已经激活,现在挂起");repositoryService.suspendProcessDefinitionById("flow1:1:4");}}
查看挂起和激活状态,act_re_procdef
表中SUSPENSION_STATE_
字段,1是激活,2是挂起。执行一下代码,挂起后再启动流程,就会报错提示
已经启动的流程是不受影响的。
流程实例的挂起和激活
先挂起流程实例,act_ru_task
表的SUSPENSION_STATE_字段变成2,
/*** 挂起流程实例*/@Testvoid suspendProcessInstance(){//通过流程实例id挂起流程实例runtimeService.suspendProcessInstanceById("5001");//激活流程实例
// runtimeService.activateProcessInstanceById("2501");}
然后执行审批就会报错,无法完成挂起的任务
挂起的任务需要激活,才能继续审批
任务分配
-
固定分配
在分配用户选择固定值,然后手动填入用户名,填的是谁,审批人就是谁
-
表达式
也是在固定值中写,但是不再是写死的,而是使用表达式- 使用UEL(Unified Expression Language)表达式
${}
的格式
- 使用Java表达式
结合Java类和方法来实现
- 使用UEL(Unified Expression Language)表达式
-
监听分配
选中流程节点,属性中往下翻,找到任务监听器
点击新增事件
任务监听器的四种事件类型
事件 触发时机 适用场景 create 任务创建时触发 分配任务(assignee、候选用户/组)、初始化变量 assignment 任务被分配给某个用户时触发 记录任务分配日志、发送通知 complete 任务完成时触发 更新业务数据、记录日志 delete 任务被删除时触发 处理任务被取消、流程中断等情况 - 配置监听
这里给审批节点2配置了监听,那么就是对审批节点1执行审批操作后,就会触发这个监听器import org.flowable.task.service.delegate.DelegateTask; import org.flowable.task.service.delegate.TaskListener;public class MyListener01 implements TaskListener {@Overridepublic void notify(DelegateTask delegateTask) {if(EVENTNAME_CREATE.equals(delegateTask.getEventName())){//设置审批人delegateTask.setAssignee("zhaoliu");}} }
- 配置监听
-
实例
-
第一个节点
新建了一个流程,第一个节点是写死的值,是zhangsan,它对应关系如下
如果第一个值是表达式,那么启动流程的时候就得指定,不然要报错String businessKey="demo02";Map<String, Object> variables = new HashMap<>();variables.put("assign2", "zhangsan");//通过流程定义key 启动流程实例,并指定第一个节点变量assign2的值runtimeService.startProcessInstanceByKey(businessKey, variables);
-
第二个节点是个表达式,如果执行
taskService.complete
方法,指定第二个表达式的值,就会报错
所以得指定表达式的值/*** 任务审批*/@Testvoid completeTask(){Map<String, Object> variables = new HashMap<>();variables.put("asssgin1", "lisi");//根据task完成任务,根据任务id,绑定表达式的值,根据任务 ID 完成指定的任务实例,同时将变量 "asssgin1" 设置为 "lisi",供后续流程节点使用taskService.complete("3f45a860-07b5-11f0-b92e-00ff78cf2894", variables);}
执行以后,可以看到,当前节点已经是审批节点2,然后审批人就是代码中指定的人lisi
-
第三个表达式是对象中的属性,同样的,如果不指定,也会报错,所以指定一下。
-
任务类型
服务任务
- 服务任务需要实现 JavaDelegate 接口,重写 execute方法,这个方法会在流程执行到对应的服务任务时被调用
package com.wzw.delegate;import com.wzw.Log.ConsoleOutput;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.time.LocalDateTime;public class MyFirstDelegate implements JavaDelegate {Logger log= LoggerFactory.getLogger(MyFirstDelegate.class);/*** 回调方法* @param execution*/@Overridepublic void execute(DelegateExecution execution) {// 输出日志ConsoleOutput.output(log,"执行了自定义委托类:"+ LocalDateTime.now());}
}
- 流程节点绑定实现了JavaDelegate的类
- 部署流程,查看日志,正常输出了
流程变量
Flowable 的 RuntimeService
和 TaskService
提供了变量管理功能,其中变量分为 全局变量(Process Variables) 和 局部变量(Local Variables),但它们的存储范围、生命周期和适用场景有所不同。
1. 变量作用域
Flowable 变量存储在不同的作用范围内,分为以下三种层次:
变量类型 | 绑定对象 | 生命周期 | 适用场景 |
---|---|---|---|
流程变量(全局变量) | ProcessInstance | 流程结束前一直有效 | 订单号、请假天数等流程级共享数据 |
执行变量(局部变量) | Execution | 绑定到 Execution ,不会随任务结束清除 | 某个流程分支使用的数据 |
任务变量(局部变量) | Task | 任务结束后自动清除 | 任务审批意见、表单临时数据 |
2. 全局变量(Process Variables)
全局变量 绑定到整个流程实例(ProcessInstance),可以在整个流程的 不同任务和执行路径 之间共享。
✅ 特点
- 作用范围:整个流程实例,包括所有任务、执行路径。
- 生命周期:流程实例存续期间,变量存在;流程结束后,变量被清理。
📌 设置全局变量
- 使用
RuntimeService
runtimeService.setVariable(processInstanceId, "leaveDays", 5);
- 使用
DelegateExecution
在执行过程中设置全局变量
execution.setVariable("leaveDays", 5);
📌 获取全局变量
- 在任务中获取全局变量
Integer leaveDays = (Integer) runtimeService.getVariable(processInstanceId, "leaveDays");
✅ 适用场景
- 需要在整个流程中传递和共享的数据,如 订单 ID、申请人、审批状态 等。
3. 局部变量(Local Variables)
局部变量 只在当前任务(Task)或执行实例(Execution)有效,不会影响其他任务或执行路径。
✅ 特点
- 作用范围:仅限当前任务或执行实例,其他任务无法访问。
- 生命周期:任务变量随任务结束自动清除,而执行变量绑定到
Execution
,需要手动清除。
📌 设置局部变量
- 使用
TaskService
设置任务的局部变量
taskService.setVariableLocal(taskId, "approval", "approved");
- 使用
RuntimeService
设置 Execution 级别局部变量
runtimeService.setVariableLocal(executionId, "approval", "approved");
📌 获取局部变量
- 获取当前任务的局部变量
String approval = (String) taskService.getVariableLocal(taskId, "approval");
- 获取当前任务的所有局部变量
Map<String, Object> localVariables = taskService.getVariablesLocal(taskId);
✅ 适用场景
- 仅在某个任务或节点有效的临时数据,如 审批意见、表单数据。
4. RuntimeService
局部变量的特点
在 Flowable 中,runtimeService.setVariableLocal(executionId, key, value)
绑定变量到当前 Execution
,但:
Execution
可能被多个任务共享,因此变量不会因为某个任务完成而被清除。- 只有当 该
Execution
结束(例如分支合并、流程结束)时,变量才会被删除。
📌 示例:RuntimeService 局部变量在任务完成后仍然存在
// 1. 启动流程
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveProcess");// 2. 获取 Execution ID
Execution execution = runtimeService.createExecutionQuery().processInstanceId(processInstance.getId()).onlyChildExecutions().singleResult();
String executionId = execution.getId();// 3. 在 Task A 设置局部变量
runtimeService.setVariableLocal(executionId, "approval", "approved");// 4. 完成 Task A
Task taskA = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
taskService.complete(taskA.getId());// 5. Task B 仍然能访问变量
Task taskB = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
String approvalStatus = (String) runtimeService.getVariable(executionId, "approval");
System.out.println("Task B 仍然可以获取 approval 变量: " + approvalStatus); // 仍然是 "approved"
✅ 结论:
RuntimeService
局部变量绑定到Execution
,任务完成后仍然存在。- 只有
Execution
结束时(流程完成或分支合并),变量才会消失。
5. 让变量在任务完成后消失
如果希望变量在任务完成后自动清除,有以下三种方法:
✅ 方法 1:使用 TaskService
设置任务局部变量
使用 taskService.setVariableLocal()
绑定变量到 Task
,变量在任务完成后自动清除:
taskService.setVariableLocal(taskId, "approval", "approved");
✅ 方法 2:手动删除 RuntimeService
局部变量
如果变量存储在 Execution
级别,可以在任务完成后手动删除:
runtimeService.removeVariableLocal(executionId, "approval");
✅ 方法 3:在任务监听器中删除变量
可以在 任务完成时 自动删除变量:
public class RemoveVariableTaskListener implements TaskListener {@Overridepublic void notify(DelegateTask delegateTask) {if (TaskListener.EVENTNAME_COMPLETE.equals(delegateTask.getEventName())) {delegateTask.removeVariableLocal("approval");}}
}
然后在 BPMN 任务节点中配置:
<extensionElements><flowable:taskListener event="complete" class="com.example.RemoveVariableTaskListener"/>
</extensionElements>
这样,每次任务完成时,局部变量都会自动删除。
6. 关键区别总结
方法 | 变量绑定对象 | 变量生命周期 | 变量是否随任务完成清除 |
---|---|---|---|
runtimeService.setVariable() | ProcessInstance | 流程结束 | ❌ 不会清除 |
runtimeService.setVariableLocal() | Execution | Execution 结束 | ❌ 任务完成后仍然存在 |
taskService.setVariableLocal() | Task | 任务完成 | ✅ 任务完成后自动清除 |
runtimeService.removeVariableLocal() | Execution | 立即删除 | ✅ 任务完成后消失 |
✅ 最佳实践
- 需要在整个流程共享的数据 →
runtimeService.setVariable()
- 仅当前任务使用的数据 →
taskService.setVariableLocal()
- 任务完成后删除 Execution 变量 →
runtimeService.removeVariableLocal()
- 任务监听器自动清除变量 → 配置
TaskListener
历史变量
表act_hi_varinst
存储了变量的历史记录,包含了与流程实例和任务相关的所有变量的详细信息。每个变量的每次变更(创建或更新)都会生成一条新的记录。
身份服务
候选人
流程节点中使用表达式配置三个候选用户,
配置保存后下载bpmn文件,拿到项目中,部署流程启动,会在act_ru_identitylink表中显示身份信息和对应的taskId
-
type的类型
TYPE_值 含义描述 candidate
表示用户或组是某个任务的候选人,意味着他们有可能执行该任务。 participant
表示用户或组是任务的实际参与者,即已经被分配并参与了任务。 starter
表示用户启动了一个流程实例,虽然不是直接与任务相关的身份链接类型。 assignee
表示单一用户的直接任务分配情况(不常见于 act_ru_identitylink
表)。
候选用户并不直接等于审批人
拾取操作
/*** 根据候选人查询待办信息* 候选人还不是审批人* 候选人通过拾取操作,把候选人变更为审批人* 多个候选人只能有一个可以变为审批人* 审批人如果不想审批,可以通过归还操作,把审批人变为候选人*/@Testvoid climTask(){//根据候选人查询List<Task> list = taskService.createTaskQuery().taskCandidateUser("zhangsan").list(); //查询候选人是houqi的,相关的待办信息list.forEach(task -> {//拾取操作,将候选人变为审批人taskService.claim(task.getId(),"zhangsan");});}
act_ru_identitylink表中不会变化,但是act_ru_task表中原本审批人是空的,拾取以后,已经更新成zhangsan了
归还操作
拾取操作后,执行归还操作
/*** 归还操作*/@Testvoid unclaimTask(){//houqi登录后,查询到自己相关的待办信息List<Task> list = taskService.createTaskQuery().taskAssignee("houqi").list();list.forEach(task -> {//归还操作,将审批人归还为候选人taskService.unclaim(task.getId());});}
指派
/*** 指派操作* 指派另一个用户来审批*/@Testvoid assignTask(){//zhangsan登录后,查询到自己相关的待办信息List<Task> list = taskService.createTaskQuery().taskAssignee("houqi").list();list.forEach(task -> {//当前任务,指定审批人taskService.setAssignee(task.getId(),"lisi");});}
候选人组
管理用户和组
- 用户维护
/*** 维护用户*/@Testvoid user() {User zhangsan = identityService.newUser("lisi");zhangsan.setFirstName("李四");zhangsan.setLastName("李四");zhangsan.setEmail("lisi@163.com");zhangsan.setPassword("123");identityService.saveUser(zhangsan);}
新增后在act_id_user
表中,
- 用户组的维护
/*** 用户组的维护*/@Testvoid group() {Group group = identityService.newGroup("group2");group.setName("组2");group.setType("type2");identityService.saveGroup(group);}
- 用户和用户组关联
/*** 用户和用户组关联*/@Testvoid userGroup() {//查询用户组 group1Group group = identityService.createGroupQuery().groupId("group1").singleResult();//用户和用户组关联identityService.createMembership("lisi", group.getId());}
关联关系在表act_id_membership
中
候选人组应用
- 管理端指定组
- 下载bpmn,移动到java中部署启动,
查看act_ru_identitylink表的身份信息,candidate候选人,groupId组
/*** 候选组*/@Testvoid queryTask() {//根据用户查询组Group group = identityService.createGroupQuery().groupMember("lisi").singleResult();//根据组查询待办信息List<Task> list = taskService.createTaskQuery().taskCandidateGroup(group.getId()) //根据候选人组查询待办信息.list();//拾取操作再指定给用户list.forEach(task -> {taskService.claim(task.getId(),"lisi");});}
网关服务
4种网关
排他网关
根据条件表达式的计算结果来决定流程的执行路径,只会走其中一个路径
- 排他网关流程
- 设置条件
请假少于3天,组长审批
请假大于等于三天,经理审批
- num设置为2,
进入了组长审批
- num设置为5,
进入了经理审批
- 如果没有符合条件的,会报错
并行网关
启动两个并行路径,这两个路径的任务都完成后,流程再次合并,继续进行
- 并行网关图
- 对应的表数据
因为这里是并行网关,所以用户审批通过以后,这个流程会产生两条任务记录
两条任务都审批完,就会到达合并的地方,又变成一个任务记录
包容网关
每个分支都有条件,如果符合多个条件,那么多个条件都要审批完成才能到下面的节点。
- 包容网关图
num值设置为5了,同时满足审批2和审批3的条件,所以就有两条审批任务
事件网关
这种类型的网关后面必须跟随中间捕获事件。流程会等待第一个发生的事件,然后按照对应的顺序流继续。
事件
定时器事件
- 特定时间触发的事件,
- 在流程部署就开始计时,不需要调用runtimeService.startProcessInstanceById就会在指定时间启动,如果单独去调用runtimeService.startProcessInstanceById,就会创建一个新的流程实例
- 开启
flowable:
async-executor-activate: true #是否开启异步任务,否则定时器不生效 - 重复部署同一个流程定义,旧的定时器事件会被覆盖
启动事件
-
定时器事件触发的三种方式:
类型 描述 示例 开始时间(ISO-8601) 指定一个具体的日期时间来触发定时器 2025-03-25T14:25:00:在这个时间触发 循环时间(例:R3/PT10H) 定义一个重复周期,用于定期触发定时器。可以使用ISO 8601格式表示重复周期。 R3/PT10S:每隔10s一次,共执行三次 持续时间(例:PT5M) 指定一个持续时间,在该持续时间后触发定时器。 PT5M:在当前时间点后的5分钟后触发 - 配置定时器启动事件,只需要部署流程,等待触发条件达成,就会自动启动流程。
- 配置定时器启动事件,只需要部署流程,等待触发条件达成,就会自动启动流程。
中间事件
流程执行到某一特定点时等待一个特定时间间隔或直到某个特定时间点的元素,再触发后续活动。
- 我这里设置的是10秒。申请出库操作完成后,就会等待10秒,才流转到出库节点。
申请出库节点
完成后,act_ru_task表中的这条数据就会清除,act_ru_timer_job表中会出现定时任务,会在DUEDATE_这个时间,继续流转到出库节点
,act_ru_task中有了节点数据
边界事件
当流程执行到达被附加的活动时,定时器开始计时,一旦满足了定时器设定的时间条件,就会触发相应的处理逻辑
- 流程图
拖动到流程节点上面,设置边界事件。
- 取消活动
不勾选取消活动:主流程继续执行,边界事件关联的流程也执行。
勾选取消活动:主流程直接结束,不再执行,只执行边界时间关联的流程。
- 事例中关联了一个服务任务
- 服务任务的实现类
import com.wzw.Log.ConsoleOutput; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.delegate.JavaDelegate; import org.slf4j.Logger; import org.slf4j.LoggerFactory;import java.time.LocalDateTime;/*** 自定义委托类* 实现接口JavaDelegate,*/ public class MySecondDelegate implements JavaDelegate {Logger log= LoggerFactory.getLogger(MySecondDelegate.class);/*** 回调方法* @param execution*/@Overridepublic void execute(DelegateExecution execution) {// 输出日志ConsoleOutput.output(log,"服务通知:"+ LocalDateTime.now());} }
- 服务任务关联实现类
- 服务任务的实现类
- 流程启动后,所在节点是合同审批,合同审批关联了边界事件。
- 如果边界事件勾选了取消活动,在这个节点停留超过10s,执行通知服务,然后结束流程,并且主流程终止,后续的财务审核将不会执行了。
- 如果边界事件没勾选取消活动,在这个节点停留超过10s,执行通知服务的同时,达到下个节点,继续执行财务审核
消息事件
启动事件
触发了启动事件,才能开始流程。
要设置消息引用,默认是没有的。可以在消息定义中设置
- 消息定义
空白处点击,找到属性中的消息定义
新增保存
- 绑定消息
消息定义中保存以后,在启动时间的消息引用就可以看到了
- 部署流程
流程部署以后,可以在表act_ru_event_subscr
中看到数据
然后就可以发送消息来激活启动这个流程 - 激活流程
/*** 发送消息,触发流程*/@Testvoid send() throws InterruptedException {ConsoleOutput.output(log,"发送消息");//这里参数是消息的nameruntimeService.startProcessInstanceByMessage("message01");Thread.sleep(50000);}
中间事件
流程执行到中间消息事件,需要发送消息触发以后,才能继续执行流程。
- 创建中间消息捕获事件
可以从左边选,也可以先创建一个定时器中间事件然后改成中间消息捕获事件。
- 消息定义然后绑定到中间消息捕获事件
- 在任务1完成审批后,需要等待发送消息触发中间消息事件以后,才能进行任务2
/*** 发送消息,触发中间事件流程*/@Testvoid middle() throws InterruptedException {ConsoleOutput.output(log,"发送消息");runtimeService.messageEventReceived("message02", "dae3583f-0a27-11f0-bdd2-00ff78cf2894");}
边界事件
- 消息边界事件绑定到流程节点
左边菜单中拖到对应的流程节点
- 绑定消息
- 服务通知绑定MyThreeDelegate
import com.wzw.Log.ConsoleOutput;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.time.LocalDateTime;/*** 自定义委托类* 实现接口JavaDelegate,*/
public class MyThreeDelegate implements JavaDelegate {Logger log= LoggerFactory.getLogger(MyThreeDelegate.class);/*** 回调方法* @param execution*/@Overridepublic void execute(DelegateExecution execution) {// 输出日志ConsoleOutput.output(log,"服务通知:"+ LocalDateTime.now());}
}
- 部署启动流程,节点就会停留在任务1,在这个阶段,发送消息,触发通知任务,然后分支结束,
/*** 发送消息,触发中间事件流程*/@Testvoid middle() throws InterruptedException {ConsoleOutput.output(log,"发送消息");runtimeService.messageEventReceived("message03", "bc1d4e56-0ab9-11f0-a07f-00ff78cf2894");}
- 这个事件是非中断事件,所以触发事件后任务1节点没变,可以继续执行
- 然后触发任务2的消息事件
/*** 发送消息,触发中间事件流程*/@Testvoid middle() throws InterruptedException {ConsoleOutput.output(log,"发送消息");runtimeService.messageEventReceived("message04", "66e20691-0ae6-11f0-b338-00ff78cf2894");}
- 这个事件是中断事件,所以主流程结束,进入分支,进入到任务3
错误事件
开始事件
用于启动一个子流程或边界事件处理的特殊类型开始事件。流程实例或子流程是因为捕获到某个错误而被触发启动的
。错误开始事件不能用于顶级流程
,即整个业务流程模型的起点不能是一个错误开始事件。
- 主流程,服务任务绑定类Err
- 错误事件不能用于顶级流程,先创建一个子流程
- 错误启动事件拖入子流程
- 服务任务绑定类
- 绑定错误异常
子流程错误异常开始事件触发的引用为:error1,需要在代码中抛出throw new BpmnError(“error1”)来触发
- 实例
- 流程启动后,直接来到服务任务1,服务任务1绑定了ServiceError1Delegate
public class ServiceError1Delegate implements JavaDelegate {Logger log = LoggerFactory.getLogger(ServiceError1Delegate.class);@Overridepublic void execute(DelegateExecution execution) {ConsoleOutput.output(log, "服务任务1:"+ LocalDateTime.now());//抛出对应异常,触发错误开始事件throw new BpmnError("error1");} }
- 服务任务1抛出了
BpmnError("error1")
,这个异常触发了子流程的错误引用指定的值,然后就开始执行子流程。
- 触发子流程以后,执行了服务任务2,服务任务2绑定了ServiceError2Delegate,最后主流程子流程都输出了服务任务
public class ServiceError2Delegate implements JavaDelegate {Logger log = LoggerFactory.getLogger(ServiceError2Delegate.class);@Overridepublic void execute(DelegateExecution execution) {ConsoleOutput.output(log, "服务任务2:"+ LocalDateTime.now());} }
- 流程启动后,直接来到服务任务1,服务任务1绑定了ServiceError1Delegate
边界事件
用于处理异常情况,附加在活动(如任务或子流程)上。并且仅在发生特定错误时触发。一旦被触发,当前的活动会被中断,流程会沿着与该错误边界事件关联的顺序流继续执行。
-
流程图
-
服务任务实现类
如流程图,任务实现类1抛出的是error2来触发import org.flowable.engine.delegate.BpmnError; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.delegate.JavaDelegate;import java.time.LocalDateTime;/*** 错误边界事件示例* 服务任务1*/ public class BoundaryDelegate1 implements JavaDelegate {@Overridepublic void execute(DelegateExecution execution) {System.out.println("错误边界事件1--------"+ LocalDateTime.now());throw new BpmnError("error2");} }
任务实现类2抛出的是error3来触发
public class BoundaryDelegate2 implements JavaDelegate {@Overridepublic void execute(DelegateExecution execution) {System.out.println("错误边界事件2--------"+ LocalDateTime.now());throw new BpmnError("error3");} }
其它实现类没有抛出异常
- 部署启动流程
- 任务1抛出error2,触发以后执行顺序是任务1-任务4
- 任务1的抛出注释掉,不抛出异常,任务2抛出error3,顺序应该是任务1-任务2-任务5
- 任务1抛出error2,触发以后执行顺序是任务1-任务4
结束事件
错误结束事件是一种特殊类型的结束事件,用于立即终止其所在的子流程或整个流程实例,并可选地抛出一个错误。该流程实例状态会被标记为错误结束。
-
流程图
子流程支付失败,触发错误边界事件,错误边界事件捕获后,重新触发支付子流程
-
部署
@Testvoid deploy() {Deployment deploy = repositoryService.createDeployment().addClasspathResource("process/01/event-error-end.bpmn20.xml").name("消息事件-错误结束事件").deploy();ConsoleOutput.output(log,"部署流程:"+deploy.getId());}
- 启动
@Testvoid start() throws InterruptedException {ConsoleOutput.output(log,"启动流程");runtimeService.startProcessInstanceById("event-error-end:1:89fdf554-1fe1-11f0-8acb-00155da42014");}
启动成功,当前节点是下单,审批人是zhangsan
- 审批下单节点
该流程主要是子流程验证结束事件,先把下单节点审批完,走到子流程,
@Testvoid complete() throws InterruptedException {ConsoleOutput.output(log,"审批");taskService.complete("ff9d042d-2009-11f0-976d-00155da42014");}
- 审批子流程的支付节点
审批完下单,就来到子流程的支付节点。
支付接下来涉及到网关,需要用到变量
设置变量然后继续审批,先设置为false,根据流程图,如果是false,就会重新走子流程,也就是说会到支付节点。审批看效果
/*** 设置变量,然后审批*/@Testvoid setVariable() throws InterruptedException {ConsoleOutput.output(log,"设置变量,然后审批");taskService.complete("06be7786-200b-11f0-9bcd-00155da42014", Map.of("payFlag",false));}
确实还在支付节点,触发了错误结束事件,流程结束,又指向到了子流程。
再改成true,审批通过,继续主流程了,和流程图一致
@Testvoid setVariable() throws InterruptedException {ConsoleOutput.output(log,"设置变量,然后审批");taskService.complete("bf2ad614-200b-11f0-9ff1-00155da42014", Map.of("payFlag",true));}
信号事件
用于在流程执行过程中,通知其它流程实例或任务实例。当其它触发的流程获取到信号事件,将被唤醒并继续执行。
信号事件是一种全局事件,可以在任何流程实例或任务重处罚和捕获。
开始事件
用于启动一个流程,当匹配到了触发条件,才会启动。
- 编辑流程图
编辑流程图,空白地方点击,属性中找到信号定义,创建一个信号定义
信号定义两个Scope属性:- Global Scope(全局范围):作用范围扩展到整个流程引擎的所有流程实例
- Process Scope(流程范围):仅限当前流程实例,信号的作用范围限制在当前流程实例内部,
然后选中启动事件,把刚才创建的信号定义和启动事件绑定
- 部署
@Testvoid deploy() {Deployment deploy = repositoryService.createDeployment().addClasspathResource("process/01/event-signal-start.bpmn20.xml").name("信号事件-开始事件").deploy();ConsoleOutput.output(log,"部署流程:"+deploy.getId());}
部署成功,事件会在表act_ru_event_subscr
中有记录
- 启动任务,三种方式
-
1.通过runtimeService中提供的API来发送信号
@Testvoid start1() throws InterruptedException {ConsoleOutput.output(log,"通过runtimeService中提供的API来发送信号");runtimeService.signalEventReceived("signal01");}
启动成功
-
2.通过其他流程实例中的信号中间抛出事件来触发
用户任务1审批完,触发信号抛出,而绑定的信号引用值如果一样,就会启动流程
-
3.作为普通的流程实例来启动即同
@Testvoid start2() throws InterruptedException {ConsoleOutput.output(log,"作为普通的流程实例来启动");runtimeService.startProcessInstanceById("event-signal-start:1:909d2a6d-2010-11f0-abc3-00155da42014");}
-
启动成功
中间事件
中间事件分为捕获事件和抛出事件
,流程流转到中间事件时候,会中断等待触发,一直到接收到响应的信号后,继续执行。
- 流程图
- 部署
@Testvoid deploy() {Deployment deploy = repositoryService.createDeployment().addClasspathResource("process/01/event-signal-mid.bpmn20.xml").name("信号中间事件").deploy();ConsoleOutput.output(log,"部署流程:"+deploy.getId());}
- 发起流程
@Testvoid start() {runtimeService.startProcessInstanceById("event-signal-mid:1:bdbc46ae-2015-11f0-852f-00155da42014");}
发起流程后,按照流程图,进行到用户任务1,正确
现在的节点是用户任务1,审批以后,到达信号抛出,没有阻塞,并且触发了信号捕获,所以服务任务1和服务任务2都执行了。
如果有其他流程已经部署,并且信号引用的值一样,作用范围是全局的,也会被处罚。
边界事件
依附在一个活动(如用户任务、服务任务等)上,并且可以在流程执行期间通过发送信号来触发。如果边界事件设置为中断,原流程就不会继续执行了,如果非中断,则分支和原流程都会执行
- 流程图
创建一个全局信号引用signal02,绑定到信号抛出事件和边界事件
- 部署
/*** 部署*/@Testvoid deploy() {Deployment deploy = repositoryService.createDeployment().addClasspathResource("process/01/event-singal-boundary.bpmn20.xml").name("信号边界事件").deploy();ConsoleOutput.output(log,"部署流程:"+deploy.getId());}
部署成功,表act_ru_event_subscr
中新增了信号事件
- 发起流程
/*** 发起流程*/@Testvoid start() {runtimeService.startProcessInstanceById("event-singal-boundary:1:8af798bd-230b-11f0-b4cb-00155da42014");}
流程发起后,进入到审批节点1.
- 触发边界事件
当前在审批节点1,通过API来触发信号,执行服务任务1- 触发信号signal02
成功触发,执行了服务任务1/*** 通过API触发信号* @throws InterruptedException*/@Testvoid start1() throws InterruptedException {ConsoleOutput.output(log,"通过runtimeService中提供的API来发送信号");runtimeService.signalEventReceived("signal02");}
因为是非中断事件,所以主流程还是会继续执行。
- 触发信号signal02
- 审批通过节点1
审批通过进入到子流程的审批节点2
/*** 审批流程*/@Testvoid complete() throws InterruptedException {taskService.complete("a4b43096-230b-11f0-9d7a-00155da42014");}
- 通过审批节点2,按照流程图,接下来就会执行信号抛出事件,然后执行中断的边界事件,主流程就结束了,应该到服务任务3,然后结束流程
- 审批节点2通过
主流程结束/*** 审批流程*/@Testvoid complete() throws InterruptedException {taskService.complete("164f5f78-230e-11f0-9309-00155da42014");}
可以看到控制台输出,执行了服务任务3,流程结束
- 审批节点2通过
其它事件
终止结束事件
用于立即结束整个流程或子流程。如果是在一个子流程中使用,则不会影响到外部更大的流程(除非整个流程只包含这一个子流程)。
如果勾选了终止所有,不管是否子流程,全都
-
- 主流程中触发
-
1.1 部署
/*** 部署流程*/@Testvoid deploy() throws InterruptedException {Deployment deploy = repositoryService.createDeployment().addClasspathResource("process/01/event-final-end.bpmn20.xml").name("其它事件-终止结束事件").deploy();System.out.println("------deploy:"+deploy.getId());}
-
1.2 启动
/*** 启动流程*/@Testvoid start() throws InterruptedException {ConsoleOutput.output(log,"启动流程");runtimeService.startProcessInstanceById("event-final-end:1:4c47f45a-2313-11f0-8cd7-00155da42014");}
启动成功
-
1.3 审批任务3,并设置flag为false,测试是否全部审批任务都终止
/*** 审批*/@Testvoid complete() throws InterruptedException {ConsoleOutput.output(log,"审批");taskService.complete("7c072891-2313-11f0-97f1-00155da42014", Map.of("flag","false"));}
流程正确,全都终止了
- 主流程中触发
-
- 子流程中触发(终止所有未勾选)
-
2.1 流程图
-
2.2 部署
/*** 部署流程*/@Testvoid deploy() throws InterruptedException {Deployment deploy = repositoryService.createDeployment().addClasspathResource("process/01/event-final-end2.bpmn20.xml").name("其它事件-终止结束事件(子流程,未勾选终止所有)").deploy();System.out.println("------deploy:"+deploy.getId());}
-
2.3 启动流程
/*** 启动流程*/@Testvoid start() throws InterruptedException {ConsoleOutput.output(log,"启动流程");runtimeService.startProcessInstanceById("event-final-end2:1:d2da608d-232e-11f0-8a62-00155da42014");}
-
2.4 审批任务3,进入子流程
/*** 审批*/@Testvoid complete() throws InterruptedException {ConsoleOutput.output(log,"审批");taskService.complete("e11d0abd-232e-11f0-9b84-00155da42014");}
-
2.5 审批子流程任务1,携带参数flag==false
/*** 审批*/@Testvoid complete() throws InterruptedException {ConsoleOutput.output(log,"审批");taskService.complete("1ca1dc8a-232f-11f0-b75c-00155da42014", Map.of("flag","false"));}
子流程被终止了,主流程的其它并行任务正常
-
- 子流程中触发(终止所有勾选)
勾选终止所有选项,更新流程图
- 3.1 部署
- 3.2 启动
- 3.3 流程任务1,携带flag==false
勾选终止所有,主流程的也被结束了
- 子流程中触发(终止所有勾选)
取消结束事件
取消结束事件只能与事务子流程(普通的子流程,勾选是事务子流程)一起使用。当流程执行到达取消结束事件时,会抛出一个取消事件,并且这个取消事件必须由取消边界事件(cancel boundary event)捕获。一旦取消事件被捕获,事务子流程将被取消,并触发补偿机制(compensation)。
- 流程图
子流程要勾选是事务子流程,服务任务勾选是否为补偿
- 部署
/*** 部署*/@Testvoid deploy() {Deployment deploy = repositoryService.createDeployment().addClasspathResource("process/01/event-cancel-end.bpmn20.xml").name("取消结束事件").deploy();ConsoleOutput.output(log,"部署流程:"+deploy.getId());}
- 启动
/*** 发起流程*/@Testvoid start() {runtimeService.startProcessInstanceById("event-cancel-end:1:58f474bf-2365-11f0-ad2d-00155da42014");}
按照流程图,启动后来到用户任务1的节点,正确
- 审批,接下来,排他网关需要变量flag,设置flag==false来进入取消结束事件
/*** 审批流程*/@Testvoid complete() throws InterruptedException {taskService.complete("680f2f69-2365-11f0-adde-00155da42014", Map.of("flag",false));}
- 按照流程图,走到了取消结束事件,就触发了取消边界事件,来到任务4,并触发了边界补偿事件,然后执行了补偿服务任务。
补偿事件是为那些已经成功完成的活动定义的“撤销”逻辑,具体数量取决于事务子流程中有多少个活动定义了补偿处理
补偿事件
补偿事件是一种特殊类型的捕获中间事件(Intermediate Catch Event),它可以与一个 已执行的活动(Activity) 关联。针对那些已经完成的活动执行特定的“补救措施”,例如:退款、释放资源、取消订单等
-
流程图
-
启动流程后,执行了订票任务和支付任务
-
支付任务抛出异常,触发错误边界事件,然后错误边界事件接下来触发补偿中间事件,
@Overridepublic void execute(DelegateExecution execution) {ConsoleOutput.output(log,"服务任务:支付");throw new BpmnError("error1");}
- 补偿中间事件触发补偿任务取消订票
其它
flowable的ProcessEngine、*Service注入失败
flowable注入失败,提示找不到processEngine
或者其他flowable的service
@Resourceprivate ProcessEngine processEngine;
原因:老一点的flowable依赖,使用的是spring.factories
进行自动装配,
springboot2采用spring.factories
进行自动装配,所以springboot2是正常的,但是springboot3采用org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件来进行自动装配。
- 解决方法
- 自己实现配置类
既然不支持,那就自己配置flowable的数据源,
添加了这个配置类,再次注入的时候就正常了package com.wzw.config;import com.alibaba.druid.pool.DruidDataSource; import jakarta.annotation.Resource; import org.flowable.engine.*; import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration public class FlowableConfig {@Resourceprivate DruidDataSource dataSource;@Beanpublic ProcessEngine processEngine() {//流程引擎的配置对象,关联相关的数据源ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration().setJdbcUrl(dataSource.getUrl()).setJdbcDriver(dataSource.getDriverClassName()).setJdbcUsername(dataSource.getUsername()).setJdbcPassword(dataSource.getPassword())//检查数据库是否已经存在,如果表结构不匹配(如表不存在或版本过低),会自动创建缺失的表或更新现有表结构.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);return cfg.buildProcessEngine();}@Beanpublic RepositoryService repositoryService(ProcessEngine processEngine){return processEngine.getRepositoryService();}@Beanpublic RuntimeService runtimeService(ProcessEngine processEngine){return processEngine.getRuntimeService();}@Beanpublic TaskService taskService(ProcessEngine processEngine){return processEngine.getTaskService();} }
- 更改版本
低版本的flowable和springboot2搭配使用,或者使用新版本的flowable和springboot3搭配使用
- 自己实现配置类
event definitions only allowed on start event if subprocess is an event subprocess
- Flowable 的规范要求:只有在事件子流程(Event Subprocess)的开始事件中才允许使用事件定义(如错误事件、消息事件等)。
在普通的子流程(Subprocess)中,开始事件不能包含任何事件定义。
提示11行有问题,11行是个子流程,查看一下流程图,确实是使用了一般子流程。
org.flowable.common.engine.api.FlowableException: Errors while parsing:
[Validation set: 'flowable-executable-process' | Problem: 'flowable-subprocess-start-event-event-definition-not-allowed'] : event definitions only allowed on start event if subprocess is an event subprocess - [Extra info : processDefinitionId = event-error-begin | processDefinitionName = event-error-begin | | id = sid-FD1ADCD3-7D60-4DF0-889B-13126F1F95F8 | ] ( line: 11, column: 87)
元素 ‘boundaryEvent’ 中必须包含属性 ‘attachedToRef’。
org.flowable.bpmn.exceptions.XMLException: javax.xml.transform.TransformerException: javax.xml.stream.XMLStreamException: org.xml.sax.SAXParseException; lineNumber: 24; columnNumber: 8; cvc-complex-type.4: 元素 'boundaryEvent' 中必须包含属性 'attachedToRef'。
根据提示信息,在流程文件24行,boundaryEvent边界事件必须关联一个任务节点。错误是因为缺少了attachedToRef。说明没有关联任务节点
<!-- 错误的--><boundaryEvent id="sid-27A25923-8FD5-4555-B40F-681C6CAAE171">
·····</boundaryEvent>
<!-- 正确的--><boundaryEvent id="sid-27A25923-8FD5-4555-B40F-681C6CAAE171" attachedToRef="sid-E8832ACC-B8C2-4CD2-AEF2-C31EEE87FCB3">
·····</boundaryEvent>
所有表信息
1. 流程定义相关表
表名 | 字段名 | 含义 | 说明 |
---|---|---|---|
ACT_RE_PROCDEF | ID_ | 流程定义ID | 唯一标识,格式如:myProcess:1:4 |
KEY_ | 流程定义Key | BPMN文件中定义的ID | |
NAME_ | 流程定义名称 | 流程定义的名称 | |
VERSION_ | 流程版本 | 每部署一次+1 | |
DEPLOYMENT_ID_ | 所属部署ID | 关联 ACT_RE_DEPLOYMENT | |
RESOURCE_NAME_ | 资源文件名 | 如:myProcess.bpmn20.xml |
2. 部署相关表
表名 | 字段名 | 含义 | 说明 |
---|---|---|---|
ACT_RE_DEPLOYMENT | ID_ | 部署ID | 每次部署的唯一ID |
NAME_ | 部署名称 | 可选,设置部署的名字 | |
DEPLOY_TIME_ | 部署时间 | 部署时间戳 |
3. 流程实例相关表
表名 | 字段名 | 含义 | 说明 |
---|---|---|---|
ACT_RU_EXECUTION | ID_ | 执行实例ID | 当前流程的运行实例 |
PROC_INST_ID_ | 流程实例ID | 关联流程实例 | |
ACT_ID_ | 当前活动ID | 正在执行的节点ID | |
IS_ACTIVE_ | 是否激活 | 用于判断是否激活状态 |
| ACT_RU_PROCESS_INSTANCE
| ID_
| 流程实例ID | 是 ACT_RU_EXECUTION
的子集 |
| | PROC_DEF_ID_
| 流程定义ID | 当前实例对应的定义 |
4. 任务相关表
表名 | 字段名 | 含义 | 说明 |
---|---|---|---|
ACT_RU_TASK | ID_ | 任务ID | 当前用户任务ID |
NAME_ | 任务名称 | 流程定义中任务节点的名称 | |
ASSIGNEE_ | 任务处理人 | 当前任务分配的用户 | |
EXECUTION_ID_ | 执行ID | 所属执行实例 | |
PROC_INST_ID_ | 所属流程实例ID |
5. 历史数据表
表名 | 字段名 | 含义 | 说明 |
---|---|---|---|
ACT_HI_PROCINST | ID_ | 流程实例ID | 已完成或进行中的流程实例记录 |
PROC_DEF_ID_ | 流程定义ID | 所属流程定义 | |
START_TIME_ , END_TIME_ | 开始/结束时间 | 流程实例执行时间 | |
START_USER_ID_ | 发起人 |
| ACT_HI_TASKINST
| ID_
| 任务ID | 历史任务记录 |
| | NAME_
| 任务名称 | |
| | ASSIGNEE_
| 任务处理人 | |
| | START_TIME_
, END_TIME_
| 执行时间 | |
6. 变量相关表
表名 | 字段名 | 含义 | 说明 |
---|---|---|---|
ACT_RU_VARIABLE | ID_ | 变量ID | |
NAME_ | 变量名称 | ||
TYPE_ | 类型 | string、long等 | |
EXECUTION_ID_ | 所属执行ID | ||
PROC_INST_ID_ | 所属流程实例ID | ||
TEXT_ , LONG_ 等 | 变量值 | 根据类型存储在不同字段 |
| ACT_HI_VARINST
| 类似字段 | 历史变量表 | |
7. 身份/用户/组表(可选模块)
表名 | 字段名 | 含义 | 说明 |
---|---|---|---|
ACT_ID_USER | ID_ , FIRST_ , LAST_ | 用户信息 | Flowable的用户数据 |
ACT_ID_GROUP | ID_ , NAME_ , TYPE_ | 用户组信息 |