背景
去年用一个人+AI给公司搭内部管理平台的时候,技术选型卡在工作流引擎上。请假、报销、招待费这些审批流程是刚需,绕不开。
一开始看的是Flowable,毕竟是Activiti原班人马做的,社区活跃、功能齐全。但研究了几天后我放弃了------一个简单的请假审批要搞懂几十张表、BPMN 2.0规范、各种部署模式,学习成本太高了。我只有一个人,没人能分担,时间上耗不起。
后来在Gitee上找国产方案,发现了Warm-Flow。试了一下,半天跑通了第一个流程。这篇聊聊我的选型思路和实际使用经验。
先看对比:7张表 vs 几十张表
Flowable完整部署后会创建将近80张表,就算精简版也有40多张。这些表覆盖流程定义、运行时实例、历史数据、身份管理、任务分配等方方面面。功能确实强大,但对于大多数审批场景来说太臃肿了。
Warm-Flow只有 7张核心表:
| 表 | 用途 |
|---|---|
| flow_definition | 流程定义(名称、编码、版本、定义JSON) |
| flow_node | 流程节点(开始、中间节点、网关、结束) |
| flow_skip | 节点跳转关系(通过/驳回的流转路径) |
| flow_instance | 流程实例(谁发起的、当前走到哪了) |
| flow_task | 审批任务(当前待审人、审批结果) |
| flow_his_task | 历史任务(审批轨迹回溯) |
| flow_user | 用户(参与流转的人员,可选) |
7张表,表名见名知意。相比之下Flowable的ACT_RU_EXECUTION、ACT_HI_IDENTITYLINK、ACT_GE_BYTEARRAY这些表名,没学过BPMN规范的话根本不知道是干嘛的。
表少的直接好处是维护成本低。 数据出了问题不用在几十张表里来回查,7张表的关系一两分钟就能理清。
其他维度的对比
学习曲线: Flowable需要理解BPMN 2.0标准(事件子流程、补偿边界事件、调用活动等概念),API层叠复杂。Warm-Flow只暴露5个Service(DefService、InsService、TaskService、NodeService、HisTaskService),命名方式跟Spring一贯风格一致,上手快很多。
集成方式: Flowable需要独立部署或者嵌入应用,配置一堆Environment和Engine。Warm-Flow一个Maven依赖加几行配置就启动了。
中国特色审批: 转办、委派、加签、减签、任意跳转------这些国产OA常见的操作,Warm-Flow直接封装好了。Flowable需要自己基于API二次开发。
信创适配: 如果甲方要求国产数据库(达梦、人大金仓、OceanBase),Warm-Flow原生支持,Flowable需要自己搞适配。
前端设计器: Flowable的官方UI还是AngularJS写的,前端得基于bpmn-js自己画。Warm-Flow自带Vue设计器,支持经典流程图和仿钉钉两种模式,Jar包直接引入就能用。
一句话总结:追求BPMN标准、复杂流程选Flowable;中小企业审批、快速交付选Warm-Flow。
快速上手三步
1. Maven依赖
xml
<dependency>
<groupId>org.dromara.warm</groupId>
<artifactId>warm-flow-mybatis-plus-sb-starter</artifactId>
<version>1.8.0</version>
</dependency>
我项目用的是MyBatis-Plus,如果你用JPA也有对应的starter,官方都提供了。
2. 配置
yaml
warm-flow:
enabled: true
banner: true
ui: true
key_type: SnowId19
logic_delete: true
data_source_type: mysql
再写个权限处理器,告诉引擎当前用户是谁:
kotlin
@Configuration
public class WarmFlowConfig {
@Bean
public PermissionHandler permissionHandler() {
return () -> SecurityContextHolder.getCurrentUserId();
}
}
3. 跑通第一个流程
Warm-Flow的流程定义用JSON,这点比Flowable的XML友好得多:
arduino
// 导入流程定义
String json = """
{
"flowName": "请假审批",
"flowCode": "leaveFlow",
"version": "1",
"nodeList": [
{"nodeType":0, "nodeCode":"start", "nodeName":"开始"},
{"nodeType":1, "nodeCode":"deptLeader", "nodeName":"部门经理审批"},
{"nodeType":2, "nodeCode":"end", "nodeName":"结束"}
],
"skipList": [
{"nowNodeCode":"start", "nextNodeCode":"deptLeader", "skipType":"PASS"},
{"nowNodeCode":"deptLeader", "nextNodeCode":"end", "skipType":"PASS"}
]
}""";
Definition def = defService.importJson(json);
defService.publish(def.getId());
// 启动流程
Instance ins = insService.start("业务ID", FlowParams.builder()
.flowCode("leaveFlow")
.handler("currentUserId")
.build());
// 审批通过
taskService.pass(ins.getCurrentTaskId(), "同意", null);
基本用法就这么点。从引入依赖到跑通,不踩坑的话两个小时够了。
实战:监听器改造做节点级追踪
说回我那个项目。Warm-Flow本身只管流转,但业务侧需要追踪"每个节点谁审的、什么结果、卡在哪了"。我在监听器上做了扩展。
设计思路
审批链路是:部门经理 → 总监 → 财务。每一步可能是单个人,也可能多人会签。需要一张辅助表记录每个节点的审批明细:
sql
CREATE TABLE approval_task_relation (
id BIGINT PRIMARY KEY,
instance_id BIGINT NOT NULL COMMENT '流程实例ID',
task_id BIGINT COMMENT '任务ID',
node_name VARCHAR(64) COMMENT '节点名称',
node_code VARCHAR(64) COMMENT '节点编码',
approver VARCHAR(64) COMMENT '审批人',
status VARCHAR(16) DEFAULT 'pending' COMMENT 'pending/pass/reject',
is_latest TINYINT DEFAULT 1 COMMENT '是否最新节点',
remark VARCHAR(500) COMMENT '审批意见',
create_time DATETIME,
update_time DATETIME
);
NodeCreate监听器
节点创建时触发,注入审批人信息:
- 解析当前节点配置的审批人(部门负责人/指定人/角色)
- 向
approval_task_relation插入记录 - 把上一步的
is_latest翻转为0
less
@Component("nodeCreateApprovalListener")
public class NodeCreateApprovalListener implements Listener {
@Override
public void notify(ListenerVariable var) {
Instance ins = var.getInstance();
Node node = var.getNode();
// 解析审批人------可能是指定人、部门负责人、角色
List<String> approvers = resolveApprovers(node);
for (String approver : approvers) {
// 插入审批记录
approvalTaskRelationService.save(new ApprovalTaskRelation()
.setInstanceId(ins.getId())
.setNodeName(node.getNodeName())
.setNodeCode(node.getNodeCode())
.setApprover(approver)
.setStatus("pending")
.setIsLatest(1));
}
// 翻转上一步的is_latest
approvalTaskRelationService.flipLatest(ins.getId());
}
}
NodeFinish监听器
节点完成时触发,更新审批结果。驳回时触发生成流程通知:
java
@Component("nodeFinishApprovalListener")
public class NodeFinishApprovalListener implements Listener {
@Override
public void notify(ListenerVariable var) {
Task task = var.getTask();
String result = task.getResult(); // "PASS" or "REJECT"
approvalTaskRelationService.updateStatus(
task.getInstanceId(), task.getNodeCode(),
result.equals("PASS") ? "pass" : "reject",
task.getRemark()
);
if ("REJECT".equals(result)) {
// 推送驳回通知,通知发起人
notificationService.sendRejectNotice(task);
}
}
}
在JSON里绑定:
json
{"nodeCode":"deptLeader", "nodeName":"部门经理审批",
"listenerType":"CREATE", "listener":"nodeCreateApprovalListener"},
{"nodeCode":"deptLeader", "listenerType":"FINISH",
"listener":"nodeFinishApprovalListener"}
这样任何时刻查approval_task_relation表就能看到:谁在哪个节点做了什么操作、当前卡在哪里、历史轨迹全量保留。
踩过的一个坑
Warm-Flow的def_json字段默认长度可能不够。复杂流程(多节点多网关)生成的JSON会很长,如果数据库字段是VARCHAR(2000)级别,导入时会被截断,然后流程跑一半报错。
解决: 检查数据库flow_definition表的def_json字段,至少设成TEXT类型,复杂流程用MEDIUMTEXT。
另外从1.7.0版本开始,Warm-Flow废弃了XML流程定义,统一用JSON。如果你看到网上旧教程还在讲XML,直接跳过不用管。
总结
Warm-Flow适合的场景很明确:中小型项目的审批流程,团队人少,追求快速交付。 它不是Flowable的替代品(复杂BPMN场景还是Flowable),但在它的目标场景里,体验确实比Flowable好得多。
如果你也在做类似的项目------内部管理系统、OA审批、报销流程------不妨试试。半天能跑通,比纠结Flowable的几十张表划算。
我在GitHub/Gitee上开源了一套完整的SpringBoot企业级项目,包含Warm-Flow的实际应用代码。感兴趣可以访问:gitee.com/yao113088/j...