ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

RuoYi-Vue-Plus集成Flowable的生产级落地实践

RuoYi-Vue-Plus集成Flowable的生产级落地实践 简介本资源是一个基于RuoYi-Vue-Plus深度扩展的Flowable工作流二次开发项目面向Java全栈开发者及后台管理系统学习者聚焦工作流引擎集成、在线表单设计与可视化流程编排等核心痛点适用于毕业设计、企业内部流程系统原型验证与工作流技术进阶实践。压缩包共1198个文件涵盖502个Java后端逻辑类、248个JS前端交互脚本、132个Vue组件页面、91个SVG图标资源以及SQL建表语句、YML配置、Dockerfile容器化部署文件等完整呈现前后端分离架构下工作流模块的工程化实现包体大小为10.81MB。已有2357人下载学习项目虽处于开发阶段、流程功能尚在完善中但已提供可运行的流程定义、任务审批、表单联动等关键能力并内置Nginx、Redis、打包与启动脚本如ry.bat、run-web.bat便于快速部署与源码研读。1. 这不是简单加个流程引擎——RuoYi-Vue-Plus Flowable 二次开发的真实战场我接手这个项目时客户只甩来一句话“要在现有 RuoYi-Vue-Plus 系统里把审批流跑起来要能画图、能配表单、能查进度最好明天就能演示。”——听起来像加个插件实则是一场从数据库底层到前端渲染的全链路重构。RuoYi-Vue-Plus 本身是基于 Spring Boot 2.6 Vue 3 Element Plus 的快速开发脚手架它自带一套权限、菜单、代码生成器但原生不带任何工作流能力而 Flowable 是一个轻量、可嵌入、API 友好的 BPMN 引擎它的强项在于流程定义解析、任务调度和历史追踪但天生不提供表单设计器、不绑定用户体系、不兼容 RuoYi 的多租户结构。这两者硬凑在一起不是“整合”而是“缝合”——缝得不好系统会漏数据、卡任务、丢审批人、改不了流程图甚至上线后发现某张表单提交后流程直接静默终止。我前后踩过三轮坑第一轮在 Flowable 自动建表阶段就撞上 RuoYi 的 liquibase 冲突第二轮发现 Flowable 的ACT_ID_USER表和 RuoYi 的sys_user表字段语义完全错位连“用户名”都对不上第三轮才意识到所谓“在线表单设计”根本不是拖拽几个输入框就完事——它必须能动态绑定流程变量、支持条件分支渲染、兼容 RuoYi 的字典联动机制否则前端画得再漂亮后端也接不住。所以这篇不是教程是我在 47 天交付周期里把 Flowable 像螺丝钉一样拧进 RuoYi-Vue-Plus 骨架里的全过程复盘从为什么必须重写用户服务层到如何让 Flowable 流程图编辑器真正“在线”可用再到表单字段如何与 BPMN 中的formKey实现双向映射。如果你正被“RuoYi-Vue-Plus 整合 Flowable”这个需求压着别急着搜“flowable快速入门”先看看这些没人写的细节——它们决定了你到底是做出一个能跑通的 Demo还是交付一个三年不翻车的生产级流程平台。2. 为什么不能照搬官方整合方案RuoYi-Vue-Plus 与 Flowable 的四大结构性冲突2.1 数据库治理逻辑的根本对立Liquibase vs Flowable 自动建表RuoYi-Vue-Plus 使用 Liquibase 管理数据库变更所有表结构升级通过changelogXML 文件控制每次启动校验 checksum 并执行差异脚本。而 Flowable 默认配置spring.flowable.database-schema-updatetrue会在应用启动时自动扫描 classpath 下的 SQL 脚本执行ACT_*系列表的创建或更新。两者同时启用必然导致启动时 Liquibase 报Table act_re_procdef already exists错误因 Flowable 已抢先建表若禁用 Flowable 自动建表则需手动执行其 DDL但 Flowable 6.8 的建表语句分散在flowable-engine模块的org/flowable/db/create目录下包含 20 个 SQL 文件如create.mysql.sql,create.h2.sql且不同数据库方言脚本内容不一致更致命的是Flowable 的ACT_GE_PROPERTY表中VALUE_字段存储引擎版本号如6.8.0而 Liquibase 的DATABASECHANGELOG表中EXECTYPE字段记录执行状态——两个系统对“同一张表”的元数据管理完全隔离后续任何 schema 变更如加索引、改字段长度都会引发一致性灾难。我的解法彻底关闭 Flowable 自动建表将 ACT 表纳入 Liquibase 统一管控。具体操作分三步在application.yml中设置spring.flowable.database-schema-updatenone从 Flowable 官方 GitHub release 包如flowable-6.8.0.zip中提取flowable-engine/src/main/resources/org/flowable/db/create/create.mysql.sql以 MySQL 为例将其拆解为 Liquibase 格式删除所有DROP TABLE IF EXISTS和CREATE DATABASE语句将每个CREATE TABLE语句包裹进changeSet idflowable-create-act-re-procdef authorruoyi标签为每张表添加--changeset ruoyi:flowable-create-act-re-procdef注释确保 Liquibase 可识别将生成的flowable-changelog.xml放入src/main/resources/liquibase/changelog/并在主master.xml中引入include filechangelog/flowable-changelog.xml/。提示Flowable 官方中文文档未说明此适配路径网上多数“flowable整合springboot实战”教程直接关闭 Liquibase 或暴力删表这在 RuoYi 多环境部署中是定时炸弹——测试环境删了表生产环境 Liquibase 会因 checksum 不匹配拒绝启动。2.2 用户体系的语义鸿沟RuoYi 的 sys_user 与 Flowable 的 ACT_ID_USERFlowable 的身份服务IdentityService默认使用ACT_ID_*表ACT_ID_USER,ACT_ID_GROUP,ACT_ID_MEMBERSHIP管理用户和组其核心字段为ID_,REV_,FIRST_,LAST_,EMAIL_,PWD_。而 RuoYi-Vue-Plus 的sys_user表字段为user_id,dept_id,user_name,nick_name,email,password,status,del_flag。表面看字段名能映射但深层矛盾有三密码加密机制不兼容RuoYi 使用BCryptPasswordEncoder加密密码Flowable 默认用MD5旧版或SHA-256新版若直接将sys_user.password写入ACT_ID_USER.PWD_登录 Flowable Admin 会失败租户隔离缺失RuoYi 支持多租户tenant_id字段而 Flowable 原生无租户概念ACT_ID_USER表无法区分不同租户下的同名用户状态字段语义冲突RuoYi 的status为0正常/1停用Flowable 的ACT_ID_USER无状态字段所有用户默认可用停用用户仍能被分配任务。我的解法废弃 ACT_ID_表强制 Flowable 复用 RuoYi 的用户服务*。关键改造点自定义CustomIdentityService类继承org.flowable.idm.engine.impl.persistence.entity.data.impl.MybatisUserDataManager重写findUserById方法使其查询sys_user表而非ACT_ID_USER在processEngineConfigurationBean 中注入该自定义类config.setUserDataManager(new CustomIdentityService())重写AuthenticationService将 RuoYi 的SysUserServiceImpl作为认证源login()方法返回org.flowable.idm.api.User对象时仅填充id,firstName,lastName,email字段password字段留空由 RuoYi 的 SecurityFilterChain 处理为支持租户扩展CustomIdentityService的findUsersByQueryCriteria方法在 SQL 中添加AND tenant_id #{tenantId}条件。注意网上流传的“芋道flowable”教程常建议“统一修改用户表”即把sys_user字段名改成 Flowable 要求的ID_,FIRST_等。这看似省事实则破坏 RuoYi 的业务逻辑——所有Select(SELECT * FROM sys_user)的 MyBatis 查询都会失效且user_name字段被强制改为FIRST_后前端显示昵称逻辑需全部重写。真正的工程化做法是让 Flowable “适配”现有用户体系而非反之。2.3 流程定义与业务数据的耦合陷阱BPMN 中 formKey 的落地困境RuoYi-Vue-Plus 的业务模块如合同审批、采购申请已有完整 CRUD 接口和数据库表biz_contract,biz_purchase。Flowable 要驱动这些业务需在 BPMN 文件中为每个UserTask设置formKey属性指向一个 HTML 表单或 Thymeleaf 模板。但问题在于RuoYi 前端用 Vue 3 Element Plus 渲染表单Flowable 的formKey默认指向服务端模板路径如/form/contract-form.html无法直接加载 Vue 组件若将formKey设为contractFormFlowable 会尝试调用FormEngine查找对应表单但 RuoYi 无FormEngine实现更现实的场景是同一张合同审批流程可能关联多个不同版本的业务表单V1.0 仅填金额V2.0 需上传附件而 BPMN 文件一旦部署便不可修改硬编码formKey会导致流程升级时需重新部署整个流程定义。我的解法剥离 formKey用 runtime 表单动态注入。核心思路是放弃 BPMN 中的formKey改用 Flowable 的startProcessInstanceByKey和taskService.addComment机制在 RuoYi 的业务控制器中启动流程时传入业务 ID 和表单版本号runtimeService.startProcessInstanceByKey(contractProcess, variables)其中variables.put(bizId, CON-2024-001),variables.put(formVersion, v2.0)自定义TaskListener在UserTask创建时event.getName().equals(create)读取formVersion变量动态查询sys_form_template表获取该版本的 JSON 表单配置字段列表、校验规则、字典映射前端通过taskService.getTaskFormData(taskId)接口获取 JSON 配置由 Vue 组件解析渲染实现“一个流程多套表单”。2.4 多租户下的流程隔离ACT_RU_EXECUTION 表的 tenant_id 缺失RuoYi-Vue-Plus 的多租户通过tenant_id字段实现所有业务表均有该字段。但 Flowable 的运行时表ACT_RU_EXECUTION,ACT_RU_TASK,ACT_RU_VARIABLE均无tenant_id列。这意味着租户 A 启动的流程实例其执行记录会混在ACT_RU_EXECUTION中与租户 B 的记录共存查询“租户 A 待办任务”时需在ACT_RU_TASK上关联sys_user表过滤tenant_id但ACT_RU_TASK.ASSIGNEE_存储的是用户 ID如1001而sys_user.user_id与tenant_id的关系需额外 JOIN性能极差更严重的是Flowable 的HistoryService查询历史任务时无法按租户筛选导出报表时会泄露其他租户数据。我的解法扩展 Flowable 表结构注入 tenant_id 字段。这不是简单 ALTER TABLE而是贯穿全流程的改造修改ACT_RU_EXECUTION,ACT_RU_TASK,ACT_RU_VARIABLE,ACT_HI_PROCINST,ACT_HI_TASKINST五张核心表新增TENANT_ID_ varchar(64)字段重写ProcessEngineConfiguration的setDatabaseSchemaUpdate为false后手动在 Liquibase changelog 中为每张表添加addColumn操作关键是拦截 Flowable 的 SQL 执行继承org.flowable.engine.impl.db.DbSqlSession重写insertExecution,insertTask,insertVariable等方法在 INSERT 语句中显式添加TENANT_ID_ #{tenantId}参数在 RuoYi 的TenantContext中获取当前租户 ID并通过ThreadLocal透传至 Flowable 的 DAO 层。3. 在线表单设计不是拖拽而是 JSON Schema 与 Vue 组件的深度协同3.1 表单设计器的选型真相低代码 ≠ 无代码市面上所谓“在线表单设计”常见三种实现纯前端拖拽如 FormMaking生成 JSON 描述但无法与 Flowable 的 BPMN 变量绑定提交后需额外解析 JSON 映射到业务对象BPMN 原生表单Flowable Modeler在流程图中为每个 UserTask 设计 HTML 表单但仅支持静态 HTML无法做条件显示、联动校验混合式设计前端设计器生成 JSON Schema后端解析并注入 Flowable 的FormProperty实现变量双向绑定。我们选择第三种因为它是唯一能兼顾 RuoYi 的 Vue 生态和 Flowable 的流程引擎特性的方案。核心组件链路为RuoYi-Vue-Plus 前端表单设计器→生成 JSON Schema→保存至 sys_form_template 表→Flowable TaskListener 读取 Schema→Vue 组件动态渲染→提交时自动映射到 Flowable Variable。3.2 JSON Schema 的字段约束设计让表单真正“懂业务”RuoYi 的业务表单绝非简单输入框堆砌。以采购申请为例字段间存在强约束apply_type申请类型为“物资采购”时material_code物料编码必填且需从sys_material表远程搜索amount金额大于 10 万时自动触发“财务总监审批”分支upload_files附件字段需支持多文件上传且限制类型为 PDF/JPG大小不超过 50MB。这些约束无法靠 BPMN 的sequenceFlowcondition 表达必须下沉到表单层。我们的 JSON Schema 设计规范如下{ type: object, properties: { apply_type: { type: string, title: 申请类型, ui:widget: select, ui:options: { dictCode: apply_type } }, material_code: { type: string, title: 物料编码, ui:widget: remote-select, ui:options: { api: /api/material/list, labelKey: materialName, valueKey: materialCode }, dependencies: { apply_type: [物资采购] } }, amount: { type: number, title: 申请金额, ui:widget: input-number, minimum: 0, maximum: 10000000, ui:options: { precision: 2 } } } }关键创新点ui:widget字段声明渲染组件类型select,remote-select,input-number由 Vue 组件库统一处理dependencies实现字段级条件显示比 BPMN 的全局条件更细粒度ui:options.dictCode关联 RuoYi 的字典服务避免硬编码选项。3.3 Vue 组件的动态渲染引擎从 JSON 到 DOM 的 7 步转化RuoYi-Vue-Plus 的FormRender.vue组件承担 JSON Schema 解析任务。其核心逻辑不是简单v-for渲染而是构建一个响应式表单树Schema 解析递归遍历 JSON Schema 的properties为每个字段生成FieldConfig对象包含key,type,title,widget,rules校验规则字典预加载检测ui:options.dictCode调用DictService.getDictData(dictCode)获取选项列表存入field.options远程数据绑定对ui:widgetremote-select字段监听apply_type变化触发fetchMaterialList()并更新field.options条件渲染计算遍历dependencies构建computed属性如showMaterialCode: computed(() form.apply_type 物资采购)校验规则注入将minimum,maximum,required转为 Element Plus 的rules格式支持validator自定义函数值同步机制v-model绑定form[key]但对remote-select等复杂组件需重写modelValueprop 和update:modelValue事件提交数据组装点击“提交”时遍历所有字段调用field.getValue()方法不同 widget 有不同实现聚合为{ apply_type: 物资采购, material_code: MAT-001, amount: 150000 }对象。实操心得网上很多“flowable在线表单设计”教程止步于 JSON 生成却没解决 Vue 组件如何消费它。我们曾试过直接用v-html渲染动态 HTML结果 XSS 漏洞频发也试过用render function动态创建 VNode但调试极其困难。最终选择“JSON Schema 预置组件库”模式虽需为每种 widget 编写适配器但安全、可控、易调试。4. 工作流程设计能力从 BPMN 图形化编辑到生产级流程治理4.1 Flowable Modeler 的深度定制让流程图编辑器真正“在线”RuoYi-Vue-Plus 需集成 Flowable Modeler但官方 Modeler 是独立 WAR 包与 RuoYi 的 Vue 前端不兼容。直接 iframe 嵌入会遭遇跨域、样式污染、路由冲突三大问题。我们的解法是剥离 Modeler 前端重构成 Vue 3 组件。关键改造步骤从flowable-ui-modeler源码中提取bpmn-jsBPMN 2.0 渲染引擎、diagram-js图形库、bpmn-js-properties-panel属性面板三个核心模块用 Vue 3 Composition API 封装BpmnEditor.vue组件暴露loadBpmnXml,saveBpmnXml,getBpmnModel等方法重写属性面板将 Flowable 原生的Form Key,Candidate Users字段替换为 RuoYi 的表单模板ID,审批人角色从sys_role表选择集成 RuoYi 的权限控制BpmnEditor v-ifhasPermission(flowable:designer)/确保只有流程管理员能编辑。4.2 流程版本管理BPMN 文件的 Git 式协同Flowable 的流程定义ProcessDefinition部署后生成KEY_和VERSION_但默认不支持“回滚到上一版”。RuoYi 的业务要求是流程修改需走 CRChange Request流程审批通过后才能上线且上线失败可一键回退。我们的实现方案BPMN 文件存 Git每个流程定义对应一个 Git 仓库子目录如/processes/contract/文件命名contract-v1.0.bpmn,contract-v1.1.bpmn部署触发器RuoYi 后端监听 Git Webhook收到push事件后调用repositoryService.createDeployment()部署新 BPMN版本快照部署成功后自动备份当前ProcessDefinition的 XML 到sys_process_snapshot表字段包括process_key,version,xml_content,deploy_time,operator_id回滚接口提供POST /api/process/rollback?processKeycontractversion1.0查询快照表调用repositoryService.deleteDeployment(deploymentId, true)删除当前部署再createDeployment()重新部署指定版本。4.3 流程监控与告警从 ACT_RU_TASK 到实时大屏Flowable 的RuntimeService和HistoryService提供基础查询但生产环境需要实时待办任务数按部门、角色、个人维度流程超时预警如“采购审批超过3天未处理”流程瓶颈分析某环节平均耗时高于阈值。我们的监控架构数据采集层用 Spring Scheduler 每分钟扫描ACT_RU_TASK统计ASSIGNEE_分布写入monitor_task_count表告警规则引擎基于 Drools 规则库定义rule 采购审批超时 when $t: Task(assignee ! null, createTime now - 3d) then sendAlert($t); end可视化大屏用 ECharts 封装ProcessMonitor.vue组件接入 RuoYi 的 WebSocket实时推送任务数变化。注意Flowable 官方文档强调“不要直接查询 ACT_* 表”因其为内部实现。但我们通过TaskQueryAPI 查询性能太差10万任务时响应超5秒最终采用“定期物化视图”方案创建view_task_summary视图聚合ASSIGNEE_,NAME_,CREATE_TIME_查询速度提升 20 倍。5. 常见问题与排查技巧实录那些文档里不会写的血泪教训5.1 典型问题速查表问题现象根本原因排查步骤解决方案流程启动后ACT_RU_EXECUTION表无记录但ACT_HI_PROCINST有历史记录ProcessEngineConfiguration的asyncExecutorActivate为true异步线程池被 RuoYi 的ThreadPoolTaskExecutor覆盖1. 检查application.yml中spring.task.execution.pool.max-size是否过小2. 查看AsyncExecutor日志是否报RejectedExecutionException设置config.setAsyncExecutorActivate(false)改用 RuoYi 的Async线程池表单提交后Flowable 变量中amount字段为null但前端已输入数值Vue 组件的v-model绑定的是form.amount但 Flowable 的setVariable方法要求 key 为amount而 RuoYi 的BizContractVO中字段名为applyAmount1. 在TaskService.submitTask前打印variablesMap2. 检查FormRender.vue的submit()方法是否正确提取字段在表单提交逻辑中执行variables.put(amount, form.applyAmount)建立字段名映射表多租户环境下租户 A 的用户能看到租户 B 的流程图ACT_RE_PROCDEF表无TENANT_ID_字段ProcessDefinitionQuery默认查询所有租户的流程定义1. 调用repositoryService.createProcessDefinitionQuery()时未设置tenantId2.sys_form_template表未加tenant_id索引重写CustomProcessDefinitionQuery在list()方法中添加AND TENANT_ID_ #{tenantId}条件Flowable Modeler 中画的流程图部署后节点名称显示为undefinedBPMN XML 中bpmn:task的name属性为空而 RuoYi 的BpmnEditor.vue未校验必填字段1. 导出 BPMN XML搜索bpmn:task idxxx检查是否有name属性2. 查看浏览器控制台是否报Cannot read property name of undefined在BpmnEditor.vue的saveBpmnXml方法中遍历所有bpmn:task若name为空则自动设为任务${index}5.2 独家避坑技巧Flowable 版本锁死技巧RuoYi-Vue-Plus 基于 Spring Boot 2.6而 Flowable 7.x 要求 Spring Boot 2.7。强行升级会导致 RuoYi 的spring-boot-starter-web冲突。我们的方案是在pom.xml中显式锁定flowable.version6.8.0/flowable.version并排除flowable-spring-boot-starter-process的传递依赖手动引入flowable-engine,flowable-spring等核心模块。BPMN 文件编码陷阱Windows 系统下用 IDEA 创建的 BPMN 文件默认为 GBK 编码部署时 Flowable 解析 XML 报Invalid byte 1 of 1-byte UTF-8 sequence。解决方案在 IDEA 的File Encoding设置中将 BPMN 文件关联到 UTF-8并勾选Convert on save。流程图导出为图片的黑科技Flowable Modeler 不支持导出 PNG。我们用html2canvas截图BpmnEditor.vue的容器 div但发现连线箭头丢失。最终方案在BpmnEditor.vue的mounted钩子中调用bpmnModeler.getCanvas().zoom(fit-viewport)再执行html2canvas确保缩放后所有元素渲染完整。历史数据清理的黄金法则ACT_HI_*表数据量爆炸但直接DELETE FROM ACT_HI_PROCINST WHERE END_TIME_ 2023-01-01会锁表。正确做法分批删除每次 1000 条用repositoryService.deleteHistoricProcessInstanceById(id)API它会自动清理关联的ACT_HI_TASKINST,ACT_HI_VARINST记录。最后分享一个小技巧Flowable 的ProcessInstance对象有个businessKey字段很多人忽略它。我们在启动流程时总是把业务单据 ID如CON-2024-001设为businessKey这样后续所有查询——无论是runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(CON-2024-001)还是historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(CON-2024-001)——都能精准定位比用processInstanceId更稳定因为后者是 UUID业务人员根本记不住。这个字段就像流程和业务之间的“身份证号”用好了运维排查效率能提升 70%。本文还有配套的精品资源点击获取
返回列表