跳到主要内容

Flowable

提示

Flowable是一个使用Java编写的轻量级业务流程引擎。Flowable流程引擎可用于部署BPMN 2.0流程定义(用于定义流程的行业XML标准), 创建这些流程定义的流程实例,进行查询,访问运行中或历史的流程实例与相关数据。

节点绘图流程:

目前的功能:

  • 流程定义设计
  • 流程 缺失或待改进的功能:
  1. 定义流程模型时,只能用${}变量插值符号来引入,这涉及到需要修改后端编码
  2. 发起事务后没有撤销实例的接口或操作。

flowable 任务多实例

概念部分

  • 会签:指同一个审批节点设置多个人,如ABC三人,三人会同时收到审批,需全部同意之后,审批才可到下一审批节点;

  • 或签:指同一个审批节点设置多个人,如ABC三人,三人会同时收到审批,只要其中任意一人审批即可到下一审批节点。

如果一个活动是多实例,将通过在该活动底部的三条短线表示。三条竖线代表实例会并行执行,而三条横线代表顺序执行。

例如上面流程,在设置一级部门初审时,设置全局流程变量为列表,对或签的审核人员进行安排。其中需要注意的是完成条件设置为1,代表只要列表用户中存在一人通过审核即可进行下个流程。会签选择100%即可

代码部分

if (Func.isEmpty(guideScreen.getId())) {
// 保存guideScreen,写入id,createUser等基本表信息
save(guideScreen);
List<String> taskUserList = new ArrayList<>();
Method method;
//读取对象中的taskUser1,taskUser2,taskUser3
for (int i = 1; i <= 3; i++) {
try {
method = guideScreen.getClass().getMethod("getTaskUser" + i);
//获取taskUser1,taskUser2,taskUser3
if (Func.isNotEmpty(method.invoke(guideScreen))) {
taskUserList.add(TaskUtil.getTaskUser(method.invoke(guideScreen).toString()));
} else {
break;
}
} catch (Exception e) {
log.error("获取taskUser{}失败", i);
e.printStackTrace();
}
}
// 启动流程
Kv variables = Kv.create()
.set(ProcessConstant.TASK_VARIABLE_CREATE_USER, AuthUtil.getUserName())
.set("taskUserList", taskUserList)
.set("auditUser", TaskUtil.getTaskUser(Func.toStr(guideScreen.getAuditUser())));
R<BladeFlow> result = flowClient.startProcessInstanceById(guideScreen.getProcessDefinitionId(), FlowUtil.getBusinessKey(businessTable, String.valueOf(guideScreen.getId())), variables);
if (result.isSuccess()) {
log.debug("引导屏审核流程已启动,流程ID:{}", result.getData().getProcessInstanceId());
// 返回流程id写入guideScreen
guideScreen.setProcessInstanceId(result.getData().getProcessInstanceId());
updateById(guideScreen);
} else {
System.out.println(result.getMsg());
throw new ServiceException("开启引导屏审核流程失败");
}
}else {
updateById(guideScreen);
}

需要注意的代码的功能是从 guideScreen 对象中读取 taskUser1, taskUser2, taskUser3 这三个属性的值,并将这些值处理后添加到 taskUserList 中。具体步骤如下:

  1. 声明 Method 对象:
Method method;//Method 是 Java 反射(Reflection)API 中的一个类,属于 java.lang.reflect 包。它表示的是类或接口中的某个具体方法的抽象。通过 Method 对象,程序可以在运行时动态地调用某个对象的方法,而不需要在编译时明确地知道这个方法的名称或签名。

这里声明了一个 Method 对象,用于后续动态调用 guideScreen 对象的 getTaskUserX 方法。

  1. 循环获取 taskUser1, taskUser2, taskUser3:
