嘿,各位技术大佬们,今天我们来聊聊一个能让你在开发中“偷懒”的神器——Flowable。从此你将告别各种复杂的审批流程、状态机管理,告别手写 if-else
堆砌审批逻辑。
一、什么是 Flowable?它和 Activiti 是什么关系?
简单来说,Flowable 是从 Activiti “分支”出来的一个项目,而且是由 Activiti 的核心开发者们创建和维护的。
你可以把它们想象成两兄弟,Activiti 是哥哥,Flowable 是弟弟。在发展的过程中,弟弟 Flowable 显然更有活力,社区更活跃,功能迭代也更快,尤其是在与 Spring Boot 等现代技术栈的整合上,表现得更为出色。
二、Flowable 的“心脏”:核心组件探秘
要玩转 Flowable,得了解它的几个核心组件,它们就像是工作流引擎的“五脏六腑”,各司其职,共同协作。
-
ProcessEngine: 这是 Flowable 的绝对核心,可以理解为是所有服务的“总指挥官”。通过它,你才能获取到下面我们要说的各种 Service。
-
RepositoryService: 流程定义和部署的管理中心。比如,你想把画好的 BPMN 流程图部署到引擎中,就得靠它。它负责存储和管理流程的“蓝图”。
-
RuntimeService: 流程实例的“执行官”。当一个流程(比如,一个请假申请)被启动后,就变成了一个流程实例(Process Instance)。
RuntimeService
就是用来启动、查询和管理这些正在运行中的流程实例的。 -
TaskService: 任务管理的“专家”。在一个审批流中,大部分节点都是需要人来处理的,这些就叫做用户任务(User Task)。
TaskService
专门用来查询用户的待办任务、完成任务等。 -
HistoryService: “历史记录员”。所有已经完成的流程实例、任务、变量等信息,都会被它记录下来,方便你日后审计和追溯。
-
IdentityService: “身份认证专家”。虽然在实际项目中,我们通常会用自己的用户体系,但 Flowable 也提供了一套简单的用户和组管理功能。
-
FormService: “表单大师”。它可以帮你管理和渲染流程中用到的表单。
三、流程的“通用语言”:BPMN 核心元素
Flowable 使用 BPMN 2.0(业务流程模型和标记法)来定义流程。别被这个名字吓到,其实它就是一套用来画流程图的“通用语言”,而且非常直观。我们来看看最核心的几个元素:
-
事件 (Events):
-
开始事件 (Start Event): 每个流程的起点,用一个圆圈表示。
-
结束事件 (End Event): 流程的终点,用一个加粗的圆圈表示。
-
-
活动 (Activities):
-
用户任务 (User Task): 需要人工处理的节点,比如“部门经理审批”。这通常是我们交互最多的地方。
-
服务任务 (Service Task): 系统自动执行的任务,比如“发送邮件通知”。
-
-
网关 (Gateways):
-
排他网关 (Exclusive Gateway): 流程的分支点,根据条件只选择一条路径执行,就像
if-else
。例如,根据请假天数决定是经理审批还是总监审批。
-
-
顺序流 (Sequence Flow): 连接以上各个元素的“箭头”,定义了流程的执行顺序。
四、实战演练:设计一个最简单的审批流
光说不练假把式。我们来设计一个最简单的“请假审批”流程:员工发起申请 -> 经理审批 -> 结束。
1. 流程图
2. 对应的 BPMN 2.0 (XML 文件)
这个 XML 文件就是流程的“蓝图”,我们会把它部署到 Flowable 引擎中。文件名可以叫 leave-process.bpmn20.xml
。
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:flowable="http://flowable.org/bpmn"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.flowable.org/processdef">
<process id="leaveProcess" name="请假审批流程" isExecutable="true">
<startEvent id="startEvent" name="开始"/>
<sequenceFlow id="flow1" sourceRef="startEvent" targetRef="submitTask"/>
<userTask id="submitTask" name="提交请假申请" flowable:assignee="${applyUser}"/>
<sequenceFlow id="flow2" sourceRef="submitTask" targetRef="managerApproveTask"/>
<userTask id="managerApproveTask" name="经理审批" flowable:assignee="manager"/>
<sequenceFlow id="flow3" sourceRef="managerApproveTask" targetRef="endEvent"/>
<endEvent id="endEvent" name="结束"/>
</process>
</definitions>
注意: 在 submitTask
中,flowable:assignee="${applyUser}"
表示这个任务的负责人是一个叫 applyUser
的流程变量,这个变量在我们启动流程时传入。managerApproveTask
中,我们硬编码了审批人为 manager
。
Flowable 与 Spring Boot 的“天作之合”
第一步:添加依赖
在你的 pom.xml
文件中,加入 Flowable 的 Spring Boot Starter。
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.8.0</version> </dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
第二步:配置
在 application.properties
中,你几乎不需要做什么特殊配置,Flowable 会自动配置好数据源。如果你想看它执行的 SQL,可以加上日志配置。
Properties
# 自动创建和更新数据库表结构
spring.flowable.database-schema-update=true
第三步:把 BPMN 文件放对位置
Spring Boot Starter 会自动扫描 src/main/resources/processes
目录下的 .bpmn20.xml
文件,并在应用启动时自动部署它们。所以,把我们上面创建的 leave-process.bpmn20.xml
文件放在这个目录下。
代码实战:让流程“跑起来”!
现在,万事俱备,我们用 Java 代码来和这个流程交互。
1. 启动一个流程实例
我们可以写一个 Service 来封装流程操作。
import org.flowable.engine.RuntimeService;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.Map;
@Service
public class LeaveProcessService {
@Autowired
private RuntimeService runtimeService;
@Transactional
public void startLeaveProcess(String userId) {
Map<String, Object> variables = new HashMap<>();
variables.put("applyUser", userId); // 设置发起人
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveProcess", variables);
System.out.println("成功启动流程,流程实例ID: " + processInstance.getId());
}
}
2. 查询当前用户的待办任务
当流程启动后,“提交请假申请”这个任务就创建了,并且分配给了我们传入的 userId
。现在我们来查一下他的待办。
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class LeaveTaskService {
@Autowired
private TaskService taskService;
public List<Task> getMyTasks(String assignee) {
return taskService.createTaskQuery().taskAssignee(assignee).list();
}
// 完成任务
@Transactional
public void completeTask(String taskId) {
taskService.complete(taskId);
System.out.println("任务 " + taskId + " 已完成!");
}
}
调用示例
// 假设有个 Controller
@RestController
public class LeaveController {
@Autowired
private LeaveProcessService processService;
@Autowired
private LeaveTaskService taskService;
// 员工 "zhangsan" 提交申请
@PostMapping("/leave/start")
public String startLeave(@RequestParam String userId) {
processService.startLeaveProcess(userId);
return "请假流程已启动.";
}
// 查询 "zhangsan" 的待办
@GetMapping("/leave/tasks")
public List<String> getTasks(@RequestParam String userId) {
List<Task> tasks = taskService.getMyTasks(userId);
return tasks.stream().map(task -> "任务ID: " + task.getId() + ", 任务名称: " + task.getName()).collect(Collectors.toList());
}
// "zhangsan" 完成提交任务
@PostMapping("/leave/complete/{taskId}")
public String completeTask(@PathVariable String taskId) {
taskService.completeTask(taskId);
return "任务 " + taskId + " 已提交,等待经理审批。";
}
}
当 “zhangsan” 完成了他的提交任务后,流程会自动流转到“经理审批”节点,此时我们用 getTasks("manager")
就能查到经理的待办任务了。
五、进阶玩法:多级审批和流程监听器
1. 多级审批:员工 -> 部门经理 -> HR
如果请假天数大于3天,需要HR审批,怎么搞?很简单,加一个排他网关就行了。
流程图
BPMN 实现
这需要在BPMN中增加一个 exclusiveGateway
,并为流出的 sequenceFlow
添加 conditionExpression
。
<exclusiveGateway id="daysCheck" name="检查请假天数"/>
<sequenceFlow sourceRef="managerApproveTask" targetRef="daysCheck"/>
<sequenceFlow sourceRef="daysCheck" targetRef="hrApproveTask">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${approved == true && days > 3}]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="daysCheck" targetRef="endEvent">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${approved == true && days <= 3}]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="managerApproveTask" targetRef="submitTask">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${approved == false}]]>
</conditionExpression>
</sequenceFlow>
<userTask id="hrApproveTask" name="HR审批" flowable:assignee="hr"/>
在经理审批时,需要设置流程变量 approved
(true/false) 和 days
。
2. 流程监听器:在流程中“搞点事情”
有时候,我们想在流程的某个特定时刻(比如任务创建时、流程结束时)自动执行一些业务逻辑,比如发送通知、更新业务数据等。这时,Listener
就派上用场了。
Flowable 支持两种主要的监听器:ExecutionListener
(监听流程执行路径)和 TaskListener
(监听任务生命周期)。
示例:实现一个任务创建监听器
我们想在“经理审批”这个任务被创建时,自动发一条通知。
创建一个实现了 TaskListener
接口的类:
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
public class ManagerTaskCreateListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
// 在这里写你的业务逻辑
System.out.println("============== 经理审批任务创建了! ==============");
String applyUser = (String) delegateTask.getVariable("applyUser");
System.out.println("申请人是: " + applyUser);
System.out.println("请经理尽快审批!发送通知...");
// 实际场景下可能是调用钉钉、企业微信或者邮件的API
}
}
在 BPMN 文件的 userTask
中配置这个监听器:
<userTask id="managerApproveTask" name="经理审批" flowable:assignee="manager">
<extensionElements>
<flowable:taskListener event="create" class="com.yourpackage.ManagerTaskCreateListener"/>
</extensionElements>
</userTask>
这样,每次流程流转到“经理审批”节点并创建任务时,ManagerTaskCreateListener
中的 notify
方法就会被自动调用。
总结
Flowable 的功能远不止于此,它还支持并行网关、子流程、动态流程等等强大的功能。
但掌握了今天的内容,你已经足以应对 80% 的审批流需求了。剩下的 20%,就留给你在实践中继续探索和发现了。
工具是用来解放生产力的。别再让复杂的审批流拖慢你开发的脚步,是时候让 Flowable 登场,帮你“一键搞定”了!