Spring Boot 3 集成 Camunda 7:工作流引擎实战指南
2026/9/20 14:25:56 网站建设 项目流程

简介:这是一份基于 Spring Boot 3.X 整合 Camunda 的工作流引擎项目源码,面向需要快速搭建流程审批、任务管理类功能的 Java 后端开发者。资源采用 Maven 多模块结构,拆分为 server 与 client 两个子模块,便于理解服务端与调用端的职责划分;源码中包含 Camunda 核心配置、BPMN 流程定义文件、业务接口示例以及相关 XML 映射,可直接导入 IDE 运行调试。压缩包共 87 个文件,以 java、xml、bpmn、yml 等类型为主,包体仅 1.17MB,轻量紧凑。从文件组成来看,项目还附带 Git 版本记录与 README 说明,适合作为学习和二次开发基础。已有 300 人学习下载,适合具备一定 Spring Boot 基础、希望掌握 Camunda 集成方式的开发者参考。 工作流引擎这个词,对 Java 后端来说是个既熟悉又陌生的东西。熟悉是因为一提审批流、工单流转、状态机,绕不开 Camunda、Flowable、Activiti 这几家;陌生是因为很多项目组压根没正经在 Spring Boot 里从零整合过一套完整的流程引擎,最多是看过文档、跑过 demo。这次我在一个 Spring Boot 3.2 的项目里完整落地了 Camunda,从版本选型到 BPMN 建模,再到核心 API 调用和线上问题排查都走了一遍。这篇就按我的实操顺序来梳理,从配置到跑通第一个流程,再到把你一定会遇到的坑提前踩平。

文章里用的版本是Spring Boot 3.2.x + Camunda 7.20的组合。这是目前社区版里和 Spring Boot 3.x 配合最成熟的一套,基于 Java 17,内嵌式部署,不需要额外起单独的流程引擎服务。有一定 Spring Boot 基础的开发者可以照着做完整个集成,新手也能通过这篇了解工作流引擎在你项目里到底扮演什么角色。

1. 版本选型:Spring Boot 3.x 里的 Camunda 不是随便选的

很多人在第一步就栽跟头。看到 Spring Boot 3.x,脑子一热去 Maven 搜 Camunda 最新版,结果引入一堆和 Spring Boot 2.x 时代完全不同的依赖。这里有个大前提:Camunda 从 7.x 到 8.x 是两套完全不同的架构。7.x 是传统的 Java 库,直接嵌进你的 Spring Boot 应用,共享数据库连接池和事务;8.x 是基于 Zeebe 的云原生架构,通常要独立部署 Broker,Spring Boot 应用只作为客户端远程调用。选哪个取决于你的部署环境,但如果你想"整合",也就是把引擎跑在 Spring Boot 进程内,那么 Camunda 7 是合理选择,版本上从 7.19 开始才完整支持 Spring Boot 3.x 的 Jakarta 命名空间。

1.1 Camunda 7 和 Camunda 8 的区别,先搞清楚再动手

我见过不止一个同事把 Camunda 8 的 Spring Boot Starter 加到项目里,结果启动直接报错找不到javax.persistence。原因是 Camunda 8 的 Spring Boot Starter 默认假设你连接的是 Zeebe Gateway,而不是本地数据库,整个交互模型完全不同。

简单说,如果你的场景是"在现有 Spring Boot 单体应用里加一套可嵌入的流程引擎,流程定义存在数据库表里,用 Java API 直接操作",就选 Camunda 7。如果你的场景是"微服务架构,流程引擎需要独立扩展、独立部署,通过 REST 或 gRPC 和业务服务解耦",那才考虑 Camunda 8。

1.2 引入依赖和基础配置,一步到位

Spring Boot 3.2 项目的 pom.xml 中,核心依赖就两个:

<dependency> <groupId>org.camunda.bpm.springboot</groupId> <artifactId>camunda-bpm-spring-boot-starter</artifactId> <version>7.20.0</version> </dependency> <dependency> <groupId>org.camunda.bpm.springboot</groupId> <artifactId>camunda-bpm-spring-boot-starter-rest</artifactId> <version>7.20.0</version> </dependency>