for (int i = 1; i <= 3; i++) {

这个循环从 i=1 开始,直到 i=3,也就是循环三次,用来依次处理 taskUser1, taskUser2, 和 taskUser3

  1. 动态获取方法并调用:
method = guideScreen.getClass().getMethod("getTaskUser" + i);

在循环内部,通过字符串拼接的方式动态生成方法名,比如当 i=1 时,方法名就是 getTaskUser1。接着使用反射机制获取这个方法。

  1. 调用方法并处理结果:
if (Func.isNotEmpty(method.invoke(guideScreen))) {
taskUserList.add(TaskUtil.getTaskUser(method.invoke(guideScreen).toString()));
} else {
break;
}

使用 method.invoke(guideScreen) 调用获取的 getTaskUserX 方法,取得返回值。

  • 如果该返回值不为空(通过 Func.isNotEmpty() 判断),则调用 TaskUtil.getTaskUser() 进行处理,并将结果添加到 taskUserList 中。

  • 如果该返回值为空,则跳出循环,不再处理后续的 taskUserX 属性。

  1. 异常处理:
} catch (Exception e) {
log.error("获取taskUser{}失败", i);
e.printStackTrace();
}

如果在获取方法或调用方法的过程中出现任何异常,代码会捕获并记录错误日志,日志信息中会标明是哪个 taskUser 读取失败,同时打印异常堆栈跟踪信息。

设置流程变量的四种方式

流程设计分为三种:

  • 全局流程变量:在整个流程执行期间,这个流程变量都是有效的。

  • 本地流程变量:这个只针对流程中某一个具体的 Task(任务)有效,这个任务执行完毕后,这个流程变量就失效了。

  • 临时流程变量:顾名思义就是临时的,这个不会存入到数据库中。

全局流程变量设计

启动前设置

Kv variables = Kv.create()
.set(ProcessConstant.TASK_VARIABLE_CREATE_USER, AuthUtil.getUserName())
.set("taskUserList", taskUserList)
.set("auditUser", TaskUtil.getTaskUser(User.toString));
R<BladeFlow> result = flowClient.startProcessInstanceById(Id,variables);

当变量是对象时候记得传能够序列化,即实现了 Serializable 接口,具体变量存储表位置在ACT_HI_VARINST 是存储流程执行的历史信息的,ACT_RU_VARIABLE 则是保存流程运行时候的信息的。

相关查询查阅:

Flowable 设置流程变量的四种方式详解_flowable 流程变量-CSDN博客

通过 Task 设置(启动成功后设置)

taskService.setVariables(task.getId(),variables);//读取Task用set方法即可设置

完成任务时设置

Map<String, Object> variables = flow.getVariables();
if (variables == null) {
variables = Kv.create();
}
variables.put(ProcessConstant.PASS_KEY, flow.isPass());
// 完成任务
taskService.complete(taskId, variables);//使用complete函数

通过RuntimeService设置

Execution execution = runtimeService.createExecutionQuery().singleResult();
runtimeService.setVariable(execution.getId(), "days", 10);
Map<String, Object> variables = new HashMap<>();
variables.put("reason", "休息一下");
variables.put("startTime", new Date());
runtimeService.setVariables(execution.getId(), variables);

本地流程变量

本地流程也就是每个Task的专属变量,通过这个Task会释放这个变量

Task任务点监听

任务监听器类型

  1. create:在任务创建且所有任务属性设置完成之后才触发。

  2. assignment:在任务被分配给某个班里人之后触发,它是在create事件触发前被触发。

  3. complete:在配置了监听器的任务完成时触发,也就是说运行期任务删除之前触发。

  4. delete:任务删除触发

实例删除思路

public boolean deleteProcessGuideScreen(String processInstanceId) {
// 获取业务表
String businessTable = FlowUtil.getBusinessTable(ProcessConstant.GUIDE_SCREEN_KEY);

if (Func.isNotEmpty(businessTable)) {
// 删除业务数据,并检查是否成功
int rowsAffected = baseMapper.deleteByProcessInstanceId(processInstanceId);

if (rowsAffected <= 0) {
log.error("删除业务数据失败,流程实例ID: {}", processInstanceId);
return false;
// 删除业务数据失败,返回false
}

// 删除流程数据
R result = flowClient.deleteProcessInstance(processInstanceId, "删除流程实例");

if (result.isSuccess()) {
log.info("删除流程实例成功,流程实例ID: {}", processInstanceId);
return true;
// 成功删除流程实例,返回true
} else {
log.error("删除流程实例失败,流程实例ID: {}", processInstanceId);
return false;
// 删除流程实例失败,返回false
}
}

// 如果业务表为空,直接返回true
return true;
}