恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
SpringBoot集成Flowable Modeler实现流程可视化与审批流转
首页
资讯中心
/
SpringBoot集成Flowable Modeler实现流程可视化与审批流转
SpringBoot集成Flowable Modeler实现流程可视化与审批流转
发布时间:2026/9/12 14:09:59
简介对于需要在 Spring Boot 项目中集成 Flowable 工作流引擎并实现流程配置可视化的开发者可直接参考此完整工程包。包内包含 2000 个文件其中 JS 文件 412 个、HTML 288 个、CSS 52 个以这些前端静态资源为主配合 Java 后端源码、XML 流程定义、JSON 配置、properties 与 yml 配置文件可支撑 Flowable Modeler 的界面展示与流程设计功能同时包含 png、svg、gif 等图示文件便于对照图解说明理解集成细节。资源整体约 12.78MB压缩后轻量紧凑十分适合直接导入工程或按需提取核心配置其中少量 Java 源码可用于参考启动逻辑与接口分层Markdown 文档则能辅助快速梳理项目结构。目前已有 2276 人学习下载。通过该工程读者能掌握 SpringBoot 与 Flowable Modeler 的整合思路理清流程可视化涉及的前后端文件结构与关键配置项从而在实际项目中快速落地流程设计器提升开发效率。1. 为什么把流程引擎和可视化编辑器放在一个项目里工作流引擎落地的难点从来不在引擎本身而在“让业务人员敢自己改流程”。集成过 Flowable 的团队大多有这种经历流程定义文件BPMN画好了部署也成功但每次调整审批链路都要改 XML、重新部署、再清缓存业务方反复确认“这个节点是不是加在财务之后”一来一回消耗掉大量沟通成本。把 Flowable Modeler 嵌进 SpringBoot 项目核心是让流程配置这件事回到业务手里——在线拖节点、配网关、指定审批人保存后直接部署整个过程不离开应用本身。这篇讲的是这条链路的完整落地SpringBoot 里怎么配 Flowable、Modeler 怎么和主应用共享用户体系、发布后的流程如何发起和处理以及最后那张高亮流程图怎么画出来。适合正在做审批、工单、合同等流程类系统的后端工程师也适合被“流程可视化”这个需求反复纠缠过的前端同学对照着看后端提供的接口到底是什么形态。2. SpringBoot 集成 Flowable 的核心配置与初始化表2.1 依赖引入与版本选择SpringBoot 集成 Flowable 的第一步是引入官方 starter。常见做法是在pom.xml中加入flowable-spring-boot-starter它会自动装配 ProcessEngine、RuntimeService、TaskService、RepositoryService 等核心 Bean省去手动构建流程引擎的样板代码。dependency groupIdorg.flowable/groupId artifactIdflowable-spring-boot-starter/artifactId version6.x/version /dependency版本选择上有一个实际经验Flowable 6.x 系列对 SpringBoot 2.x 的支持最成熟如果你的项目是 SpringBoot 3.x需要核对 Flowable 官方仓库里对应版本的兼容矩阵直接用 6.x 的 starter 会出现 javax 与 jakarta 命名空间冲突。选版本的原则是“先定 SpringBoot 大版本再看 Flowable 的 release notes 里是否明确支持”不要贪新。2.2 数据源配置和自动建表策略Flowable 启动时会自动检查数据库中的表结构。默认策略是drop-create也就是每次启动都重建表这在开发阶段方便但一旦联调或预发环境重启就会清空已有流程数据。实际项目中应显式指定为true只在表不存在时创建。spring: datasource: url: jdbc:mysql://localhost:3306/flowable_demo?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghainullCatalogMeansCurrenttrue username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver flowable: database-schema-update: true async-executor-activate: false history-level: audit db-history-used: true check-process-definitions: true这段配置里有几个参数需要特别说明。database-schema-update是建表策略开关设为true只在表缺失时创建async-executor-activate控制异步执行器如果业务里没有用到定时器边界事件和异步任务建议关闭否则会额外启动后台线程池history-level控制历史数据记录的粒度audit是常用级别包含流程实例和任务的所有实例数据能支撑流程图高亮和审批记录查询db-history-used决定是否写入历史表check-process-definitions表示启动时扫描并部署resources/processes目录下的 BPMN 文件。数据库连接串里有个容易被忽略的参数nullCatalogMeansCurrenttrue。MySQL 8.x 下如果不加这个参数Flowable 建表时会扫描整个 catalog导致“表已存在”的误判。2.3 首次启动后的关键表解析启动后数据库会自动生成几十张表按用途可以分成四组。理解分组是后续排错的基础表前缀用途典型表ACT_RE_流程定义与模型存储ACT_RE_DEPLOYMENT、ACT_RE_PROCDEFACT_RU_运行时数据流程结束后清理ACT_RU_TASK、ACT_RU_EXECUTION、ACT_RU_VARIABLEACT_HI_历史数据流程结束后保留ACT_HI_PROCINST、ACT_HI_TASKINST、ACT_HI_ACTINSTACT_ID_用户、组与关系ACT_ID_USER、ACT_ID_GROUP、ACT_ID_MEMBERSHIP需要注意 ACT_RU_ 和 ACT_HI_ 的区别一个流程实例运行期间的待办任务、执行分支、变量都写在 ACT_RU_流程一旦结束这些记录会被引擎异步删除而 ACT_HI_ 只追加不删除用来追溯完整链路。如果发现某个流程结束后查不到运行时任务不要慌去 ACT_HI_ 里查历史记录就好。集成阶段最常见的报错是“表不存在”和“列不存在”前者通常是database-schema-update没配对后者往往是升级版本后旧表缺新字段需要手动执行官方提供的 upgrade SQL 脚本不要直接删表重建。确认集成的验证方式通常是一段启动日志出现 Flowable 6.x 或者 ProcessEngine created 的字样。3. Flowable Modeler 流程配置可视化接入方案3.1 可视化编辑器不是唯一选项但要选就选官方 Modeler流程可视化在开源领域有几套方案基于 BPMN.js 自研编辑器、集成 Flowable Modeler、集成 Activiti Modeler。三者对比下来Flowable Modeler 的优势在于模型数据与引擎原生打通——它保存的是 BPMN XML部署时直接走 RepositoryService不需要额外做模型转换。BPMN.js 灵活性强但要自己完成模型校验、节点属性面板和部署逻辑工作量远大于预期。选 Flowable Modeler 的潜台词是把可视化当成流程引擎的“前端视图”而不是独立产品。3.2 官方 Modeler 的两种接入路线接入 Flowable Modeler 有两种成熟路线。第一种是把flowable-ui-modeler作为独立 Web 应用部署通过反向代理和主应用共享域名第二种是把 Modeler 静态资源放进 SpringBoot 的 static 目录由主应用直接托管页面。前者适合独立部署、独立升级后者适合中小团队省一套服务。实际操作中官方发布包里的 Flowable UI 是一个完整的 Spring Boot 应用包含了 Modeler、IDM身份管理、Admin 等模块。只想要 Modeler 的团队普遍做法是把flowable-ui-modeler相关的前端资源和后端 Controller 摘出来放进自己的项目。这个“摘”的过程是集成的主要工作量复制flowable-ui-modeler的静态资源modeler 相关的 HTML、JS、CSS到src/main/resources/static/modeler目录。引入 Modeler 后端接口依赖flowable-ui-modeler-rest它会提供/modeler前缀下的模型 CRUD 接口。处理静态资源放行确保 SpringSecurity 不拦截 Modeler 页面的资源请求。spring: security: filter: dispatcher-types: async, request如果主应用使用 Spring Security需要把/modeler/**在配置类中放行或者要求用户先登录主应用再进入 Modeler。推荐后者因为流程设计器本身不应该是匿名可访问的。3.3 用户体系和登录认证的接缝处理Flowable Modeler 自带的用户体系基于 ACT_ID_ 表和业务系统的用户表是两套数据。常见做法是通过 Flowable 的IdmIdentityService在用户登录时同步一份用户到 ACT_ID_USER并维护成员关系表。这个同步动作在注册和修改用户信息的入口埋点即可。如果你不想引入 Flowable 的用户体系也可以直接写一个过滤器拦截 Modeler 的 Rest API 请求从主应用的 Session 里解析登录态再把当前用户塞进 Flowable 的 Authentication 上下文Component public class FlowableAuthFilter extends OncePerRequestFilter { Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { User currentUser (User) request.getSession().getAttribute(currentUser); if (currentUser ! null) { Authentication.setAuthenticatedUserId(currentUser.getId().toString()); } chain.doFilter(request, response); } }这里的关键点是每次请求都要重新设置认证用户因为 Flowable 的 Authentication 是 ThreadLocal请求结束后就被清空。如果漏配你在 Modeler 里看到的创建人就会变成 null部署记录也会缺失操作人信息。Modeler 接入完成后验证手段很简单打开模型列表、新建流程、拖拽节点并保存然后去 ACT_RE_DEPLOYMENT 表里看是否多了一条模型部署记录。4. 流程发布、发起与任务流转的代码落地4.1 用编程方式部署流程定义流程模型在 Modeler 里保存后它的状态是“已保存”而不是“已部署”。要让它真正生效需要调用 RepositoryService 完成部署。常见的做法是在模型列表页面加一个“发布”按钮后端接口从 ACT_RE_MODEL 取出模型 BPMN 数据再创建部署。PostMapping(/deploy/{modelId}) public String deploy(PathVariable String modelId) { Model model repositoryService.getModel(modelId); byte[] bpmnBytes repositoryService.getModelEditorSource(modelId); if (bpmnBytes null) { throw new BusinessException(模型数据为空请先保存流程设计); } String processKey model.getKey(); Deployment deployment repositoryService.createDeployment() .name(model.getName()) .key(processKey) .addString(processKey .bpmn20.xml, new String(bpmnBytes, StandardCharsets.UTF_8)) .enableDuplicateFiltering() .deploy(); return deployment.getId(); }enableDuplicateFiltering()的作用是避免同一份 BPMN 文件重复部署。没有这个方法时每次都生成新版本号久而久之 ACT_RE_PROCDEF 里堆积大量无用版本。这个方法内部校验部署文件的 MD5 和名称相同则跳过返回值是 null所以调用后要判断 deployment 是否为空。流程定义的版本管理依赖 ACT_RE_PROCDEF 的 VERSION 字段每次部署递增但业务层面通常只关心最新版本。提示如果模型修改后没有重新部署发起流程时用的仍是旧版本。排查“改了的流程没生效”时先查 ACT_RE_PROCDEF 的 VERSION 和 DEPLOYMENT_ID。4.2 发起流程并绑定业务 Key发起流程是 RuntimeService 的职责。流程实例必须和一个业务单据关联才能在审批完成后反向找到业务数据。这个关联通过 businessKey 实现。PostMapping(/start) public String startProcess(RequestBody StartRequest req) { String processKey req.getProcessKey(); String businessKey req.getBusinessKey(); MapString, Object variables new HashMap(); variables.put(applyUser, req.getApplyUser()); variables.put(days, req.getDays()); variables.put(reason, req.getReason()); ProcessInstance instance runtimeService.startProcessInstanceByKey(processKey, businessKey, variables); return instance.getId(); }startProcessInstanceByKey的三个参数依次是流程定义 Key、业务单据主键、流程变量 Map。落地时有两点需要留意。第一是流程变量不要塞大量对象Flowable 会把变量序列化存入 ACT_RU_VARIABLE复杂对象会牵出多张关联表查询效率下降第二是如果要保证“同一单据不能重复发起”需要自己在业务代码加唯一校验引擎层不做这类限制。businessKey 在发起后可以通过runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult()反查等同于给流程实例加了一个业务索引。4.3 查询待办和完成任务审批人打开待办列表时查询的是 ACT_RU_TASK本质上是 TaskService 的职责范围。常见做法是按 candidateUser 或 assignee 两种维度查流程设计时指定了“候选人组”就用 candidate 查询指定了“审批人”就用 assignee 查询。GetMapping(/todos) public ListTodoVO todos(RequestParam String userId) { ListTask tasks taskService.createTaskQuery() .taskCandidateUser(userId) .active() .orderByTaskCreateTime() .desc() .listPage(0, 20); return tasks.stream().map(task - { ProcessInstance pi runtimeService.createProcessInstanceQuery() .processInstanceId(task.getProcessInstanceId()) .singleResult(); TodoVO vo new TodoVO(); vo.setTaskId(task.getId()); vo.setProcessKey(pi.getProcessDefinitionKey()); vo.setBusinessKey(pi.getBusinessKey()); vo.setName(task.getName()); vo.setCreateTime(task.getCreateTime()); return vo; }).collect(Collectors.toList()); }active()是容易被忽略的过滤条件它排除挂起suspended的流程实例产生的任务。流程设计里经常有定时暂停的场景如果不过滤已挂起流程的任务会继续出现在待办里审批人点击后报错。完成任务时至少要传入审批结论和批注PostMapping(/complete/{taskId}) public void complete(PathVariable String taskId, RequestBody CompleteRequest req) { MapString, Object variables new HashMap(); variables.put(approved, req.getApproved()); variables.put(comment, req.getComment()); taskService.complete(taskId, variables); }这里的approved会驱动排他网关的分支判断值必须是 Boolean 类型如果在流程 XML 里配了${approved true}这样的条件字符串true会导致条件不成立流程走向错误分支。这是网关判断时最常见的坑类型不一致排在第一位。4.4 常用 API 参数对照表方法用途关键参数失败时的异常repositoryService.createDeployment()部署流程定义addString、name、keyActivitiExceptionBPMN 解析失败runtimeService.startProcessInstanceByKey()发起流程processDefinitionKey、businessKey、variablesActivitiObjectNotFoundException流程定义不存在taskService.createTaskQuery()查询任务taskCandidateUser、taskAssignee、active无异常返回空列表taskService.complete()完成任务taskId、variablesActivitiTaskAlreadyClaimedException任务已办historyService.createHistoricProcessInstanceQuery()查询历史流程processInstanceId、finished无异常返回 null后端完成这些能力后前端的流转可视化就有数据基础了。流程图高亮不再需要前端解析 BPMN XML后端直接把节点坐标和高亮节点编号交给前端渲染在下一章展开。5. 流程配置可视化的进阶细节流程图高亮与数据清理5.1 动态渲染流程图并高亮当前节点流程配置可视化的完整闭环不只是“能画能发布”还包括流程运行后的状态可视化——当前流转到哪个节点、哪些历史分支已经走过。后端生成高亮流程图是常见做法前端只负责展示图片避免在浏览器里二次解析 BPMN 的兼容性问题。GetMapping(/diagram/{processInstanceId}) public void diagram(PathVariable String processInstanceId, HttpServletResponse response) throws IOException { ProcessInstance pi runtimeService.createProcessInstanceQuery() .processInstanceId(processInstanceId) .singleResult(); BpmnModel bpmnModel; ListString activeActivityIds new ArrayList(); if (pi ! null) { bpmnModel repositoryService.getBpmnModel(pi.getProcessDefinitionId()); activeActivityIds runtimeService.getActiveActivityIds(processInstanceId); } else { HistoricProcessInstance hpi historyService.createHistoricProcessInstanceQuery() .processInstanceId(processInstanceId) .singleResult(); bpmnModel repositoryService.getBpmnModel(hpi.getProcessDefinitionId()); } ProcessDiagramGenerator generator new DefaultProcessDiagramGenerator(); InputStream is generator.generateDiagram(bpmnModel, png, activeActivityIds, Collections.emptyList(), 宋体, 宋体, 宋体, ClassLoaderUtils.getClassLoader(), 1.0, true); response.setContentType(image/png); IOUtils.copy(is, response.getOutputStream()); }这个方法画出的图片里运行中的节点会高亮显示。关键在ProcessDiagramGenerator的 8 个参数其中activeActivityIds传入当前活动的节点 ID引擎会在对应坐标上绘制出高亮边框后面的两个字体参数分别指定节点名称和边框文字的字体中文环境不指定字体画出来的图全是豆腐块。true表示节点名称按多行换行绘制。流程结束后runtimeService.getActiveActivityIds返回空此时需要回退查历史表拿到完成状态或者干脆只画静态图由前端根据历史节点列表自己叠加标记。5.2 运行时数据的归档与清理Flowable 集成的后期问题多半不是功能缺失而是数据膨胀。ACT_RU_ 表在流程结束后自动删除但 ACT_HI_ 表只增不减半年后单表轻松过百万行。历史数据的清理策略直接影响查询性能和备份体量。常用做法是写一个定时任务按月归档已经结束的流程实例的历史记录。Flowable 提供了historyService.deleteHistoricProcessInstance方法但实际操作中不要直接删而是先导出到归档表或者冷存储。Component public class HistoryCleanJob { Scheduled(cron 0 0 2 * * ?) public void archiveHistory() { ListHistoricProcessInstance finishedList historyService.createHistoricProcessInstanceQuery() .finished() .finishedBefore(new Date(System.currentTimeMillis() - 180L * 24 * 3600 * 1000)) .listPage(0, 500); for (HistoricProcessInstance hpi : finishedList) { // 归档逻辑写入归档表或导出文件 historyService.deleteHistoricProcessInstance(hpi.getId()); } } }finishedBefore是清理任务的核心过滤条件这里取 180 天前结束的流程。注意listPage(0, 500)分页必须保留一次性查全部会拖垮数据库。删除一个流程实例会级联清理它的任务、活动、变量等历史记录但不会影响运行时数据因为能查出来的都是已结束实例。如果将来需要审计追溯建议归档表保留原始 BPMN XML 和变量快照Flowable 的HistoricVariableInstance里保存的是序列化对象脱离引擎环境后不便阅读。流程配置可视化项目的收尾工作通常集中在两个点一是确认流程图中所有节点类型用户任务、排他网关、并行网关、子流程都能在前端正确渲染二是验证权限边界——谁能画流程、谁能发布流程、谁能查看全部实例的流程图这三类权限在可视化场景里最容易混淆。把这两个点验证通过这套流程配置可视化链路就可以交给业务方使用了。本文还有配套的精品资源点击获取