告别 Flowable 28 张表的臃肿噩梦:7 张表搞定中国式复杂审批的国产轻量级工作流 Warm-Flow 深度实战
在企业级企业信息化与数字化中台系统的建设中,“审批流”几乎是绕不开的刚性需求。从常见的报销单审批、请假流转,到复杂的合同多级会签、加签撤回、退回任意节点,工作流引擎始终是业务架构的心脏。
然而,长期统治 Java 生态的工作流标准框架——Activiti、Flowable 与 Camunda,在带来标准化(BPMN 2.0)的同时,也为开发团队带来了难以承受的沉重负担:动辄 28 到 40 多张底层物理表、极其复杂的 XML 格式规范、难以捉摸的监听器生命周期,以及面对国内特有的“转办、会签、委派、驳回至指定人”等“中国式审批”场景时抓襟见肘的二次开发成本。

难道实现一个业务工作流,真的需要把系统搞得如此臃肿复杂吗?Dromara 开源社区孵化的国产轻量级工作流引擎 Warm-Flow(暖流) 给出了颠覆性的答案:仅用 7 张表,零 BPMN 学习成本,原生支持中国特色审批场景! 本文将从底层架构原理、表结构剖析、Spring Boot 3 集成实战到复杂审批逻辑演练,带你彻底搞懂并驾驭这款极简工作流引擎。
一、痛点反思:传统 BPMN 引擎为何成为团队的技术负债?
要理解 Warm-Flow 的价值,我们必须先看清传统工作流引擎(如 Flowable / Activiti)在日常业务系统中的几大痛点:
1. 表结构极其膨胀,排查运维宛如天书
Flowable 初始化后会建立多达 28+ 张 ACT_* 开头的系统表(包括 ACT_RU_* 运行时表、ACT_HI_* 历史表、ACT_RE_* 资源库表、ACT_GE_* 通用表等)。当线上发生一个卡单或节点卡死问题时,排障人员常常需要在 ACT_RU_TASK、ACT_RU_EXECUTION、ACT_RU_IDENTITYLINK 之间反复 JOIN,关联查询痛苦不堪。
2. 标准 BPMN 2.0 的“水土不服”
BPMN 2.0 是国际标准的工业流程建模规范,设计初衷是涵盖跨系统通信、补偿事务、事件网关等全量业务流程。但国内 90% 的企业办公场景本质上只是“以人为中心的任务流转(Human Task Flow)”。BPMN 中严苛的网关规则使得简单的“驳回上一节点”或“任意退回”都需要开发人员手写复杂的命令树(Command Executor)或操作 Execution 指针,极易引发死锁和数据不一致。
3. ORM 框架强绑定与侵入性过强
多数成熟 BPMN 引擎底层死死绑定在 MyBatis 原始 XML 体系上,在团队广泛拥抱 MyBatis-Plus、Spring Data JPA 甚至无实体持久层(如 Solon、Flex)时,无法实现无缝的语法统一与分页拦截复用。
二、Warm-Flow 核心设计:7 张表如何构建完整工作流闭环?
Warm-Flow 抛弃了晦涩沉重的 BPMN 2.0 规范,基于状态机(State Machine)思想,采用高内聚低耦合的数据模型。整套引擎仅依赖 7 张精简数据表,逻辑层次清晰分明:


