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,我们只需要:

  1. 在流程设计器中绘制新的流程:添加网关判断请假天数,添加HR和总经理审批节点,添加撤回和通知任务

  2. 稍微修改后端代码:传递请假天数变量

修改后的后端代码:

java
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)标准化流程管理

  • 提供统一的流程定义和执行机制:所有流程使用同一套引擎

  • 支持版本管理:流程可以迭代升级,不影响正在运行的实例

  • 易于集成:与现有系统无缝对接

六、总结

通过本文的例子,我们可以看到:

  1. 简单场景:Flowable和传统实现差异不大,代码量可能略有增加,但为后续扩展打下基础

  2. 复杂场景:Flowable的优势显现,后端代码大幅简化,流程管理更加清晰,维护成本显著降低

  3. 核心价值:Flowable不是银弹,但对于需要处理复杂业务流程的系统来说,它是一个强大的工具。通过将流程逻辑从代码中分离出来,我们可以:

    • 提高系统的可维护性

    • 加快业务需求的响应速度

    • 降低开发和维护成本

下面给出一个简单的流程图

image

posted @ 2026-01-28 14:06  雨花阁  阅读(17)  评论(0)    收藏  举报