Spring Boot 2.6.13 + MySQL8 + Flowable 6.8.1 审批流搭建实战指南

发布时间:2026/10/12 16:50:54
Spring Boot 2.6.13 + MySQL8 + Flowable 6.8.1 审批流搭建实战指南 简介一套Spring Boot 2.6.13、MySQL 8与Flowable 6.8.1整合的工作流应用工程面向需要快速落地流程审批、任务管理等场景的Java后端开发者重点解决流程引擎集成、关系型数据持久化与数据库环境搭建三方面痛点适合作为企业级应用开发的学习模板或起步脚手架。压缩包共29个文件整体约382.9MB包含Java源码、pom.xml构建配置、yml与properties配置文件、编译后的class与可运行jar并含MySQL 8安装程序msi兼顾源代码研读、参数调优与一键部署等多种用途。该工程已吸引109人学习可作实践参考。借助自带的MySQL安装程序开发者无需单独安装数据库即可启动完整环境省去繁琐配置结合Flowable的BPMN 2.0流程建模能力可对照示例完成从流程定义、任务派发到与Spring Boot接口联调的全过程并方便后续按业务需求扩展审批流、会签、条件分支等模块。整体结构清晰便于按需检索代码与配置。1. 为什么 Spring Boot 2.6.13 MySQL8 Flowable 6.8.1 是当前做审批流最省心的组合很多团队一提到工作流引擎就头皮发麻总觉得要引入一堆中间件要么版本对不上要么部署环境复杂。但这套组合恰恰相反——它最大的价值在于把「流程引擎」和「业务系统」塞进了同一个工程里版本之间又是经过大量生产环境验证过的稳定搭配。我见过太多人卡在搭建阶段最后才发现是版本不匹配而不是业务逻辑难写。这套组合能解决的问题很直接你需要给业务系统补上审批流、会签、驳回、多实例任务这些能力但不想为它单独部署一套重量级平台。Flowable 6.8.1 作为一个嵌入式工作流引擎直接在 Spring Boot 进程里跑表结构自动建API 现成可用。而 MySQL8 配合装好的安装程序连数据库环境都顺手解决了对于内网部署、以及刚接手别人项目的新人来说少了最让人头疼的一步。适合谁用正在做 OA 类项目、企业内部系统、或者任何需要「状态机 人工审核 流程追踪」功能的 Java 开发者。下文我会把从建工程到跑通第一条审批流的完整路径写清楚包括参数、配置和几个容易翻车的细节。2. 从零搭建Spring Boot 工程结构与 MySQL8 安装程序的关键作用2.1 为什么选 Spring Boot 2.6.13 而不是更新的 3.x 版本很多人在选版本时有个误区越新越好。但在工作流引擎这个场景情况恰恰相反。Flowable 6.8.1 对 Spring Boot 3.x 的支持是通过单独的 starter 来适配的而 2.6.13 是 2.6.x 的最后一个版本生命周期完整社区反馈充分和 Flowable 6.8.1 的兼容性是被大量项目验证过的。另外一个现实原因是很多公司现有的项目就停在 Spring Boot 2.x你要做的只是把 Flowable 加进去而不是连带着升级整个微服务架构。改动范围越小风险就越可控。Spring Boot 2.6.13 的另一个好处是它对 Java 8 和 Java 11 都支持得很好而不少老项目的 JDK 就卡在 8 上这点很关键。Spring Boot 2.6.13 也有它的独有行为需要注意比如对循环依赖默认禁止、路径匹配策略从 AntPathMatcher 切到了 PathPatternParser。这些改动会直接影响 Flowable 的某些 URL 匹配行为后面集成时会具体说。2.2 最小工程骨架pom.xml 里必须出现的依赖我在搭建最小可用工程时一般保持依赖极简用最少的 maven 坐标跑通引擎再逐步加自己不熟悉的配置。properties java.version8/java.version spring-boot.version2.6.13/spring-boot.version flowable.version6.8.1/flowable.version /properties dependencies !-- Web 支持 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Flowable 核心流程定义、任务、历史 -- dependency groupIdorg.flowable/groupId artifactIdflowable-spring-boot-starter/artifactId version${flowable.version}/version /dependency !-- MySQL 驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency /dependencies这里有两个细节值得说。第一不用单独引入flowable-spring-boot-starter-process因为flowable-spring-boot-starter已经包含了流程引擎、任务、历史、IDM 这几个最常用的模块。第二MySQL 驱动的版本不需要手写Spring Boot 2.6.13 的依赖管理已经把它锁到了 8.0.26 左右这个版本配 MySQL8 正是稳定区。还有一点flowable-spring-boot-starter会启用 Flowable 所有模块的自动配置。如果你只想用流程引擎加任务不想引入表单、DMN、CMMN 这些模块后面可以在配置里关掉减少启动耗时和内存占用这在低配置服务器上效果明显。2.3 自带 MySQL8 安装程序理解两个阶段的不同作用标题里提到「自带 mysql8 安装程序」这句话在真实项目里要拆成两种形态理解。第一种是开发环境一键脚本通常是.bat或.sh负责在本地把 MySQL 8 的 zip 包解压、初始化 data 目录、注册 Windows 服务或 Linux systemd 服务、设置 root 初始密码。第二种是生产环境的静默安装配置配合响应文件来做的避免手工安装的交互步骤。我一般会在工程根目录放一个mysql-setup/文件夹里面至少包含# 初始化 MySQL8 数据目录Linux/macOS 下 mysqld --initialize-insecure --basedir/opt/mysql8 --datadir/opt/mysql8/data初始化加--initialize-insecure表示 root 账号初始为空密码后面通过 SQL 去改密码比--initialize随机密码更省事尤其适合无人值守的安装脚本。Windows 下对应的命令是mysqld --initialize-insecure --basedirD:\\mysql8\\ --datadirD:\\mysql8\\data原理一样。这个安装程序的意义在于它让整个项目从「数据库、引擎、业务代码」变成了一个整体分发的方案。新同事或客户拿过去不用自己去装数据库、记一堆安装步骤跑完脚本环境就齐了。3. Flowable 6.8.1 与 Spring Boot 融合配置参数与自动建表策略3.1 最关键的 5 个配置项少一个都会让你后面难受把 Flowable 接进 Spring Boot 之后application.yml里有一组参数是必须理解的。先看一段我在项目里反复调优后的配置spring: datasource: url: jdbc:mysql://localhost:3306/flowable?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver flowable: database-schema-update: true async-executor-activate: false history-level: audit db-history-used: true process-definition-location-prefix: classpath*:/processes/ process-definition-location-suffixes: - .bpmn20.xml - .bpmn逐项拆开说。database-schema-update设为true的意思是流程引擎启动时自动检查并更新表结构第一次运行会自动把 60 多张表建好。生产环境我会改成false用专门的脚本去迁移避免运行时不小心改了表结构。async-executor-activate这里设为false是我个人的偏好。Flowable 的异步执行器会启动定时线程去扫 Job 表如果不做边界事件超时、异步消息这些高级功能开着反而多耗资源。如果流程里需要定时器或异步延续再把它打开。history-level设为audit是稳妥选择。它记录了流程实例、任务、活动的完整历史同时又不像full那样把变量每次变更的细节都存下来适合绝大多数业务系统——既能查谁在什么时候批过什么又不至于让历史表膨胀太快。关于process-definition-location-prefix它指定了引擎自动部署流程模型时的扫描路径。上面配置用的是classpath*:/processes/意味着我只要把.bpmn20.xml文件丢到resources/processes/目录下项目启动时 Flowable 就会自动部署这些流程定义不需要手动调 API。3.2 自动建表成功后的验证动作连不上或表不全时怎么看配置写完后第一次启动要重点观察日志。一个健康的启动过程会在日志里看到类似Flowable 6.8.1的 banner然后是一串create table ACT_GE_BYTEARRAY、create table ACT_RE_PROCDEF这样的 DDL 输出。如果看到Tables already exist或者跳过建表说明 data 目录里的库已经有了结构。还有一个容易骗人的点Flowable 默认会用自己的 IDM 模块创建用户、组相关表比如ACT_ID_USER和ACT_ID_GROUP。如果你不打算用 Flowable 原生的用户体系而是想让流程任务和现有系统的用户体系对接可以在配置里关掉 IDMflowable: idm: enabled: false关掉之后不会建ACT_ID_*这几张表候选组、候选人功能会受影响但单纯的流程引擎、任务分配、审批逻辑不受影响。我的建议是如果你已经有一个完善的用户系统就该关掉避免两套用户数据互相干扰。验证是否成功的另一个关键手段是看数据库。连上 MySQL8 后执行use flowable; show tables;你会看到以ACT_为前缀的表按用途分几个族ACT_RE_*流程定义和模型、ACT_RU_*运行时的实例、任务、变量、ACT_HI_*历史数据、ACT_GE_*通用数据。如果表齐了说明引擎和数据库的链路是通的接下来就可以部署流程了。4. 部署并跑通第一条审批流从 BPMN 文件到完整 Java API 调用4.1 用带注释的 BPMN 文件完成流程定义一个简易请假审批理论讲完下面是动手环节。我在项目里的习惯是先画一个最简单的「单人审批」流程走通后再往里面加会签、条件网关和驳回。?xml version1.0 encodingUTF-8? definitions xmlnshttp://www.omg.org/spec/BPMN/20100524/MODEL xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:flowablehttp://flowable.org/bpmn targetNamespacehttp://flowable.org/bpmn process idleaveApproval name请假审批流程 isExecutabletrue !-- 流程开始无触发由API显式启动 -- startEvent idstart name开始 / !-- 第一个用户任务员工提交申请实际业务中可能由前一个表单任务承接 -- userTask idapply name提交请假申请 flowable:assignee${taskService.getVariable(task.getId(), \applyUser\)} extensionElements modeler:initiator-can-complete xmlns:modelerhttp://flowable.org/modeler flowable:initiatorapplyUser / /extensionElements /userTask !-- 部门经理审批节点 -- userTask idmanagerApprove name部门经理审批 flowable:candidateGroupsdeptManager / !-- 条件排他网关根据审批结果决定走向 -- exclusiveGateway idgateway name审批结果网关 / !-- 同意则流程结束 -- sequenceFlow idflow1 sourceRefapply targetRefmanagerApprove / sequenceFlow idflow2 sourceRefmanagerApprove targetRefgateway / userTask idend name结束 / sequenceFlow idflow4 sourceRefgateway targetRefend conditionExpression xsi:typetFormalExpression ![CDATA[${approved true}]] /conditionExpression /sequenceFlow endEvent idendEvent name流程结束 / sequenceFlow idflow5 sourceRefend targetRefendEvent / /process /definitions这份 BPMN 文件有几个值得注意的地方。第一用户任务的flowable:assignee我写的是动态表达式从一个名为applyUser的流程变量里取指派人这就避免了把用户 ID 写死在流程定义里。第二flowable:candidateGroups可以指定一组候选角色这类任务会进入候选组列表由组里的任何一个人认领。实际项目里我会优先用候选组而不是固定指派适应「领导休假、其他人代审」的常见需求。第三条件网关里的表达式${approved true}依赖一个名为approved的布尔流程变量提交审批时必须把它作为变量传进去。很多人第一次跑不通流程就是漏掉了这个变量。顺便一提BPMN 文件里isExecutabletrue必须显式加上否则 Flowable 会把它当作描述性定义而跳过部署。4.2 Java 侧完整调用链启动流程、查询任务、完成任务文件放到resources/processes/目录后启动项目Flowable 会自动部署。下面这段代码是我在模拟项目X里反复使用的模板涵盖了从启动到结束的完整操作Service public class LeaveApprovalService { private final RuntimeService runtimeService; private final TaskService taskService; public LeaveApprovalService(RuntimeService runtimeService, TaskService taskService) { this.runtimeService runtimeService; this.taskService taskService; } /** * 启动请假流程并设置初始变量 */ public String startLeaveProcess(String applyUserId, Integer days) { MapString, Object variables new HashMap(); variables.put(applyUser, applyUserId); variables.put(days, days); variables.put(approved, false); // 初始值设为 false ProcessInstance instance runtimeService .startProcessInstanceByKey(leaveApproval, variables); return instance.getId(); } /** * 查询某个用户作为候选组可办理的任务 */ public ListTask queryTasksByCandidateGroup(String groupId) { return taskService.createTaskQuery() .taskCandidateGroup(groupId) .orderByTaskCreateTime() .desc() .list(); } /** * 审批通过或驳回 */ public void completeTask(String taskId, boolean approved) { MapString, Object taskVariables new HashMap(); taskVariables.put(approved, approved); // 这里的 true 表示完成任务并设置局部变量 taskService.complete(taskId, taskVariables); } }这段代码的每一行都对应着 Flowable 的核心 API。startProcessInstanceByKey用的是流程定义里process idleaveApproval这个 key而不是文件名。如果你改过流程 ID但代码里还写旧值会直接报ProcessDefinitionNotFoundException。变量applyUser会在启动时被设置用户任务的动态 assignee 表达式正是从它取值。queryTasksByCandidateGroup是典型的「查待办」场景它查的是ACT_RU_TASK表里候选组匹配的任务查询条件走的是 Flowable 自己的查询器底层空间很小不会有 SQL 注入风险。complete方法把任务变量的 map 传进去这些变量会被写入任务的局部变量但上面排他网关读取的approved就是在这里传入的。还有个细节taskService.complete()之后任务就从运行态消失流程走到下一个节点。如果流程被驳回实际会走一条单独的驳回路径而不是把同一个任务复活。这是 Flowable 和某些国产流程引擎最大的不同——它更贴合 BPMN 2.0 规范驳回是「另起一个任务」而不是「任务回到原处」。4.3 模型设计器做的图为什么部署后偶尔显示为空白或缺失坐标用 Flowable 自带的流程设计器在 Web 界面里拖拽画图时有概率遇到一个问题设计器里画得好好的流程图部署到引擎里之后在流程追踪页面上变成空白或者节点叠在一起。原因是 BPMN 文件里如果缺少diagram interchange信息也就是图形坐标数据引擎运行时无法还原出可视化的流程图。出现这种情况多半是手动编辑了 BPMN XML或者通过接口把模型转 XML 时丢失了图形信息。解决办法是部署前确认 BPMN 文件里包含BPMNDiagram段。如果你用的是代码部署可以在 XML 里补一段标准的坐标描述如果你只是手动改 XML最简单的方法是放到 Flowable 官方 Modeler 里打开再保存一次坐标信息会被自动补充。5. Flowable 6.8.1 实战避坑指南5 个你一定会遇见的麻烦5.1 MySQL8 时区问题导致连接时报错现象项目启动时数据源初始化报错错误内容类似The server time zone value Öйú±ê׼ʱ¼ä is unrecognized。原因MySQL8 的 JDBC 驱动对时区参数要求更严格而 Spring Boot 2.6.13 默认的驱动版本里时区校准逻辑和 MySQL 服务端配置不一致。解决JDBC URL 显式指定serverTimezoneAsia/Shanghai像我在 3.1 节配置里写的那样。另一个办法是在 MySQL8 服务端设置default-time-zone 08:00并重启服务。5.2 Flowable 自动部署重复注册流程定义现象每次重启项目ACT_RE_PROCDEF表里出现多个版本的同一个流程版本号递增旧版本没有被自动清理。原因Flowable 的自动部署机制是根据文件内容和上次部署的deployment做比对。但如果你改了 BPMN 文件里的任何文本——哪怕只是加了个空格——引擎都会认为这是一个新版本。解决如果只是想开发调试可以在配置里把flowable.check-process-definitions设为false来关闭启动时的自动部署检查。但更推荐的做法是用固定的deployment名称或代码部署并复用 Deployment ID生产环境则走 SQL 脚本或专门的发布流程来管理版本。5.3 任务的候选人查不到数据现象流程模型里明明设置了flowable:candidateGroupsdeptManager但调用taskQuery.taskCandidateGroup(deptManager)时查不到任务。原因任务可能已经被其他人认领或者candidateGroups属性写错了位置。还有一个容易踩的坑是如果你没关掉 Flowable IDM但业务代码又没往 IDM 里写用户和组的数据候选组的字段可能根本没被填上。解决确认任务在ACT_RU_IDENTITYLINK表里存在类型为candidate的记录。排查时直接查库select * from ACT_RU_IDENTITYLINK where TASK_ID_ 你的任务ID。如果没有记录回去检查流程定义里的属性名是不是写成了candidateGroup少了 s 的复数。5.4 流程变量在网关处读取不到或为 NULL现象任务完成时明明传了变量approvedtrue但流程走到排他网关时报错或者走了默认路径。原因变量作用域不一致。taskService.complete(taskId, variables)传入的变量默认是任务局部变量如果网关判断用的是流程实例级别的变量有可能读到null。另一种情况是变量名拼写不一致。解决在使用网关条件前确认变量层级。用runtimeService.getVariable(processInstanceId, approved)取到的才是全局流程变量。如果任务局部变量盖住了全局变量可以在 complete 时同时设置局部和全局taskService.complete(taskId, variables, globalVariables)。再不行就在 BPMN 里给条件表达式加一个默认值判断。5.5 Spring Boot 2.6.x 路径匹配策略导致 Flowable 接口 404现象Flowable 自带的管理接口或 REST 接口通过/service/**访问时返回 404但在早些版本是正常的。原因Spring Boot 2.6 开始默认用PathPatternParser替代AntPathMatcher/**通配符的匹配规则有变化导致某些路径没被正确映射。解决在application.yml里把路径匹配策略改回旧模式spring: mvc: pathmatch: matching-strategy: ant_path_matcher这个配置在 Flowable 6.8.1 的官方文档和社区讨论里都被反复提及属于典型的升级副作用。如果你不涉及自定义路径匹配这一项可以不管但如果你同时集成了 Swagger 或 Knife4j那就一定要显式配置否则接口列表会加载不出来。6. 进阶技巧把流程历史查询性能提升 10 倍的索引设计与数据归档策略前面内容已经能让你跑通一条流程了。当流程实例数量从几百涨到几十万你会发现ACT_HI_*系列表成了查询瓶颈。此时不看引擎的 API 优化而是直接落到 MySQL8 的索引和数据生命周期上。我一般在流程实例量过十万的时候就执行一次索引优化。Flowable 6.8.1 自带了一些基础索引但它的设计是面向通用场景的没有照顾到你的特定查询模式。最常见的优化动作是给ACT_HI_TASKINST表加上基于PROC_INST_ID_和END_TIME_的联合索引因为绝大多数历史查询是「查某条流程下的所有历史任务按结束时间排序」。另一个很常用的做法是定期归档。Flowable 官方没有提供现成的归档功能我在某公司交付项目时是写了一个定时任务把ACT_HI_*表里结束超过 90 天的流程实例数据同步到归档库然后从主库删除。这里要特别提醒删除历史数据必须严格按照PROC_INST_ID_关联删除因为历史表之间没有外键约束漏删任何一张表都会导致流程历史显示不完整。这个工作流的调试技巧也值得分享每次启动流程前我会先看ACT_RE_PROCDEF表里最新部署的流程定义 key 和版本号。排查任务问题时第一步永远是看ACT_RU_TASK和ACT_HI_TASKINST的ASSIGNEE_和END_TIME_能立刻定位到任务卡在哪个节点、谁处理过。个人习惯是不管项目多急第一次写 Flowable 集成时都要先在本地把完整的启动、查询、完成链路跑通再往业务里嵌。那些跳过这一步直接改公司老项目的人后面花在排查环境问题上的时间往往比节省下来的多得多。希望这套方案能帮你把流程引擎稳稳地落到项目里。本文还有配套的精品资源点击获取