7 张核心表职责矩阵:
| 表名 | 中文定义 | 业务职责与生命周期 |
|---|---|---|
flow_definition |
流程定义表 | 存储流程模版基础信息(编码、名称、状态、分类等) |
flow_node |
流程节点表 | 存储节点配置(开始、审批节点、网关分支、结束节点、审批人配置) |
flow_skip |
流程跳转条件表 | 定义节点间的连接线与流转规则(支持 SpEL 表达式过滤) |
flow_instance |
流程实例表 | 存储运行中的业务流程主记录(业务主键、当前状态、发起人、耗时) |
flow_task |
待办任务表 | 存储当前需要人工或系统处理的活动任务(执行人、任务状态) |
flow_his_task |
历史任务记录表 | 归档所有已流转完毕的任务快照(包含审批意见、处理人、操作时间) |
flow_user |
流程权限人表 | 存储流程设计期与运行时的候选人、候选组(支持部门、角色多维权限绑定) |
从上表可以看出:3 张表管理静态设计期(Definition/Node/Skip),3 张表管理动态运行时(Instance/Task/HisTask),1 张表管理用户关联(User)。没有繁琐的中间层,开发人员甚至用 Navicat 看一眼表数据,就能对全流程的运行状态一目了然!
三、Spring Boot 3 + Warm-Flow 极速落地实战
接下来,我们以一套标准的请假报销审批流为例,演示如何在 Spring Boot 3 工程中 10 分钟集成并运行 Warm-Flow。
1. 引入依赖与配置
在 Maven pom.xml 中引入 warm-flow-plugin-modes-sb 依赖(内置适配 MyBatis-Plus):
<dependencies>
<!-- Warm-Flow Spring Boot Starter -->
<dependency>
<groupId>org.dromara.warm</groupId>
<artifactId>warm-flow-mybatis-plus-sb-starter</artifactId>
<version>1.3.4</version>
</dependency>
<!-- 支持 SpEL 表达式计算 -->
<dependency>
<groupId>org.dromara.warm</groupId>
<artifactId>warm-flow-expression-spel</artifactId>
<version>1.3.4</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.7</version>
</dependency>
</dependencies>
在 application.yml 中开启自动建表:
warm-flow:
# 开启启动时自动初始化建表与升级
auto-ddl: true
# 表达式类型选择 SpEL
expression-type: spel
2. 流程定义装配(代码化定义或 JSON/Web 驱动)
除了使用官方配套的仿钉钉/飞书前端低代码设计器外,后端开发者可以直接通过 API 或 JSON 定义流程节点与跳转规则:
package com.skillup.warmflow.service;
import org.dromara.warm.flow.core.dto.FlowCombine;
import org.dromara.warm.flow.core.entity.Definition;
import org.dromara.warm.flow.core.entity.Node;
import org.dromara.warm.flow.core.entity.Skip;
import org.dromara.warm.flow.core.service.DefService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class WorkflowDeployService {
@Autowired
private DefService defService;
public void deployReimbursementFlow() {
FlowCombine combine = new FlowCombine();
// 1. 流程主定义
Definition def = defService.newDef();
def.setFlowCode("leave_reimbursement");
def.setFlowName("请假与报销审批流");
def.setVersion("1.0.0");
def.setIsPublish(1); // 立即发布生效
combine.setDefinition(def);
// 2. 装配节点:开始 -> 主管审批 -> 财务审批 -> 结束
List<Node> nodeList = new ArrayList<>();
Node startNode = createNode("start", "发起人提交", "start", null);
Node managerNode = createNode("manager_audit", "部门经理审批", "between", "manager_role");
Node financeNode = createNode("finance_audit", "财务总监审批", "between", "finance_role");
Node endNode = createNode("end", "流程归档", "end", null);
nodeList.add(startNode);
nodeList.add(managerNode);
nodeList.add(financeNode);
nodeList.add(endNode);
combine.setAllNodes(nodeList);
// 3. 装配跳转连线与条件(支持 SpEL 判断金额)
List<Skip> skipList = new ArrayList<>();
// start -> manager
skipList.add(createSkip("start", "manager_audit", "提交", null));
// manager -> finance (金额 > 1000 元需要财务审批)
skipList.add(createSkip("manager_audit", "finance_audit", "转入财务", "#{amount > 1000}"));
// manager -> end (金额 <= 1000 元经理审批完直接结束)
skipList.add(createSkip("manager_audit", "end", "直接归档", "#{amount <= 1000}"));
// finance -> end
skipList.add(createSkip("finance_audit", "end", "财务归档", null));
combine.setAllSkips(skipList);
// 部署入库
defService.insertFlowCombine(combine);
System.out.println(">>> 流程 [leave_reimbursement] 部署成功!");
}
private Node createNode(String code, String name, String type, String permission) {
Node node = defService.newNode();
node.setNodeCode(code);
node.setNodeName(name);
node.setNodeType(type);
if (permission != null) {
node.setPermissionFlag(List.of(permission));
}
return node;
}
private Skip createSkip(String nowCode, String nextCode, String name, String expr) {
Skip skip = defService.newSkip();
skip.setNowNodeCode(nowCode);
skip.setNextNodeCode(nextCode);
skip.setSkipName(name);
skip.setSkipType("PASS");
skip.setExpr(expr);
return skip;
}
}
3. 核心流转:发起、审批、条件分支流转
在业务 Controller 中注入 InsService(实例服务)与 TaskService(任务服务):
package com.skillup.warmflow.service;
import org.dromara.warm.flow.core.dto.FlowParams;
import org.dromara.warm.flow.core.entity.Instance;
import org.dromara.warm.flow.core.service.InsService;
import org.dromara.warm.flow.core.service.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class LeaveApprovalService {
@Autowired
private InsService insService;
@Autowired
private TaskService taskService;
/**
* 发起申请
*/
public Long submitLeave(String userId, String businessId, double amount) {
Map<String, Object> variables = new HashMap<>();
variables.put("amount", amount);
variables.put("submitter", userId);
FlowParams params = FlowParams.build()
.flowCode("leave_reimbursement")
.createBy(userId)
.variable(variables);
// 启动流程实例,业务主键绑定 businessId
Instance instance = insService.start(businessId, params);
System.out.println("流程启动成功,实例ID: " + instance.getId());
return instance.getId();
}
/**
* 经理审批并流转
*/
public void managerApprove(Long taskId, String managerId, boolean pass, String comment) {
FlowParams params = FlowParams.build()
.createBy(managerId)
.message(comment);
if (pass) {
// 通过当前节点,自动计算 SpEL 分支跳转
taskService.skip(taskId, params);
System.out.println("经理审批通过,流转下一节点");
} else {
// 驳回至开始节点或指定节点
taskService.termination(taskId, params);
System.out.println("经理驳回,流程终止");
}
}
}
四、中国式复杂审批特性:会签、委派、任意退回
Warm-Flow 在设计之初就深度考虑了国内办公自动化场景的特殊性:
1. 票签与会签(Countersign)
在传统 BPMN 中,多实例(Multi-Instance)会签是无数初学者的噩梦。Warm-Flow 原生提供多种表决策略: - 百分比票签(Percentage):例如当同意人数达到 70% 时自动推进; - 全票通过(All Pass):只要有一票拒绝立即终止; - 一人即过(Any Pass):类似或签机制。
只需在节点配置 collaborativeHandler 或会签属性,引擎自动在 flow_task 中管理子任务并汇总结果。
2. 任意退回(Any Node Return)
在审批过程中,领导常常提出“退回给发起人修改”,甚至“财务退回给经理重新审核”。 Warm-Flow 提供一行 API:
// 退回到指定前置节点 code
taskService.back(taskId, FlowParams.build().skipType("REJECT").nodeCode("start"));
引擎自动清除中间活动任务,恢复目标节点的待办状态,并将历史记录完整归档到 flow_his_task。
五、架构全维度基准选型对比
| 核心指标 | Activiti / Flowable 6.x | Camunda 7/8 | Warm-Flow 1.3+ |
|---|---|---|---|
| 底层核心表数量 | 28 ~ 42 张 | 30+ 张 (Camunda 8 引入 Zeebe) | 仅 7 张表 |
| JAR 依赖体积 | ~18 MB | ~25 MB | < 1.5 MB |
| 启动耗时 | 3.5s ~ 7.0s | 4.0s ~ 8.0s | 0.2s 极速冷启动 |
| 国内审批特性支持 | 需深度定制扩展 Command | 需二次开发 | 开箱即用(驳回、加签、减签) |
| 持久层适配 | MyBatis XML 强绑定 | MyBatis / 自研 Engine | 适配 MyBatis-Plus / JPA / Solon |
| 学习门槛 | 高(BPMN 2.0 规范体系) | 极高(Zeebe 分布式流) | 极低(30分钟掌握全部 API) |
六、总结与实操练习指引
工作流引擎的核心价值在于服务业务流转,而非制造技术壁垒。Warm-Flow 用 7 张表重新定义了国产 Java 工作流的优雅与精巧,无论是中小型 SaaS 产品、企业内部 OA 办公流,还是高吞吐的微服务调度,它都展现出了极强的适应力与维护幸福感。
为了让大家零门槛验证 Warm-Flow 的完整能力,我们整理了配套的完整实战工程源码,包含 Spring Boot 3 工程、内置 H2 嵌入式数据库、初始化表结构脚本与完整的审批流转单元测试用例:
- 配套开源实战工程:
labs/warm-flow-lightweight-engine/ - 在线实战演练与沙盒环境:欢迎访问 SkillUp 技术实训平台 (https://www.skillup.host/) 直接启动云端容器体验流程编排!
💻 配套实训环境与动手练习
本文涉及的相关技术指令、开发环境与工具链已内置在边学边练在线实验室中,无需繁琐安装配置,随时在浏览器中实践体验: