基于RuoYi-Vue-Plus与Flowable的可视化工作流与表单设计器集成实践

基于RuoYi-Vue-Plus与Flowable的可视化工作流与表单设计器集成实践 简介本资源是一个基于RuoYi-Vue-Plus深度扩展的Flowable工作流二次开发项目面向Java后端开发者与后台管理系统学习者聚焦工作流场景下的表单在线设计、流程建模与任务调度能力构建。项目完整集成Flowable引擎同步更新RuoYi-Vue-Plus脚手架功能采用MIT协议开源适用于毕业设计、企业内部流程系统原型验证及工作流技术进阶实践。压缩包共1198个文件含502个Java核心业务与流程服务类、248个JS前端交互逻辑、132个Vue组件覆盖流程图渲染、表单设计器等关键界面、91个SVG图标资源及53个Flowable相关XML流程定义文件整体体积10.81MB。已有2357人下载学习提供开箱即用的本地运行脚本如ry.bat、run-web.bat、Nginx与Redis配置模板、AdminLTE主题样式及完整SQL初始化脚本便于快速部署与源码级调试。1. 项目概述与核心价值最近在做一个内部审批系统的升级客户那边提了个硬性要求审批流程要能灵活配置表单样式还得能在线拖拽设计不能总让我们开发去改代码。这需求一听不就是典型的工作流引擎场景嘛。市面上成熟的方案不少像Activiti、Camunda还有我们这次选中的Flowable都是久经考验的。但光有引擎还不够得有一个好用的“驾驶舱”来管理它这就是RuoYi-Vue-Plus这类开源后台框架的价值所在了。这个项目本质上就是在RuoYi-Vue-Plus这个优秀的“车身”上集成并深度扩展Flowable这个强大的“发动机”最终打造出一套支持可视化流程设计和在线表单设计的开箱即用解决方案。简单来说它解决了几个核心痛点第一流程定义与业务系统脱节。传统开发模式下流程引擎往往作为一个独立服务流程设计、表单设计、业务数据流转是割裂的开发和维护成本高。我们这个项目将它们无缝整合进一个统一的管理后台。第二表单设计僵化。很多工作流系统表单是硬编码的业务一变就要重新发布。我们实现的在线表单设计器让业务人员也能通过拖拽组件的方式快速定义审批单的样式和字段。第三学习与部署成本。Flowable功能强大但配置复杂RuoYi-Vue-Plus提供了清晰的前后端分离架构和基础功能模块。我们的二次开发相当于把Flowable的复杂能力进行了“平民化”封装让开发者能更专注于业务逻辑而不是引擎本身的配置。这套方案非常适合需要快速构建企业内部流程化应用OA、ERP、CRM中的审批模块的团队。无论你是想学习Spring Boot Vue前后端分离架构下如何集成工作流还是手头正好有类似的项目需求希望找到一个功能相对完整、可二次开发的起点这个项目的思路和实现细节都值得深入参考。2. 技术选型与架构设计思路为什么是RuoYi-Vue-Plus Flowable这个组合这不是拍脑袋决定的而是基于技术匹配度、社区生态和项目实际需求综合权衡的结果。2.1 基础框架RuoYi-Vue-Plus的基石作用RuoYi-Vue-Plus并非普通的RuoYi-Vue它是一个功能更强大的衍生版本提供了许多企业级开发所需的“轮子”。选择它作为基础主要看中以下几点清晰的分层与模块化其前后端分离架构Spring Boot Vue 3非常成熟代码结构清晰对于集成Flowable这类需要添加新表、新服务、新API的组件来说遵循现有规范进行扩展非常顺畅。强大的后台管理功能自带的用户、角色、部门、菜单、权限管理模块与工作流所需的“用户-组-权限”模型天然契合。我们可以直接复用或稍作扩展来作为Flowable的用户体系避免了重复造轮子。丰富的内置组件其前端基于Vue 3和Element Plus提供了大量现成的UI组件。这对于我们构建流程设计器、表单设计器、任务列表等界面时能极大提升开发效率保证UI风格统一。2.2 流程引擎为什么是Flowable在Activiti、Flowable、Camunda这几个同源分支中我们选择了Flowable主要基于以下考量活跃的社区与文档Flowable社区相对活跃官方文档包括中文文档比较全面遇到问题时更容易找到解决方案。这对于项目长期维护和团队学习至关重要。对Spring Boot的友好集成Flowable提供了flowable-spring-boot-starter可以非常方便地与Spring Boot集成自动化配置数据源、事务管理器等大大降低了初始配置的复杂度。功能丰富且轻量它包含了流程引擎BPMN、表单引擎DMN、内容引擎等功能齐全。同时它又保持了相对轻量可以根据需要引入特定模块不会给项目带来不必要的负担。与RuoYi-Vue-Plus的技术栈匹配两者都是Java技术栈且对Spring生态支持良好整合过程中的技术冲突较少。2.3 整体架构设计我们的扩展并非简单地把两个系统拼在一起而是进行了深度的融合设计。整体架构可以理解为三层展现层Vue 3 Element Plus在RuoYi-Vue-Plus原有后台界面的基础上新增了“流程设计”、“表单设计”、“我的待办”、“流程监控”等菜单模块。流程设计器我们选择了集成bpmn-js这是一个专业的BPMN 2.0流程图绘制库表单设计器则基于Vue的自定义组件开发实现拖拽生成表单。应用层Spring Boot Flowable REST API这是核心业务逻辑层。我们创建了独立的模块如ruoyi-module-workflow来存放所有工作流相关的代码。在这里我们不仅调用Flowable Engine的原生Java API来处理流程部署、启动、任务完成等核心操作还封装了一层更符合我们业务需求的Service。同时为了给前端提供更便捷的接口我们也部分启用了Flowable自带的REST API并对其进行了安全加固与RuoYi的权限系统对接。数据层MySQL Flowable EngineFlowable引擎启动时会自动创建数十张表这些表用于存储流程定义、运行时数据、历史数据等。我们需要规划好这些表与RuoYi现有业务表如sys_user,sys_dept的关联关系例如将Flowable的用户任务执行人ACT_RU_TASK表的ASSIGNEE_指向sys_user表的用户ID。注意在架构设计初期一个关键的决策点是用户体系的融合。强烈建议采用“接管”策略即禁用Flowable自带的IdentityService所有关于用户、组的查询和认证都通过扩展RuoYi的SysUserService来实现并通过实现Flowable的UserGroupManager接口来适配。这样可以保证整个系统只有一套用户数据源避免数据不一致。3. 核心功能模块实现详解这一部分我们将深入三个最核心的功能模块看看它们是如何从设计落到代码的。3.1 在线表单设计器的实现表单设计器是整个系统业务数据承载的关键。我们的目标是实现一个可通过拖拽左侧组件输入框、下拉框、日期选择器等到中间画布并在右侧动态配置组件属性的可视化设计器。前端实现Vue 3 JSON Schema组件库注册我们将每个表单字段如InputWidget、SelectWidget封装成一个独立的Vue组件。这些组件接收一个value属性和一个config属性包含字段标签、placeholder、校验规则等。画布与组件管理设计器主界面维护一个widgetList数组每个元素对应画布上的一个字段组件及其配置。拖拽操作实质上是向这个数组添加一个新的组件配置对象。属性配置面板当选中画布上的某个组件时右侧属性面板动态渲染该组件类型对应的所有可配置项如label、field、rules。这里使用v-model双向绑定修改属性即时更新画布组件。表单JSON Schema生成设计完成后widgetList数组可以被序列化成一个JSON对象。这个JSON对象就是表单的“蓝图”它描述了表单有哪些字段、每个字段的类型和规则。我们将这个JSON保存到后端数据库。// 示例一个简单表单的JSON Schema { “formName”: “请假申请单” “widgets”: [ { “type”: “date-picker” “icon”: “el-icon-date” “label”: “请假日期” “field”: “leaveDate” “rules”: [{ “required”: true, “message”: “请选择日期”, “trigger”: “change” }] }, { “type”: “input” “icon”: “el-icon-edit” “label”: “请假事由” “field”: “reason” “config”: { “type”: “textarea”, “rows”: 4 } } ] }后端实现动态表单渲染与数据存储Schema存储在数据库中创建wf_form_def表用于存储表单的JSON Schema、版本、关联的流程定义ID等信息。运行时渲染当用户需要填写一个任务表单时前端根据流程定义ID找到对应的表单Schema动态循环widgets数组根据type字段渲染出对应的Vue组件生成一个完整的表单页面。这个过程完全是动态的无需为每个表单编写前端代码。数据绑定与提交表单填写的数据会被收集成一个键值对对象如{“leaveDate”: “2023-10-27”, “reason”: “身体不适”}。在提交任务时这个数据对象会作为流程变量Process Variables提交到Flowable引擎中并可以同时保存一份到自定义的业务数据表实现流程与业务数据的关联。实操心得表单设计器的JSON Schema设计至关重要。初期我们只定义了基础属性后来发现需要支持“数据联动”、“显示隐藏逻辑”等复杂场景。建议在设计Schema时预留一个extendConfig字段用于存放未来可能扩展的复杂配置。另外表单校验规则最好也纳入Schema管理实现前后端校验规则统一。3.2 Flowable流程引擎的深度集成集成不仅仅是引入starter依赖更重要的是如何让Flowable引擎适应我们的业务架构。依赖引入与配置 在项目的pom.xml中引入关键依赖。dependency groupIdorg.flowable/groupId artifactIdflowable-spring-boot-starter/artifactId version6.8.0/version !-- 注意版本与Spring Boot的兼容性 -- /dependency dependency groupIdorg.flowable/groupId artifactIdflowable-spring-boot-starter-rest/artifactId version6.8.0/version /dependency在application.yml中进行最小化但关键的配置例如指定数据库类型、关闭一些不必要的自动部署。spring: datasource: url: jdbc:mysql://localhost:3306/ry_workflow?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneGMT%2B8 username: root password: yourpassword flowable: async-executor-activate: false # 根据需求开启异步执行器 database-schema-update: true # 首次启动可设为true自动建表生产环境建议用false通过Liquibase管理 history-level: audit # 历史数据级别audit是平衡性能与信息的常用级别核心服务封装 我们创建了WorkflowService封装了最常用的流程操作使其更符合业务语义。Service public class WorkflowService { Autowired private RepositoryService repositoryService; Autowired private RuntimeService runtimeService; Autowired private TaskService taskService; Autowired private HistoryService historyService; /** * 部署流程定义 (支持BPMN XML和ZIP包) */ public Deployment deployProcess(String processName, InputStream bpmnInputStream) { Deployment deployment repositoryService.createDeployment() .addInputStream(processName “.bpmn20.xml”, bpmnInputStream) .name(processName) .deploy(); return deployment; } /** * 启动流程实例并关联业务键和表单数据 */ public ProcessInstance startProcess(String processDefKey, String businessKey, MapString, Object variables) { variables.put(“applyUserId”, SecurityUtils.getUserId()); // 自动注入当前申请人 ProcessInstance instance runtimeService.startProcessInstanceByKey(processDefKey, businessKey, variables); // 可选将启动的流程实例ID与你的业务单据IDbusinessKey关联存储到自建表 return instance; } /** * 查询用户的待办任务 (与系统用户体系结合) */ public ListTask getTodoTasks(Long userId) { // 这里可以扩展不仅查询ASSIGNEE_也查询候选组、候选用户等 return taskService.createTaskQuery() .taskAssignee(userId.toString()) .orderByTaskCreateTime().desc() .list(); } }用户体系适配 这是集成中最关键的一环。我们需要告诉Flowable如何根据一个用户ID找到他的组部门/角色。实现UserGroupManager接口。Component public class CustomUserGroupManager implements UserGroupManager { Autowired private ISysUserService userService; Autowired private ISysRoleService roleService; Override public ListGroup getGroupsForUser(String userId) { ListGroup groups new ArrayList(); // 将系统角色转换为Flowable的Group对象 ListSysRole sysRoles roleService.selectRolesByUserId(Long.valueOf(userId)); for (SysRole role : sysRoles) { GroupImpl group new GroupImpl(); group.setId(role.getRoleId().toString()); group.setName(role.getRoleName()); group.setType(“assignment”); // 类型很重要用于任务分配 groups.add(group); } return groups; } // ... 实现其他方法如getUsersInGroup, isValidUser等 }在流程定义中任务分配人就可以使用${部门经理}或${role:admin}这样的表达式Flowable会通过我们实现的UserGroupManager来解析。3.3 可视化流程设计器BPMN.js的集成我们选择将bpmn-js集成到Vue项目中而不是使用Flowable官方自带的Modeler主要是为了获得更好的前端体验和定制能力。集成步骤安装依赖npm install bpmn-js bpmn-js-properties-panel camunda-bpmn-moddle --save组件封装创建一个Vue组件如BpmnModeler.vue在mounted生命周期中初始化BpmnModeler实例并将其挂载到一个div元素上。属性面板集成bpmn-js-properties-panel允许用户在右侧编辑选中元素的属性如任务名称、分配人表达式、表单关联等。自定义模块使用camunda-bpmn-moddle或自定义moddle来扩展BPMN XML的语义例如添加我们自定义的属性用于关联前面设计的表单ID。前后端交互加载流程打开设计器时调用后端API根据流程定义ID获取对应的BPMN 2.0 XML字符串然后通过modeler.importXML(xml)导入渲染。保存流程用户设计完成后通过modeler.saveXML({ format: true })导出为XML字符串然后调用后端API将其与流程名称、分类等信息一起保存。后端接收到XML后调用WorkflowService.deployProcess进行部署。注意事项bpmn-js的定制化有一定学习成本。初期建议先实现基础的查看和编辑功能。对于“关联表单”这类自定义需求可以通过在属性面板中增加一个自定义的select组件其选项从“表单设计器”已发布的表单列表中动态获取并将选中的表单ID写入BPMN元素的extensionElements中。4. 关键业务流程与接口设计有了基础模块接下来看几个贯穿始终的核心业务流程是如何串联起来的。4.1 流程发起与表单填充这是用户接触最多的场景。我们设计了一个统一的“流程发起”页面。选择流程用户首先从一个列表中选择想要发起的流程类型如“请假流程”、“报销流程”。这个列表来自已部署的流程定义。动态渲染表单前端根据选中的流程定义ID查询其关联的表单JSON Schema并动态渲染出对应的填写界面。数据提交与流程启动用户填写表单并提交。前端将表单数据组装成对象调用后端的/process/start接口。后端WorkflowService.startProcess方法会做三件事a) 启动流程实例b) 将表单数据作为流程变量存入c) 将流程实例ID与业务数据如果需要关联保存。这里流程的“业务键”businessKey通常可以用业务数据的ID如请假单ID来填充建立强关联。4.2 任务处理与审批流转任务处理的核心是“待办任务列表”和“任务办理页面”。待办列表用户登录后前端调用/task/todo接口。后端getTodoTasks方法会查询Flowable任务表并可能关联查询业务数据返回一个包含任务基本信息及相关业务摘要的列表给前端。任务办理用户点击一个任务进入办理页面。页面同样需要动态渲染表单表单Schema可能因任务节点不同而不同即“节点表单”。表单可能预填充了之前环节提交的数据从流程变量中读取。用户填写审批意见可能是一个简单的“同意/驳回”单选也可能是一段评语并选择下一步的流向如果是网关分支。提交时调用/task/complete接口后端通过TaskService.complete(taskId, variables)完成任务驱动流程流向下一节点。审批意见会被作为一个特殊的流程变量如comment存储同时也可以记录到自建的审批意见表中便于生成审批记录。4.3 流程监控与历史查询对于管理员或申请者需要查看流程的当前状态和历史轨迹。运行中流程通过RuntimeService查询ProcessInstance可以获取当前正在运行的流程实例列表及其当前活动节点。历史数据通过HistoryService可以查询已完成流程实例的历史信息、每个节点的任务执行历史、以及所有的流程变量变化记录。我们可以将这些数据与业务表关联在前端以时间轴或流程图高亮的形式直观展示“流程走到哪了”、“谁在什么时候做了什么操作”。高亮当前节点这是一个提升用户体验的功能。利用HistoryService获取已完成的节点利用RuntimeService获取当前活动节点然后将这些节点ID传递给前端。前端bpmn-js在查看模式下可以通过覆盖层的方式将已完成节点标记为绿色当前节点标记为红色。4.4 后端核心接口设计示例以下是一些关键的后端RESTful接口设计它们通常由RestController暴露供前端调用模块接口路径方法说明流程定义/workflow/deployPOST部署一个新的流程定义上传BPMN文件/workflow/definition/listGET获取已部署的流程定义列表流程实例/process/startPOST启动一个流程实例传入业务键和表单变量/process/instance/listGET查询流程实例列表可分页、过滤/process/instance/{instanceId}/diagramGET获取指定流程实例的当前状态图SVG格式任务管理/task/todoGET获取当前用户的待办任务列表/task/{taskId}/form-dataGET获取某个任务需要渲染的表单数据及Schema/task/completePOST完成一个任务提交表单数据和审批意见表单设计/form/design/savePOST保存或更新一个表单设计JSON Schema/form/design/{formKey}GET根据表单Key获取表单设计详情历史数据/history/instance/{instanceId}GET获取一个流程实例的详细历史轨迹5. 部署、调优与常见问题排查项目开发完成后如何部署到生产环境并确保其稳定高效运行是另一个重要课题。5.1 多环境部署策略数据库Flowable引擎表建议与业务表放在同一个数据库实例的不同Schema中或者使用表前缀如ACT_进行区分便于管理和备份。生产环境务必关闭database-schema-update: true改为使用Flyway或Liquibase进行数据库版本迁移。RuoYi-Vue-Plus本身已集成Liquibase我们可以将Flowable的建表语句也纳入其管理。配置文件使用Spring Boot的application-{profile}.yml多环境配置。在application-prod.yml中需要调整数据库连接池参数如HikariCP的maximumPoolSize、Flowable的历史数据级别可能调整为none或activity以提升性能、以及异步执行器配置。前端部署将Vue项目打包npm run build:prod生成的dist目录内容部署到Nginx或Apache等Web服务器上。后端Spring Boot应用打包成Jar通过java -jar命令或容器化Docker方式运行。5.2 性能调优要点工作流系统的性能瓶颈通常出现在历史数据、异步任务和流程变量上。历史数据管理Flowable的历史表会记录所有细节数据量增长极快。必须制定历史数据清理策略。可以使用Flowable提供的HistoryServiceAPI编写定时任务定期清理deleteHistoricProcessInstance已完成且超过一定时间的流程实例历史数据。也可以考虑调整history-level在不需要审计的场景下使用更低的级别。异步执行器对于邮件任务、调用外部HTTP服务等耗时操作务必将其设置为“异步”在BPMN中使用flowable:async”true”属性。并正确配置AsyncExecutor设置合适的核心线程数、队列大小避免任务堆积。流程变量避免在流程变量中存储过大的对象如整个文件内容。大文件应存储到对象存储或文件服务器在变量中只保存其路径或ID。查询历史变量时注意变量类型对于大文本或序列化对象查询可能会慢。5.3 常见问题与排查实录在实际开发和运维中我们踩过不少坑这里记录几个典型问题问题一任务查询不到或看不到待办。排查首先检查任务表的ASSIGNEE_或CANDIDATE_字段是否正确设置了用户ID。然后确认我们的CustomUserGroupManager是否正确实现当前登录用户的角色是否被正确转换为Flowable的Group。最后检查流程定义中用户任务的分配表达式如${applyUserId}是否正确以及在流程启动时这个变量是否被成功设置。技巧在开发环境可以开启Flowable的日志级别logging.level.org.flowableDEBUG查看任务创建和查询时的详细SQL这是最直接的调试手段。问题二流程变量在后续节点中取不到值。排查确保在完成任务taskService.complete时新的变量通过variables参数传递了进去。Flowable的变量作用域分为流程实例级别和任务本地级别。通常在完成任务时设置的变量默认会进入流程实例范围后续节点均可访问。如果是在“执行监听器”中设置的变量需要明确指定作用域。技巧使用RuntimeService.getVariable或HistoryService.getHistoricVariableInstance接口在后台直接查询某个流程实例的所有变量确认变量是否存在以及值是否正确。问题三集成后系统启动变慢或内存占用高。排查检查是否在应用启动时自动部署了大量不必要的BPMN文件flowable.check-process-definitions。生产环境应设置为false通过接口管理部署。检查是否有内存泄漏特别是与流程实例、历史实体相关的对象没有被及时释放注意在查询大量历史数据时分页。技巧使用JVM监控工具如VisualVM, JProfiler观察堆内存和GC情况。重点关注ProcessDefinitionEntity、ExecutionEntity等Flowable内部对象的数量。问题四表单设计器生成的JSON Schema在后端反序列化或渲染时出错。排查前后端对JSON Schema的版本或结构定义不一致。可能前端新增了一个自定义组件类型而后端没有对应的解析逻辑。或者JSON中包含了一些循环引用的复杂对象。技巧建立一套表单Schema的版本管理机制。在后端反序列化时使用更宽松的解析模式如Jackson的FAIL_ON_UNKNOWN_PROPERTIES false并记录详细的解析日志。对于复杂UI逻辑考虑将部分逻辑如联动规则以前端脚本的形式存储在Schema中后端只负责存储和传递不负责解析执行。这个项目从技术选型到深度集成再到细节打磨是一个典型的将强大但略显原始的中间件通过业务化的封装转化为易用、直观的产品功能的过程。其中最大的体会是“适配层”的设计至关重要。无论是用户体系的适配、表单模型的抽象还是API的封装目的都是让复杂的引擎能力以业务人员和技术人员都能理解的方式呈现出来。最后工作流项目的成功一半在技术另一半在对业务流程的深刻理解。在开发前多花时间与业务方沟通用流程图厘清每一个环节的异常处理和边界条件往往能避免后期大量的返工。本文还有配套的精品资源点击获取