导读:本期聚焦于弦宿​创作的《Spring Boot 如何整合 Flowable 实现工作流引擎与审批流转?》,敬请观看详情。审批流程是企业系统里绕不开的需求,请假申请、合同评审、报销单据都离不开流程流转。Flowable 作为一款轻量级开源工作流引擎,兼容 BPMN 2.0 标准,可以很方便地嵌入到 Spring Boot 项目中。本文将手把手讲解整合的完整过程,包括依赖引入、数据库配置、流程图设计要点、流程部署、任务认领与审批、网关条件判断以及常见踩坑点。通过一个请假审批的实战案例,带你理解流程定义、流程实例、任务节点之间的关系,并给出动态指定审批人、流程变量传递、历史记录查询等进阶用法,帮你快速搭建稳定可扩展的审批系统。

Flowable 是一个功能完备的开源工作流引擎,源自 Activiti 的分支发展而来,完全兼容 BPMN 2.0 规范。它既能以独立服务的方式运行,也可以作为 jar 包直接嵌入 Spring Boot 应用中,对国内大量基于 Spring 技术栈的中小企业系统来说,嵌入式方案部署简单、运维成本低,是最常见的选择。本文将以一个典型的请假审批流程为例,完整演示 Spring Boot 整合 Flowable 的全过程,包括环境搭建、流程图绘制、部署、审批流转以及历史查询等核心环节。

Spring Boot 如何整合 Flowable 实现工作流引擎与审批流转?

一、环境准备与依赖配置

整合 Flowable 的第一步是引入官方提供的 starter。Flowable 针对 Spring Boot 提供了 flowable-spring-boot-starter-process,它内部已经做好了自动装配,只要类路径存在该依赖,引擎就会随应用一起启动。在 pom.xml 中添加如下配置:

<dependency>
    <groupId>org.flowable</groupId>
    <artifactId>flowable-spring-boot-starter-process</artifactId>
    <version>6.8.0</version>
</dependency>

Flowable 启动时需要数据库存储流程定义、任务、历史记录等数据。它默认支持 MySQL、PostgreSQL、Oracle 等主流数据库,所有表以 ACT_ 前缀命名,例如 ACT_RE_DEPLOYMENT 存放部署信息,ACT_RU_TASK 存放运行时任务,ACT_HI_TASKINST 存放历史任务。在 application.yml 中配置数据源即可,首次启动时 Flowable 会自动建表:

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/flowable_demo?nullCatalogMeansCurrent=true
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
flowable:
  # 首次启动自动建表,后续建议改为 false 提升启动速度
  database-schema-update: true
  async-executor-activate: false

这里有一个 MySQL 8 的常见坑需要注意:nullCatalogMeansCurrent=true 这个参数必须加上,否则 Flowable 在校验表结构时可能扫描到其他库的同名表,直接抛出异常导致启动失败。另外建议在生产环境把 database-schema-update 关掉,由 DBA 统一执行官方提供的 SQL 脚本来管理表结构,避免应用账号拥有 DDL 权限带来安全隐患。

二、设计并部署一个请假审批流程

流程设计推荐使用 Flowable 官方的 Flowable Modeling 模块,也可以直接在 IDEA 中安装 Flowable Designer 插件。一个最简的请假流程包含:开始节点、申请人提交任务、组长审批、条件网关(判断请假天数)、经理审批、结束节点。下面是对应的 BPMN XML 核心片段:

<process id="leaveProcess" name="请假审批流程">
    <startEvent id="start"/>
    <userTask id="applyTask" name="提交申请" flowable:assignee="${applyUser}"/>
    <userTask id="leaderAudit" name="组长审批" flowable:assignee="${leader}"/>
    <exclusiveGateway id="dayGateway"/>
    <userTask id="managerAudit" name="经理审批" flowable:assignee="${manager}"/>
    <sequenceFlow id="flow1" sourceRef="leaderAudit" targetRef="dayGateway"/>
    <sequenceFlow id="flow2" sourceRef="dayGateway" targetRef="managerAudit">
        <conditionExpression xsi:type="tFormalExpression">
            ${days > 3}
        </conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow3" sourceRef="dayGateway" targetRef="end"/>
</process>

流程文件编写好后,最简单的部署方式是把它放到 src/main/resources/processes 目录下,Spring Boot 集成模块会自动扫描该目录并完成部署。也可以通过 RepositoryService 手动部署,适合流程图存在数据库或文件服务器上的场景:

@Service
public class ProcessDeployService {

