36-FlowableProcessService:核心封装的方法地图
308行封装了Flowable五大Service的全部常用操作——startProcess/completeTask/退回/驳回/跳转/撤回/待办已办。这篇先给全方法地图,重点拆completeTask的三段式(前置拦截→complete→后置通知)和nextid变量法的退回驳回。
文章目录
- 36-FlowableProcessService:核心封装的方法地图
-
- 一、方法地图
- 二、completeTask的三段式
- 三、nextid变量法:不用改BPMN的流转控制
- 四、jumpToNode:引擎级的任意跳转
- 五、findFirstUserTask:找起点的两层降级
- 六、@Autowired(required=false)的两个可选依赖
源码:browise-workflow/src/main/java/com/browise/workflow/service/FlowableProcessService.java(308行)
一、方法地图
| 流程 | startProcess | runtimeService.startProcessInstanceByKey |
| 任务 | completeTask | taskService.complete(含拦截/通知) |
| claimTask / unclaimTask | 认领/取消 | |
| delegateTask / transferTask | 委派/转办 | |
| 退回 | backToPrevious | nextid变量法(第38篇专述) |
| 终结 | finishProcess(通过) | nextid=endEvent+approved=true |
| rejectProcess(驳回) | nextid=endEvent+approved=false | |
| cancelProcess / withdrawProcess | deleteProcessInstance | |
| 跳转 | jumpToNode | ChangeActivityStateBuilder |
| 查询 | getTodoTasks×2 / getDoneTasks | assignee/candidate/历史 |
| 部署 | deploy / getProcessDiagram / getTasksForDiagram | 仓库/图(第42篇) |
二、completeTask的三段式
public void completeTask(String taskId, Map<String, Object> variables) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
String procInstId = task.getProcessInstanceId();
String taskDefKey = task.getTaskDefinitionKey();
// ───── 第一段:前置拦截器 ─────
if (interceptorChainService != null && ...) {
String procDefKey = getProcessDefKey(procInstId);
interceptorChainService.executeBefore(procDefKey, taskDefKey, taskId, procInstId, variables);
}
// ───── 第二段:引擎推进 ─────
taskService.complete(taskId, variables);
// ───── 第三段:后置拦截器 + 下一任务处理人通知 ─────
if (interceptorChainService != null && ...) {
interceptorChainService.executeAfter(...);
}
if (notifyService != null) {
List<Task> nextTasks = taskService.createTaskQuery()
.processInstanceId(procInstId).active().list(); // complete后的活动任务=新节点
for (Task nt : nextTasks) {
notifyService.sendMessage(nt.getAssignee(), procInstId, "新待办: …");
}
}
}
前置拦截的业务场景——审批通过前校验业务状态(如“参保状态必须是正常”)、锁定数据防并发改。
后置拦截——审批后写业务表(更新参保登记状态)、触发下游(待遇核定)。
第三段通知的时机微妙——complete之后查询active任务,查到的是下一节点的任务(当前任务已完成不在active里)。如果流程走到排他网关,complete返回时路由已定——新任务已产生——查询即得。如果下一节点是并行网关——多个新任务都查到——逐个通知。
try-catch ignored包住通知——通知失败不阻断审批(审批已完成,通知是锦上添花)。第43篇讲Spring事件版本的事务后推送——那是更严谨的方案。
三、nextid变量法:不用改BPMN的流转控制
第37篇专述的机制先给结论——所有特殊流转(退回/通过/驳回)都是“设变量+complete”:
// 退回发起人
runtimeService.setVariable(executionId, "nextid", firstTask.getTaskDefinitionKey());
runtimeService.setVariable(executionId, "user", startUserId);
taskService.complete(taskId);
// 正常结束(通过)
runtimeService.setVariable(executionId, "nextid", "endEvent");
runtimeService.setVariable(executionId, "approved", true);
taskService.complete(taskId);
BPMN网关的条件表达式读nextid——#{nextid == 'usertask1'}决定流转方向。引擎不知道“退回”这个概念——它只看到变量+complete,按网关条件走。退回逻辑全部在应用层,流程图定义保持标准。
四、jumpToNode:引擎级的任意跳转
public void jumpToNode(String taskId, String targetActivityId) {
runtimeService.createChangeActivityStateBuilder()
.processInstanceId(task.getProcessInstanceId())
.moveActivityIdTo(task.getTaskDefinitionKey(), targetActivityId)
.changeState();
}
ChangeActivityStateBuilder是Flowable 6.x的官方API——把当前活动移到目标活动,不走BPMN连线、不触发网关判断。和nextid变量法的区别:
| 依赖 | BPMN网关写好条件 | 无需改BPMN |
| 路径 | 按连线走(可经过网关) | 直接瞬移 |
| 变量副作用 | 网关沿途可读变量 | 原样保留 |
| 适用 | 流转可预见(退回/驳回) | 管理员强制干预 |
jumpToNode是管理员兜底工具——流程卡死(变量缺失/网关死路)时强制挪节点。业务代码不该日常用它——瞬移绕过一切校验(网关条件、边界事件、监听器)。
五、findFirstUserTask:找起点的两层降级
private HistoricTaskInstance findFirstUserTask(String processInstanceId) {
// ①历史任务按结束时间升序——第一个完成的就是首节点
List<HistoricTaskInstance> histTasks = historyService...
.finished().orderByHistoricInstanceEndTime().asc().list();
if (!histTasks.isEmpty()) return histTasks.get(0);
// ②无历史(流程刚启动还没人完成过任务)——查活动任务
List<Task> activeTasks = taskService...orderByTaskCreateTime().asc().list();
// 取未完成的历史单条
}
为什么按EndTime不按CreateTime——并行网关下首节点和第二节点可能同时创建——CreateTime排序可能第二节点在前。EndTime保证“最先完成的”——发起人提交必然是第一个完成的动作。
退回到“发起时的第一个用户任务”而不是“上一个任务”——政务语义:退回=打回重报,不是“退一步改改”。
六、@Autowired(required=false)的两个可选依赖
@Autowired(required = false)
private InterceptorChainService interceptorChainService;
@Autowired(required = false)
private WorkflowNotifyService notifyService;
可选注入——workflow模块被裁剪装配时(只要引擎不要拦截/通知),服务照样能跑。completeTask里的null检查对应这个设计。模块内也保持松耦合——拦截器链和通知是增强不是依赖。
✅ 亮点:308行的方法地图+completeTask三段式逐段拆、通知查询active任务拿到的是下一节点任务、nextid变量法与jumpToNode的适用对照、findFirstUserTask按EndTime排序的并行网关细节。适合封装流程引擎的人。扩展方向:第37篇nextid专述、第38篇退回驳回、第41篇拦截器链。




