Flowable工作流:从入门到实战的完整指南

5 阅读8分钟

一、你的业务流程是不是也遇到了这些问题?

公司的审批流程越来越复杂,从请假、报销到采购,各种流程满天飞。更糟糕的是,这些流程都是靠Excel表格和邮件来管理的,经常出现审批延迟、流程混乱、数据丢失的问题。

"每次有新员工入职,都要花半天时间给他讲各种审批流程,"朋友无奈地说,"更麻烦的是,流程一变,所有相关的人都要重新学习。"

这样的场景,作为后端开发的你,有没有想过用工作流引擎来解决这个问题?

二、传统流程管理的困境

在传统的开发模式中,我们通常是这样处理业务流程的:

  • 硬编码:将流程逻辑直接写在代码中
  • 状态字段:使用数据库字段来记录流程状态
  • if-else:使用大量的条件判断来处理流程分支
  • 邮件/Excel:使用邮件或Excel来传递审批信息

这种方式在流程简单的情况下工作得很好。但随着业务的发展,问题就暴露出来了:

1. 流程变更困难

每次流程变更,都需要修改代码、重新测试、重新部署,非常耗时耗力。

2. 流程缺乏可视化

流程逻辑散落在代码中,难以理解和维护。新加入的开发者需要花很多时间才能理解整个流程。

3. 审批效率低下

审批人需要定期检查邮件或系统,容易错过审批,导致流程延迟。

4. 数据难以追踪

流程的执行情况、审批历史等信息难以追踪和分析。

三、工作流引擎:业务流程的救星

为了解决这些问题,工作流引擎应运而生。工作流引擎可以帮助我们:

  • 可视化建模:通过图形化界面设计流程
  • 灵活配置:通过配置而不是代码来定义流程
  • 自动执行:自动推动流程的执行
  • 实时监控:实时监控流程的执行状态

在众多的工作流引擎中,Flowable 是一个非常优秀的选择。

四、Flowable简介

Flowable 是一个开源的、轻量级的工作流引擎,基于Activiti 5.x 分支开发而来。它提供了:

  • BPMN 2.0 标准:完全支持BPMN 2.0标准
  • 丰富的API:提供了丰富的Java API
  • 高性能:经过优化的执行引擎
  • 易集成:易于集成到Spring Boot应用中
  • 可视化工具:提供了Flowable Modeler、Flowable Admin等可视化工具

五、Flowable核心概念

在使用Flowable之前,我们需要了解几个核心概念:

1. BPMN

BPMN(Business Process Model and Notation)是业务流程模型和标记法的标准。它使用图形化的方式来描述业务流程。

2. 流程定义(Process Definition)

流程定义是业务流程的蓝图,使用BPMN 2.0 XML格式存储。它定义了流程的结构、任务、网关等。

3. 流程实例(Process Instance)

流程实例是流程定义的一次执行。当我们启动一个流程时,就创建了一个流程实例。

4. 任务(Task)

任务是流程中需要人或系统执行的步骤。常见的任务类型有:

  • 用户任务(User Task):需要人执行的任务
  • 服务任务(Service Task):需要系统执行的任务
  • 脚本任务(Script Task):执行脚本的任务
  • 发送任务(Send Task):发送消息的任务

5. 网关(Gateway)

网关用于控制流程的分支和合并。常见的网关有:

  • 排他网关(Exclusive Gateway):二选一或多选一
  • 并行网关(Parallel Gateway):并行执行多个分支
  • 包容网关(Inclusive Gateway):可以同时执行多个分支

六、Spring Boot集成Flowable

1. 添加依赖

在Spring Boot项目的pom.xml中添加Flowable依赖:

<dependencies>
    <!-- Flowable Spring Boot Starter -->
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-spring-boot-starter</artifactId>
        <version>6.8.0</version>
    </dependency>
    
    <!-- Flowable UI (可选,用于开发环境) -->
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-ui-modeler</artifactId>
        <version>6.8.0</version>
    </dependency>
    
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- 数据库驱动 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
    </dependency>
</dependencies>

2. 配置数据库