第一个 starter 是引擎本体,第二个 starter-rest 会暴露一组 REST API,方便前端或外部系统通过 HTTP 操作流程。如果你的项目不需要 REST 接口,第二个可以不引入,但实际开发中建议加上,Camunda 自带的 Cockpit 和 Tasklist Web 应用在很多场景下调试流程非常方便。

配置文件里核心是数据源和自动部署开关,我在application.yml里是这样配的:

spring: datasource: url: jdbc:mysql://localhost:3306/camunda_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver camunda: bpm: admin-user: id: admin password: admin123 first-name: Admin filter: create: All tasks auto-deployment-enabled: true database-schema-update: true history-level: full

admin-user会自动创建一个管理员账号,用于登录 Camunda 自带的 Web 应用;auto-deployment-enabled设为 true 后,Spring Boot 启动时会自动扫描classpath:/processes目录下的.bpmn文件并部署;database-schema-update设为 true 表示启动时自动创建或更新引擎需要的 40 多张表;history-level建议直接设 full,后面查历史流程和性能分析都靠它。

注意:Camunda 7 和 Spring Boot 3.x 搭配时,务必将database-schema-update设为 true 首次启动,否则会因为缺少ACT_GE_PROPERTY等核心表直接抛异常。

2. 画一个请假审批流程,部署到 Spring Boot

引擎跑起来只是第一步,真正要落地的是流程本身。我不建议一上来就写代码,先在 Camunda Modeler 里把流程图设计好,导出 bpmn 文件,再放到 Spring Boot 工程里自动部署。

2.1 用 Camunda Modeler 设计 BPMN 流程

