Flowable
Flowable是一个使用Java编写的轻量级业务流程引擎。Flowable流程引擎可用于部署BPMN 2.0流程定义(用于定义流程的行业XML标准), 创建这些流程定义的流程实例,进行查询,访问运行中或历史的流程实例与相关数据。
节点绘图流程:
目前的功能:
- 流程定义设计
- 流程 缺失或待改进的功能:
- 定义流程模型时,只能用
${}
变量插值符号来引入,这涉及到需要修改后端编码 - 发起事务后没有撤销实例的接口或操作。
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
中。具体步骤如下:
- 声明 Method 对象:
Method method;//Method 是 Java 反射(Reflection)API 中的一个类,属于 java.lang.reflect 包。它表示的是类或接口中的某个具体方法的抽象。通过 Method 对象,程序可以在运行时动态地调用某个对象的方法,而不需要在编译时明确地知道这个方法的名称或签名。
这里声明了一个 Method
对象,用于后续动态调用 guideScreen
对象的 getTaskUserX
方法。
- 循环获取
taskUser1
,taskUser2
,taskUser3
:
for (int i = 1; i <= 3; i++) {
这个循环从 i=1
开始,直到 i=3
,也就是循环三次,用来依次处理 taskUser1
, taskUser2
, 和 taskUser3
。
- 动态获取方法并调用:
method = guideScreen.getClass().getMethod("getTaskUser" + i);
在循环内部,通过字符串拼接的方式动态生成方法名,比如当 i=1
时,方法名就是 getTaskUser1
。接着使用反射机制获取这个方法。
- 调用方法并处理结果:
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
属性。
- 异常处理:
} 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任务点监听
任务监听器类型
-
create:在任务创建且所有任务属性设置完成之后才触发。
-
assignment:在任务被分配给某个班里人之后触发,它是在create事件触发前被触发。
-
complete:在配置了监听器的任务完成时触发,也就是说运行期任务删除之前触发。
-
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;
}