在application.yml中配置数据库连接:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/flowable?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  
  # Flowable配置
  flowable:
    database-schema-update: true
    async-executor-activate: true

3. 启动应用

启动Spring Boot应用,Flowable会自动创建所需的数据库表。

七、Flowable实战:请假流程

1. 设计流程

首先,我们需要设计一个请假流程。使用Flowable Modeler(或其他BPMN建模工具)创建一个流程定义:

  • 开始事件:流程的起点
  • 用户任务:员工填写请假单
  • 用户任务:部门经理审批
  • 排他网关:根据审批结果决定下一步
  • 用户任务:人力资源审批(如果请假天数超过3天)
  • 结束事件:流程的终点

2. 部署流程

将设计好的流程定义文件(.bpmn20.xml)部署到Flowable中:

@Service
public class ProcessDeployService {
    
    @Autowired
    private RepositoryService repositoryService;
    
    /**
     * 部署流程
     */
    public void deployProcess() {
        Deployment deployment = repositoryService.createDeployment()
            .addClasspathResource("processes/leave-process.bpmn20.xml")
            .name("请假流程")
            .deploy();
        
        System.out.println("流程部署成功,部署ID:" + deployment.getId());
    }
}

3. 启动流程

当员工提交请假申请时,启动一个流程实例:

@Service
public class LeaveService {
    
    @Autowired
    private RuntimeService runtimeService;
    
    /**
     * 提交请假申请
     */
    public String submitLeave(String employeeId, int days, String reason) {
        // 设置流程变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("employeeId", employeeId);
        variables.put("days", days);
        variables.put("reason", reason);
        variables.put("managerId", getManagerId(employeeId)); // 获取部门经理ID
        
        // 启动流程实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveProcess", variables);
        
        return "请假申请提交成功,流程ID:" + processInstance.getId();
    }
    
    /**
     * 获取部门经理ID
     */
    private String getManagerId(String employeeId) {
        // 这里应该从数据库或缓存中获取
        return "manager1";
    }
}

4. 查询任务

审批人登录系统后,可以查询待处理的任务:

@Service
public class TaskService {
    
    @Autowired
    private org.flowable.task.api.TaskService taskService;
    
    /**
     * 查询待处理任务
     */
    public List<org.flowable.task.api.Task> getTasks(String assignee) {
        return taskService.createTaskQuery()
            .taskAssignee(assignee)
            .active()
            .list();
    }
}

5. 完成任务

审批人处理完任务后,完成任务:

@Service
public class TaskService {
    
    @Autowired
    private org.flowable.task.api.TaskService taskService;
    
    /**
     * 完成任务
     */
    public void completeTask(String taskId, boolean approved) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("approved", approved);
        taskService.complete(taskId, variables);
    }
}

6. 监听流程事件

我们可以通过监听器来处理流程中的各种事件:

@Component
public class LeaveProcessListener {
    
    @Autowired
    private EmailService emailService;
    
    /**
     * 监听流程结束事件
     */
    @EventListener
    public void onProcessEnd(ProcessCompletedEvent event) {
        ProcessInstance processInstance = event.getProcessInstance();
        String processDefinitionId = processInstance.getProcessDefinitionId();
        
        // 只处理请假流程
        if ("leaveProcess".equals(processDefinitionId)) {
            // 获取流程变量
            String employeeId = (String) processInstance.getProcessVariables().get("employeeId");
            boolean approved = (boolean) processInstance.getProcessVariables().get("approved");
            
            // 发送邮件通知
            if (approved) {
                emailService.sendEmail(employeeId, "请假申请已通过", "您的请假申请已通过审批");
            } else {
                emailService.sendEmail(employeeId, "请假申请已拒绝", "您的请假申请未通过审批");
            }
        }
    }
}

八、Flowable高级特性

1. 流程变量

流程变量用于在流程执行过程中传递数据:

// 设置流程变量
variables.put("employeeId", employeeId);
variables.put("days", days);

// 获取流程变量
String employeeId = (String) runtimeService.getVariable(executionId, "employeeId");

2. 表达式

Flowable支持使用UEL表达式来动态设置任务的处理人、流程条件等:

<!-- 动态设置任务处理人 -->
<userTask id="managerApproval" name="部门经理审批">
    <humanPerformer>
        <resourceAssignmentExpression>
            <formalExpression>${managerId}</formalExpression>
        </resourceAssignmentExpression>
    </humanPerformer>
</userTask>

<!-- 动态设置网关条件 -->
<sequenceFlow id="flow4" sourceRef="exclusiveGateway" targetRef="hrApproval">
    <conditionExpression xsi:type="tFormalExpression">
        <![CDATA[${days > 3 && approved == true}]]>
    </conditionExpression>
</sequenceFlow>

3. 监听器

监听器用于在流程执行的特定时刻执行自定义逻辑:

  • 执行监听器:监听流程执行事件
  • 任务监听器:监听任务事件
  • 全局监听器:监听所有流程事件

4. 子流程

对于复杂的流程,可以使用子流程来分解:

<subProcess id="subProcess" name="子流程">
    <startEvent id="subStartEvent" />
    <!-- 子流程内容 -->
    <endEvent id="subEndEvent" />
</subProcess>

5. 多实例

对于需要多个人处理的任务,可以使用多实例:

<userTask id="meetingTask" name="会议讨论" camunda:asyncBefore="true">
    <multiInstanceLoopCharacteristics isSequential="false">
        <loopCardinality>3</loopCardinality>
        <completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.6}</completionCondition>
    </multiInstanceLoopCharacteristics>
</userTask>

九、Flowable监控与管理

1. Flowable Admin

Flowable Admin是一个Web应用,用于管理和监控Flowable流程:

  • 流程实例管理:查看、挂起、激活流程实例
  • 任务管理:查看、分配、完成任务
  • 历史数据:查看流程执行历史
  • 用户管理:管理用户和组

2. 自定义监控

我们也可以通过Flowable的API来实现自定义监控:

@Service
public class ProcessMonitorService {
    
    @Autowired
    private HistoryService historyService;
    
    /**
     * 获取流程执行统计
     */
    public Map<String, Object> getProcessStats() {
        Map<String, Object> stats = new HashMap<>();
        
        // 获取已完成的流程数量
        long completedCount = historyService.createHistoricProcessInstanceQuery()
            .finished()
            .count();
        
        // 获取正在执行的流程数量
        long runningCount = historyService.createHistoricProcessInstanceQuery()
            .unfinished()
            .count();
        
        // 获取平均执行时间
        // ...
        
        stats.put("completedCount", completedCount);
        stats.put("runningCount", runningCount);
        
        return stats;
    }
}

十、实战经验总结

  1. 流程设计要合理:流程要简洁明了,避免过于复杂的分支
  2. 变量命名要规范:使用有意义的变量名,便于理解和维护
  3. 权限控制要严格:确保只有授权用户才能执行相应的任务
  4. 异常处理要完善:对流程执行过程中的异常进行合理处理
  5. 监控要到位:实时监控流程的执行状态,及时发现和解决问题
  6. 性能要优化:对于高并发场景,要合理配置Flowable的线程池和缓存

十一、Flowable的适用场景

Flowable适用于以下场景:

  • 审批流程:请假、报销、采购等审批流程
  • 业务流程:订单处理、客户服务、供应链管理等
  • 工作流:任务分配、进度跟踪、状态管理等
  • 流程自动化:自动触发、自动执行、自动通知等

十二、写在最后

Flowable是一个功能强大、易于集成的工作流引擎,它可以帮助我们从繁琐的流程管理中解放出来,让业务流程更加规范、高效、透明。

当然,Flowable并不是银弹,它也有自己的适用场景和局限性。在使用Flowable之前,我们需要根据业务需求和系统架构来决定是否使用它。

希望这篇文章能给你带来一些启发,帮助你在实际项目中更好地应用Flowable。

如果你在使用Flowable的过程中有其他经验或困惑,欢迎在评论区留言交流!


服务端技术精选,专注分享后端开发实战经验,让技术落地更简单。

如果你觉得这篇文章有用,欢迎点赞、在看、分享三连!