Camunda Modeler 是 Camunda 官方出品的桌面建模工具,支持 BPMN 2.0 标准,拖拽节点就能画图。以一个最常见的请假审批流程为例,设计整条链路:

  • 开始事件:用户提交请假申请
  • 用户任务:填写请假单(Assignee 设为${requester}
  • 排他网关:判断请假天数是否大于 3 天
  • 如果大于 3 天,走"经理审批"任务(Assignee 设为manager
  • 结束事件:流程结束

导出后的 bpmn 文件里,会看到 XML 结构定义了流程的每个节点和它们之间的连线。核心结构大致是这样:

<bpmn:process id="leaveProcess" name="请假审批流程" isExecutable="true"> <bpmn:startEvent id="startEvent" /> <bpmn:userTask id="applyTask" name="填写请假单" camunda:assignee="${requester}" /> <bpmn:exclusiveGateway id="gatewayCheckDays" name="天数判断" /> <bpmn:userTask id="managerApproveTask" name="经理审批" camunda:assignee="manager" /> <bpmn:sequenceFlow id="flow1" sourceRef="startEvent" targetRef="applyTask" /> <!-- 每个节点和连线都要有对应的 sequenceFlow 定义 --> </bpmn:process>

注意一点:BPMN 文件里的process id是流程定义的唯一标识,后面调 API 启动流程时靠的就是这个 id,所以设计时要慎重,一般用驼峰命名,比如leaveProcessorderFlow这种。

2.2 自动部署机制的原理

把 bpmn 文件放到src/main/resources/processes目录下,重启 Spring Boot,Camunda 会自动读取并部署。但它不是简单地每次启动都重复部署一遍,而是比较流程定义的 key 和版本号。同一个 key 的流程,如果 bpmn 文件内容有变化,会生成一个新的版本,历史流程依然走旧版本,新发起的流程走最新版本。

这个版本管理机制在实际项目中很重要。线上流程已经在跑了,你改了一版 bpmn,不能影响进行中的实例,只有新发起的流程才用新版定义。Camunda 的部署器天然支持这个逻辑,你不需要写额外的代码,只要把新版 bpmn 放进去重启即可。

3. 核心 API 实操:从启动流程到完成任务

部署只是起点,业务系统真正要调的是 Camunda 提供的 Java API。整个操作流程分三块:启动流程实例、查询并完成任务、处理网关条件。我在代码里直接在一个 Service 类里串起来,你可以直接抄。

3.1 启动流程实例,业务数据和流程变量绑定

启动流程时,业务系统通常要传递业务单号、操作人、请假天数这些数据。Camunda 提供了"流程变量"机制,可以在启动时设置,也可以在流程执行过程中动态添加。以下是我项目里的一个典型写法:

@Service public class LeaveProcessService { @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; public String startLeaveProcess(String requester, int days) { Map<String, Object> variables = new HashMap<>(); variables.put("requester", requester); variables.put("days", days); ProcessInstance instance = runtimeService .startProcessInstanceByKey("leaveProcess", "BIZ-" + System.currentTimeMillis(), variables); return instance.getProcessInstanceId(); } }

startProcessInstanceByKey传入三个参数:流程定义的 key、业务键、流程变量。业务键也可以是业务系统里的申请单号,这样后续你要查询某个业务单号的流程实例,可以直接通过runtimeService.createProcessInstanceQuery().processInstanceBusinessKey("BIZ-10001").singleResult()查回来,比记流程实例 ID 方便得多。

3.2 查询待办任务:别用错 TaskQuery

流程启动后,就会在"填写请假单"这个用户任务上停住。比如前端页面上要给"张三"展示他待办的任务,后端就是走 TaskService 查询。这里有一个非常容易用错的点:taskAssignee是查指定办理人的任务,taskCandidateUser是查候选人的任务,这两个概念不能混淆,否则查出来的结果会漏掉。

推荐写法:

public List<Task> getTodoTasks(String assignee) { return taskService.createTaskQuery() .taskAssignee(assignee) .active() .orderByTaskCreateTime() .desc() .list(); }

查询结果里task.getProcessInstanceId()是流程实例 ID,task.getId()是任务 ID,注意区分。任务 ID 是在完成任务时要用的关键参数,而流程实例 ID 是跨任务一直存在的全局标识。

3.3 完成任务并设置网关判断变量

"填写请假单"任务完成时,需要把请假天数作为流程变量传进去,后面的排他网关会根据days的值决定走经理审批还是直接结束。完整代码如下:

public void completeApplyTask(String taskId, int days) { Map<String, Object> variables = new HashMap<>(); variables.put("days", days); taskService.complete(taskId, variables); }

BPMN 里的排他网关会自动读取这个days变量,和连线条件做比较:

<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression"> ${days > 3} </bpmn:conditionExpression>

这里的关键是,条件表达式用的是 Spring EL 语法,变量名要和传入的变量名完全一致,类型也要匹配。我遇到过一个问题:业务方传的days是字符串"5",表达式里写days > 3,结果网关直接抛异常,找了好久才定位到类型不匹配。建议在入口处统一做类型校验和转换。

4. 踩坑实录:我用 Camunda 时遇到的四个典型问题

集成 Camunda 的过程中,有几个问题是反复出现的,我在各个社区和群里也看到不少新手在问。这里把最典型的四个问题整理出来,都是你一定会遇到的。

4.1 启动报错:数据库连接失败或表不完整

首次启动如果报错信息里出现Error querying database或者Table 'ACT_GE_PROPERTY' doesn't exist,基本就是数据源配置有问题,或者database-schema-update没设成 true。MySQL 要注意的细节很多,比如时区配置、字符集配置、驱动版本。Spring Boot 3.x 默认用 MySQL Connector/J 8.x,URL 里必须带上serverTimezone=Asia/Shanghai,否则会报时间相关的 SQL 异常。

4.2 流程图里的中文乱码

Camunda 自带的 Cockpit 里查看流程定义图,中文乱码是常见现象,尤其是 Linux 服务器上。原因是 JVM 找不到中文字体。解决办法是在启动参数里加上-Dfile.encoding=UTF-8,然后在服务器上安装中文字体,比如执行yum install fontconfig后把 Windows 的 simhei.ttf 拷贝到/usr/share/fonts目录下,才能保证绘制流程图时中文不会变成方块。

4.3 事务一致性问题:流程推进和业务数据不能脱节

Camunda 7 的 API 默认会参与 Spring 事务。比如"创建请假单并启动流程"这个过程,如果业务数据保存失败了,流程实例也必须回滚,否则就会出现业务单没建成功但流程已经跑起来了的脏数据。真正稳妥的做法是把两步操作放在同一个事务方法里:

@Transactional(rollbackFor = Exception.class) public void createAndStartProcess(String requester, int days) { leaveOrderMapper.insertOrder(...); runtimeService.startProcessInstanceByKey("leaveProcess", ...); }

如果在事务外部调用流程 API,或者监听了流程事件后在监听器里操作业务库,出现数据不一致的概率会大很多。我的经验是:能用 Spring 事务包住引擎调用的地方就尽量包住,不要信任"好像大多数时候没问题"。

4.4 任务查询出现性能瓶颈时的优化

任务表ACT_RU_TASK是引擎里增长最快的表之一,随着流程实例增多,慢查询会越来越明显。一个常用的优化手段是按业务键和创建时间的联合条件去查,避免全表扫描;另一个是定期清理已完成流程的运行时数据,把历史归档到ACT_HI_*表。我在项目里配置了一个定时任务,每天凌晨清理 30 天前已结束的流程实例,执行的是 Camunda 提供的HistoryService删除接口:

historyService.deleteHistoricProcessInstance(processInstanceId);

这个操作会同步清理运行时数据和历史数据,但生产环境操作前一定要确认流程确实已经结束,否则会误删活跃流程。

5. 从 Flowable 迁移到 Camunda 的体验补充

项目早期用的是 Flowable,因为公司内部有一段历史代码基于 Flowable 开发。这次新项目换成 Camunda 后,我有几个切身的感受。

一个是 API 设计风格不同。Flowable 把很多操作封装在RuntimeServiceTaskService里,但细节上有差异,比如查询任务的排序方式、变量传递的时机,都需要重新适应。Camunda 的查询 API 更直观,尤其是TaskQuery提供了完整的链式条件,想按候选人、业务键、流程定义 key 组合查询都很顺手。

另一个是社区氛围和文档质量的差别。Camunda 的官方文档对 BPMN 2.0 规范和 Spring Boot 集成的覆盖更细致,遇到的绝大多数问题都能在文档里找到答案。Flowable 的文档也不错,但某些底层逻辑讲得没那么透。

如果你在 Spring Boot 3.x 项目里从零开始选型,我个人建议是直接上 Camunda 7。它和 Spring Boot 3.x 的兼容性、社区活跃度、版本迭代速度,目前来说都更让人放心。

6. 一点个人经验总结

从画 BPMN 流程图到跑通完整链路,我觉得最值得反复揣摩的不是 API 怎么调,而是"流程引擎在你的系统里到底负责什么"。很多团队把流程引擎当成万能钥匙,把各种业务规则都塞进流程节点里,结果流程图画得极其复杂,维护成本直线飙升。我的做法是:流程引擎只负责"流转"和"人机交互",业务规则的判断放在代码里,通过流程变量传递给网关条件,这样既灵活又不会让流程图失控。

另外一个建议是,开发阶段把 Camunda 自带的 Web 应用(Cockpit 和 Tasklist)开起来,尤其是通过camunda-bpm-spring-boot-starter-webapp引入后,你就能在浏览器里直观看到每个流程实例跑到哪个节点、停留多久、变量是什么。排查问题的时候比看日志高效得多。

最后再说个小细节:history-level如果不是full,历史任务查询和流程实例报告的数据会不完整,后面做统计报表时才发现就晚了。我当时图省事设成了audit,结果要查某个任务的变量快照时发现查不到,翻文档才发现只记录了流程级别的数据。这个配置,建议在一开始就定好。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询