Flowable工作流
工作流引擎是企业级应用中处理复杂业务流程的强大工具,而Flowable作为开源的工作流引擎,以其轻量、高性能的特点被广泛应用。
本文将通过一个实际的审批场景,带你从0开始了解Flowable的价值和使用方式。
一、工作流的本质
工作流系统本质上是一个流程编排和任务管理工具 ,它负责:
- 流程状态的管理(启动、运行、暂停、结束)
- 任务的分配和流转
- 审批规则的执行
- 流程历史的记录
- 权限和角色的控制
二、场景引入:请假审批流程
我们以一个常见的请假审批场景为例:
-
员工提交请假申请
-
部门经理审批
-
审批通过后,记录请假信息
三、传统实现方式:前后端直接处理
1. 数据库设计
首先,我们需要设计一个请假申请表:
CREATE TABLE `leave_application` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`employee_id` BIGINT NOT NULL COMMENT '员工ID',
`employee_name` VARCHAR(50) NOT NULL COMMENT '员工姓名',
`leave_type` VARCHAR(20) NOT NULL COMMENT '请假类型',
`start_date` DATE NOT NULL COMMENT '开始日期',
`end_date` DATE NOT NULL COMMENT '结束日期',
`reason` TEXT COMMENT '请假原因',
`status` VARCHAR(20) NOT NULL COMMENT '状态:PENDING(待审批)、APPROVED(已通过)、REJECTED(已拒绝)',
`manager_id` BIGINT NOT NULL COMMENT '审批人ID',
`manager_name` VARCHAR(50) NOT NULL COMMENT '审批人姓名',
`approval_time` DATETIME COMMENT '审批时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='请假申请表';
2. 前端实现
前端需要两个页面:
-
请假申请页面:员工填写请假信息(类型、日期、原因)并提交
-
审批页面:审批人查看待审批列表,点击"通过"或"拒绝"按钮
前端通过调用后端API与数据库交互,实现表单提交和审批操作。
3. 后端实现
后端需要提供以下API:
-
提交请假申请:
POST /api/leave/apply -
获取待审批列表:
GET /api/leave/pending -
审批通过:
POST /api/leave/approve/{id} -
审批拒绝:
POST /api/leave/reject/{id}
核心代码:
@Service
public class LeaveService {
@Autowired
private LeaveRepository leaveRepository;
// 提交请假申请
public void apply(LeaveRequest request) {
LeaveApplication application = new LeaveApplication();
application.setEmployeeId(getCurrentUserId());
application.setEmployeeName(getCurrentUserName());
application.setLeaveType(request.getLeaveType());
application.setStartDate(request.getStartDate());
application.setEndDate(request.getEndDate());
application.setReason(request.getReason());
application.setStatus("PENDING");
application.setManagerId(getManagerId(getCurrentUserId()));
application.setManagerName(getManagerName(application.getManagerId()));
leaveRepository.save(application);
}
// 获取待审批列表
public List<LeaveApplication> getPending() {
Long managerId = getCurrentUserId();
return leaveRepository.findByManagerIdAndStatus(managerId, "PENDING");
}
// 审批通过
public void approve(Long id) {
LeaveApplication application = leaveRepository.findById(id).orElseThrow();
application.setStatus("APPROVED");
application.setApprovalTime(LocalDateTime.now());
leaveRepository.save(application);
}
// 审批拒绝
public void reject(Long id) {
LeaveApplication application = leaveRepository.findById(id).orElseThrow();
application.setStatus("REJECTED");
application.setApprovalTime(LocalDateTime.now());
leaveRepository.save(application);
}
}
四、引入Flowable工作流
1. 流程设计
使用Flowable流程设计器创建一个简单的请假审批流程:
-
启动事件:员工提交请假申请
-
用户任务:部门经理审批
-
排他网关:根据审批结果判断
-
结束事件:流程结束
流程定义保存为BPMN文件,部署到Flowable引擎。
2. 后端实现
添加依赖:
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.8.0</version>
</dependency>
修改Service层:
@Service
public class LeaveService {
@Autowired
private LeaveRepository leaveRepository;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
// 提交请假申请
public void apply(LeaveRequest request) {
// 保存请假申请到数据库
LeaveApplication application = new LeaveApplication();
application.setEmployeeId(getCurrentUserId());
application.setEmployeeName(getCurrentUserName());
application.setLeaveType(request.getLeaveType());
application.setStartDate(request.getStartDate());
application.setEndDate(request.getEndDate());
application.setReason(request.getReason());
application.setStatus("PENDING");
application.setManagerId(getManagerId(getCurrentUserId()));
application.setManagerName(getManagerName(application.getManagerId()));
leaveRepository.save(application);
// 启动工作流实例
Map<String, Object> variables = new HashMap<>();
variables.put("managerId", application.getManagerId());
variables.put("leaveId", application.getId());
runtimeService.startProcessInstanceByKey("leaveProcess", variables);
}
// 获取待审批列表
public List<LeaveApplication> getPending() {
String managerId = String.valueOf(getCurrentUserId());
// 查询待审批的任务
List<Task> tasks = taskService.createTaskQuery()
.taskAssignee(managerId)
.processDefinitionKey("leaveProcess")
.list();
// 获取对应的请假申请
return tasks.stream()
.map(task -> {
Long leaveId = (Long) taskService.getVariable(task.getId(), "leaveId");
return leaveRepository.findById(leaveId).orElse(null);
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
// 审批通过
public void approve(Long id) {
// 更新请假申请状态
LeaveApplication application = leaveRepository.findById(id).orElseThrow();
application.setStatus("APPROVED");
application.setApprovalTime(LocalDateTime.now());
leaveRepository.save(application);
// 完成审批任务
Task task = taskService.createTaskQuery()
.processVariableValueEquals("leaveId", id)
.singleResult();
taskService.complete(task.getId(), Map.of("approved", true));
}
// 审批拒绝
public void reject(Long id) {
// 更新请假申请状态
LeaveApplication application = leaveRepository.findById(id).orElseThrow();
application.setStatus("REJECTED");
application.setApprovalTime(LocalDateTime.now());
leaveRepository.save(application);
// 完成审批任务
Task task = taskService.createTaskQuery()
.processVariableValueEquals("leaveId", id)
.singleResult();
taskService.complete(task.getId(), Map.of("approved", false));
}
}
3. 前端实现(无需修改)
前端代码几乎不需要修改,因为API接口保持不变!
承上启下
从上面的例子可以看出在这个业务中,工作流没什么用。
因为这个审批流程太过简单,说白了:说是审批,实际上就是个简单的crud呗。
这样的流程用了Flowable工作流不仅要在流程设计器设计流程,还要在service层加上许多代码
但是在下面的复杂流程中,Flowable工作流的作用就显现出来了。
五、从简单到复杂:工作流的真正价值
现在,让我们考虑一个更复杂的审批场景:
-
员工提交请假申请
-
3天以内:部门经理审批
-
3-7天:部门经理审批 → HR审批
-
7天以上:部门经理审批 → HR审批 → 总经理审批
-
审批过程中,员工可以撤回申请
-
审批通过后,自动发送通知
1. 传统实现方式的挑战
如果使用传统方式实现,后端代码会变得非常复杂:
-
需要大量的
if-else判断处理不同的审批路径 -
需要维护额外的状态字段跟踪当前审批环节
-
需要手动处理撤回逻辑
-
需要实现通知机制
代码复杂度急剧上升,维护成本高,难以适应业务变化。
2. 工作流实现方式
使用Flowable,我们只需要:
-
在流程设计器中绘制新的流程:添加网关判断请假天数,添加HR和总经理审批节点,添加撤回和通知任务
-
稍微修改后端代码:传递请假天数变量
修改后的后端代码:
public void apply(LeaveRequest request) {
// 计算请假天数
long days = ChronoUnit.DAYS.between(request.getStartDate(), request.getEndDate()) + 1;
// 保存请假申请到数据库
LeaveApplication application = new LeaveApplication();
application.setEmployeeId(getCurrentUserId());
application.setEmployeeName(getCurrentUserName());
application.setLeaveType(request.getLeaveType());
application.setStartDate(request.getStartDate());
application.setEndDate(request.getEndDate());
application.setReason(request.getReason());
application.setStatus("PENDING");
application.setManagerId(getManagerId(getCurrentUserId()));
application.setManagerName(getManagerName(application.getManagerId()));
leaveRepository.save(application);
// 启动工作流实例(添加请假天数变量)
Map<String, Object> variables = new HashMap<>();
variables.put("managerId", application.getManagerId());
variables.put("leaveId", application.getId());
variables.put("leaveDays", days); // 新增:请假天数
runtimeService.startProcessInstanceByKey("leaveProcess", variables);
}
其他代码完全不变!
3. 工作流的优势
通过这个复杂场景,我们可以看到Flowable的真正价值:
(1)降低后端复杂度
-
不再需要复杂的if-else逻辑处理分支:流程图清晰表达审批路径
-
不再需要手动跟踪审批状态:Flowable自动管理流程状态
-
流程逻辑可视化:流程图一目了然,易于理解和维护
(2)提高系统灵活性
-
流程变更只需修改流程图,无需修改代码
-
可以快速适应业务需求变化:如增加审批环节、调整审批规则
-
支持动态流程:根据业务数据自动选择审批路径
(3)增强可追溯性
-
自动记录流程执行历史:每一步操作都有记录
-
可以查看完整的审批轨迹:谁在什么时候做了什么操作
-
便于审计和问题排查:历史数据完整可查
(4)标准化流程管理
-
提供统一的流程定义和执行机制:所有流程使用同一套引擎
-
支持版本管理:流程可以迭代升级,不影响正在运行的实例
-
易于集成:与现有系统无缝对接
六、总结
通过本文的例子,我们可以看到:
-
简单场景:Flowable和传统实现差异不大,代码量可能略有增加,但为后续扩展打下基础
-
复杂场景:Flowable的优势显现,后端代码大幅简化,流程管理更加清晰,维护成本显著降低
-
核心价值:Flowable不是银弹,但对于需要处理复杂业务流程的系统来说,它是一个强大的工具。通过将流程逻辑从代码中分离出来,我们可以:
-
提高系统的可维护性
-
加快业务需求的响应速度
-
降低开发和维护成本
-
下面给出一个简单的流程图

浙公网安备 33010602011771号