    @Autowired
    private RepositoryService repositoryService;

    public String deploy() {
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("processes/leave.bpmn20.xml")
                .name("请假流程")
                .deploy();
        return deployment.getId();
    }
}

需要理解的一个重要概念是:流程定义(ProcessDefinition)和流程实例(ProcessInstance)是一对多的关系。每修改一次流程图并重新部署,就会生成一个新版本的流程定义,版本号自动加一;而每次发起审批,都会基于某个版本创建一条流程实例。旧的实例继续按旧版本流转,新的实例走新版本,这正是 BPMN 引擎版本化机制带来的好处。

三、发起流程与审批流转的实现

发起流程使用 RuntimeService,传入流程定义的 key 和流程变量。流程变量在整个实例生命周期内全局可见,网关条件、任务分配表达式都会用到它们:

@RestController
@RequestMapping("/leave")
public class LeaveController {

    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;

    // 发起请假申请
    @PostMapping("/start")
    public String start(String applyUser, String leader, int days) {
        Map<String, Object> vars = new HashMap<>();
        vars.put("applyUser", applyUser);
        vars.put("leader", leader);
        vars.put("days", days);
        ProcessInstance pi = runtimeService
                .startProcessInstanceByKey("leaveProcess", vars);
        return pi.getId();
    }

    // 审批通过
    @PostMapping("/approve")
    public void approve(String taskId, String comment) {
        // 添加审批意见,便于追溯
        taskService.addComment(taskId, null, comment);
        taskService.complete(taskId);
    }
}

审批人登录后需要查询自己的待办任务,这通过 TaskService 完成。待办列表一般还要关联业务表单数据,通常的做法是把业务主键作为流程变量存进去,或者利用 Flowable 的 businessKey 字段建立流程实例与业务单据的关联:

// 查询某人的待办任务
public List<Map<String, Object>> todoList(String assignee) {
    List<Task> tasks = taskService.createTaskQuery()
            .taskAssignee(assignee)
            .orderByTaskCreateTime().desc()
            .list();
    List<Map<String, Object>> result = new ArrayList<>();
    for (Task task : tasks) {
        Map<String, Object> item = new HashMap<>();
        item.put("taskId", task.getId());
        item.put("name", task.getName());
        item.put("createTime", task.getCreateTime());
        result.add(item);
    }
    return result;
}

审批流转中最容易被忽略的是候选组的使用。真实企业里审批人往往是某个部门或角色,而不是固定某人。可以把 userTask 配置成 flowable:candidateGroups="deptLeader",该组的所有人都能看到这条待办,其中一人先执行 taskService.claim(taskId, userId) 认领任务,任务就会从候选人变成被指派人,避免多人同时审批造成数据混乱。

四、历史查询与常见问题处理

流程结束后,运行时数据会被删除并转入历史表,此时要使用 HistoryService 查询。通过 createHistoricProcessInstanceQuery 可以拿到整个流程的开始时间、结束时间、发起人,而 createHistoricTaskInstanceQuerycreateHistoricActivityInstanceQuery 则能还原每个节点的处理轨迹,这是做审批日志页面的核心数据来源:

// 查询某流程实例的完整审批轨迹
public List<HistoricActivityInstance> trace(String processInstanceId) {
    return historyService.createHistoricActivityInstanceQuery()
            .processInstanceId(processInstanceId)
            .orderByHistoricActivityStartTime().asc()
            .list();
}

整合过程中有几个高频问题值得提前防范。第一,驳回跳转不能简单理解为往回 complete 任务,正确做法是使用 runtimeService.createChangeActivityStateBuilder() 进行节点跳转,把流程拨回到指定节点并重新生成任务。第二,网关条件表达式里引用的流程变量必须存在,否则会抛出 UnknownPropertyException,建议在发起流程前做一次变量完整性校验。第三,如果涉及定时节点或异步任务,务必开启 async-executor-activate: true,否则定时边界事件不会触发。第四,业务数据和流程数据的事务一致性要靠把业务表的更新和 Flowable 的 API 调用放在同一个 Spring 事务方法内完成,Flowable 会自动注册同步器,任一环节异常时整体回滚。

整体来看,Flowable 与 Spring Boot 的整合成本并不高,难点在于把业务模型和流程模型设计好。掌握流程定义、实例、任务、变量这四者关系之后,再加上网关、多实例会签、边界事件等进阶特性,就能支撑起绝大多数企业内部审批场景的落地。

Spring BootFlowable工作流引擎修改时间:2026-09-11 08:42:46

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260911/54563.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。