SpringBoot集成Flowable工作流引擎与bpmn-js设计器实战

📅 2026/7/21 6:01:06
SpringBoot集成Flowable工作流引擎与bpmn-js设计器实战
在业务系统开发中流程审批、工单流转等场景无处不在。手动编码处理状态流转不仅繁琐而且流程变更时牵一发而动全身。此时引入一个成熟的工作流引擎就显得尤为必要。本文将手把手带你完成 SpringBoot 与主流工作流引擎的集成并整合强大的 bpmn-js 流程设计器实现从流程定义、部署到可视化设计的完整闭环。无论你是需要为现有系统添加审批流还是从零构建一个流程驱动的应用这套方案都能让你快速上手。1. 工作流引擎与 BPMN 2.0 核心概念在开始动手之前我们需要先理解几个核心概念这有助于我们后续的配置和开发。1.1 什么是工作流引擎工作流引擎Workflow Engine是一个软件组件它负责执行业务流程的自动化。你可以将它理解为一个“流程执行机器人”。开发者只需用标准化的语言如 BPMN 2.0定义好流程的步骤、规则和参与者引擎就会按照定义自动驱动流程的流转处理任务分配、条件判断、并行网关等复杂逻辑。它解决了什么问题业务与代码解耦流程逻辑不再硬编码在业务代码中。当业务流程需要调整时例如增加一个审批环节通常只需修改流程定义文件无需改动或重新部署Java代码。状态管理自动化引擎自动管理流程实例Process Instance和任务Task的状态如创建、进行中、完成开发者无需自己设计复杂的状态机。历史数据追溯引擎会完整记录流程实例的每一步操作便于审计和复盘。提高开发效率将通用的流程驱动逻辑抽象出来开发者可以更专注于具体业务任务的实现。1.2 BPMN 2.0 与流程设计器BPMN 2.0Business Process Model and Notation是一套由 OMG 组织维护的、用于描述业务流程的图形化标准。它定义了一套丰富的符号如事件、活动、网关、顺序流使得业务人员和技术人员可以用同一种“语言”来理解和设计流程。一个 BPMN 2.0 流程定义最终会保存为一个 XML 文件通常以.bpmn或.bpmn20.xml为后缀。这个 XML 文件描述了流程的全部逻辑。流程设计器如 bpmn-js则是一个前端可视化工具它允许用户通过拖拽图形元素的方式来绘制流程图并最终生成或编辑符合 BPMN 2.0 标准的 XML 文件。这极大地降低了流程定义的门槛让非技术人员也能参与流程设计。1.3 主流工作流引擎选型Activiti vs Flowable在 Java 领域有两个非常流行且同宗同源的工作流引擎Activiti和Flowable。Activiti由 Alfresco 公司开发是较早被广泛采用的引擎。目前主要维护的版本是 Activiti 7它基于 Spring Boot 进行了深度重构架构更现代但某些高级特性在社区版中可能受限。Flowable由原 Activiti 的核心开发团队创建的分支。它被认为更开源、更活跃社区版功能也非常丰富对 BPMN、CMMN、DMN 标准支持全面性能优化较好。如何选择对于大多数中小型项目和入门学习两者都能很好地满足需求。Flowable 的社区活跃度和文档友好度略胜一筹。本文的示例将基于Flowable进行因其集成相对简单且功能强大。其核心思想与 Activiti 7 高度相似学会一个另一个也能快速上手。2. 环境准备与项目初始化我们使用最通用的技术栈来构建示例项目。2.1 基础环境要求JDK: 1.8 或更高版本推荐 JDK 11 或 17本文使用 JDK 17Maven: 3.6IDE: IntelliJ IDEA 或 Eclipse (本文使用 IDEA)数据库: MySQL 5.7 或 8.0 (Flowable/Activiti 支持多种数据库如 H2, MySQL, PostgreSQL, Oracle等)2.2 使用 Spring Initializr 创建项目访问 start.spring.io 。填写项目信息Project: MavenLanguage: JavaSpring Boot: 选择 2.7.x 或 3.x (本文使用 2.7.18与 Flowable 6.x 兼容性好)添加依赖Spring Web(用于提供 REST API)MyBatis Framework或Spring Data JPA(用于业务数据操作本文演示用 MyBatis)MySQL Driver(连接数据库)Lombok(简化代码可选但推荐)点击“Generate”下载项目压缩包并导入到你的 IDE 中。生成的pom.xml基础部分如下?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version relativePath/ /parent groupIdcom.example/groupId artifactIdspringboot-flowable-demo/artifactId version0.0.1-SNAPSHOT/version namespringboot-flowable-demo/name descriptionDemo project for Spring Boot with Flowable/description properties java.version17/java.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.0/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration excludes exclude groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /exclude /excludes /configuration /plugin /plugins /build /project3. 集成 Flowable 工作流引擎接下来我们将 Flowable 引入项目。3.1 添加 Flowable 依赖在pom.xml的dependencies部分添加 Flowable 的 Spring Boot Starter 依赖。这个 starter 会自动配置引擎、Rest API、以及 Spring 集成所需的大部分 Bean。!-- Flowable 工作流引擎 Starter -- dependency groupIdorg.flowable/groupId artifactIdflowable-spring-boot-starter/artifactId version6.8.0/version !-- 请检查官网使用最新稳定版 -- /dependency注意版本号请根据实际情况调整可以访问 Maven Central 查询最新版本。添加后记得刷新 Maven 依赖。3.2 配置数据库连接Flowable 引擎运行需要数据库来存储流程定义、流程实例、任务、历史数据等。编辑src/main/resources/application.yml(或application.properties) 文件。server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/flowable_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver # Flowable 配置 flowable: # 是否在启动时自动创建/更新数据库表结构 (开发环境建议true生产环境建议false) database-schema-update: true # 是否检查流程定义文件BPMN XML的版本如果已存在相同key的流程是否作为新版本部署 check-process-definitions: true # 关闭异步执行器方便演示生产环境需要开启并配置线程池 async-executor-activate: false # 历史数据记录级别none, activity, audit, full (full最详细) history-level: audit关键配置解释database-schema-update: 设置为true时应用启动时 Flowable 会自动检查数据库如果表不存在则创建存在则对比模型进行更新。这在生产环境是危险的可能导致数据丢失生产环境应设置为false并通过专门的数据库迁移工具如 Flyway, Liquibase来管理表结构。async-executor-activate: 异步执行器用于处理定时任务、异步调用等。演示时关闭可以简化问题。history-level: 定义历史数据记录的详细程度。audit级别会记录流程实例、活动实例、任务、变量等适合大多数业务场景。重要操作在 MySQL 中创建名为flowable_db的数据库名称可自定义与配置对应即可。启动项目后Flowable 会自动在该库中创建约 60 张表表名通常以ACT_开头如ACT_RE_PROCDEF流程定义表ACT_RU_TASK运行时任务表ACT_HI_TASKINST历史任务表等。3.3 验证集成是否成功启动 Spring Boot 应用。观察控制台日志如果没有报错并且看到类似下面的日志说明集成成功... o.f.s.b.a.FlowableSecurityAutoConfiguration : Flowable security is disabled ... o.f.s.b.a.FlowableAutoConfiguration : Found Flowable Process engine ... o.f.s.b.a.FlowableAutoConfiguration : Found Flowable CMMN engine ... o.f.s.b.a.FlowableAutoConfiguration : Found Flowable DMN engine ... o.f.s.b.a.FlowableAutoConfiguration : Found Flowable Form engine ... o.f.s.b.a.FlowableAutoConfiguration : Found Flowable Content engine ... o.f.s.b.a.FlowableAutoConfiguration : Found Flowable Idm engine ... o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http)同时检查数据库应该已经生成了大量ACT_开头的表。4. 核心 API 与服务初探集成成功后我们就可以通过 Flowable 提供的 API 来操作流程了。核心服务是通过 Spring 容器自动注入的。4.1 核心服务简介Flowable 提供了多个服务门面每个负责不同的领域RepositoryService:流程仓库服务。负责管理部署、查询、删除流程定义BPMN XML。RuntimeService:运行时服务。负责启动流程实例、查询和操作运行中的流程实例、设置流程变量。TaskService:任务服务。负责管理用户任务Task如查询任务、完成任务、认领任务、设置任务变量等。这是与最终用户交互最频繁的服务。HistoryService:历史服务。查询所有已经结束的流程实例、任务、活动等历史数据。ManagementService:管理服务。提供引擎管理和维护操作如作业查询。4.2 编写第一个流程请假审批让我们创建一个最简单的请假审批流程并通过代码来部署和启动它。第一步创建 BPMN 2.0 XML 文件在src/main/resources目录下创建processes文件夹然后新建一个leave-request.bpmn20.xml文件。内容如下?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://www.flowable.org/processdef !-- 定义一个流程id是引擎识别的唯一标识name是显示名称 -- process idleaveRequest name请假申请流程 isExecutabletrue !-- 开始事件 -- startEvent idstartEvent name开始申请/ !-- 用户任务员工提交请假申请 -- userTask idsubmitLeaveRequest name提交请假申请 flowable:assignee${applicant} documentation员工填写请假单并提交/documentation /userTask !-- 排他网关根据请假天数决定审批路径 -- exclusiveGateway iddecisionGateway name审批路由/ !-- 用户任务经理审批短假 -- userTask idmanagerApprove name经理审批 flowable:assignee${manager} documentation经理审批请假申请/documentation /userTask !-- 用户任务HR备案长假 -- userTask idhrRecord nameHR备案 flowable:assignee${hr} documentationHR部门进行备案/documentation /userTask !-- 并行网关用于合并之前的审批路径 -- parallelGateway idjoinGateway name合并/ !-- 服务任务发送通知模拟业务逻辑 -- serviceTask idsendNotification name发送审批结果通知 flowable:classorg.flowable.engine.impl.bpmn.behavior.ShellActivityBehavior documentation调用系统服务发送通知/documentation /serviceTask !-- 结束事件 -- endEvent idendEvent name流程结束/ !-- 顺序流连接各个元素 -- sequenceFlow idflow1 sourceRefstartEvent targetRefsubmitLeaveRequest/ sequenceFlow idflow2 sourceRefsubmitLeaveRequest targetRefdecisionGateway/ !-- 条件顺序流天数小于等于3天走经理审批 -- sequenceFlow idflowToManager sourceRefdecisionGateway targetRefmanagerApprove conditionExpression xsi:typetFormalExpression ![CDATA[${days 3}]] /conditionExpression /sequenceFlow !-- 默认顺序流天数大于3天走HR备案 -- sequenceFlow idflowToHR sourceRefdecisionGateway targetRefhrRecord conditionExpression xsi:typetFormalExpression ![CDATA[${days 3}]] /conditionExpression /sequenceFlow sequenceFlow idflow3 sourceRefmanagerApprove targetRefjoinGateway/ sequenceFlow idflow4 sourceRefhrRecord targetRefjoinGateway/ sequenceFlow idflow5 sourceRefjoinGateway targetRefsendNotification/ sequenceFlow idflow6 sourceRefsendNotification targetRefendEvent/ /process /definitions流程说明员工 (${applicant}) 提交请假申请。经过排他网关根据流程变量days请假天数判断days 3流转到经理 (${manager}) 审批。days 3流转到 HR (${hr}) 备案。审批/备案完成后流程合并发送通知最后结束。第二步编写 Java 代码部署并启动流程创建一个测试类FlowableQuickStartTest或直接在某个 Controller 中编写接口。package com.example.demo.controller; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.List; import java.util.Map; RestController RequestMapping(/api/flowable) Slf4j public class FlowableDemoController { Autowired private RepositoryService repositoryService; Autowired private RuntimeService runtimeService; Autowired private TaskService taskService; /** * 1. 部署流程定义 */ PostMapping(/deploy) public String deploy() { // 从 classpath 的 processes 目录下部署 leave-request.bpmn20.xml Deployment deployment repositoryService.createDeployment() .addClasspathResource(processes/leave-request.bpmn20.xml) .name(请假流程部署) .deploy(); log.info(流程部署成功部署ID: {}, deployment.getId()); // 查询流程定义 ProcessDefinition processDefinition repositoryService.createProcessDefinitionQuery() .deploymentId(deployment.getId()) .singleResult(); return String.format(流程部署成功流程定义ID: %s, 名称: %s, processDefinition.getId(), processDefinition.getName()); } /** * 2. 启动一个流程实例 * param applicant 申请人 * param manager 经理 * param hr HR * param days 请假天数 */ PostMapping(/start) public String startProcess(RequestParam String applicant, RequestParam String manager, RequestParam String hr, RequestParam Integer days) { // 设置流程变量 MapString, Object variables new HashMap(); variables.put(applicant, applicant); variables.put(manager, manager); variables.put(hr, hr); variables.put(days, days); // 使用流程定义的 KEY 来启动流程实例 ProcessInstance processInstance runtimeService.startProcessInstanceByKey(leaveRequest, variables); log.info(流程实例启动成功实例ID: {}, processInstance.getId()); return String.format(流程启动成功流程实例ID: %s, processInstance.getId()); } /** * 3. 查询某个用户的任务列表 * param assignee 任务负责人 */ GetMapping(/tasks) public ListTaskInfo getTasks(RequestParam String assignee) { ListTask tasks taskService.createTaskQuery() .taskAssignee(assignee) // 查询分配给指定用户的任务 .orderByTaskCreateTime().desc() .list(); // 转换为简单的DTO返回 return tasks.stream().map(task - new TaskInfo( task.getId(), task.getName(), task.getProcessInstanceId(), task.getCreateTime() )).toList(); } /** * 4. 完成任务 * param taskId 任务ID */ PostMapping(/complete/{taskId}) public String completeTask(PathVariable String taskId) { // 完成任务可以传入新的流程变量 taskService.complete(taskId); log.info(任务 {} 已完成, taskId); return 任务完成; } // 简单的任务信息DTO lombok.Data lombok.AllArgsConstructor public static class TaskInfo { private String taskId; private String taskName; private String processInstanceId; private java.util.Date createTime; } }4.3 测试第一个流程部署流程启动应用使用 Postman 或浏览器访问POST http://localhost:8080/api/flowable/deploy。返回成功信息。启动流程实例访问POST http://localhost:8080/api/flowable/start?applicantzhangsanmanagerlisihrwangwudays5。这将启动一个流程实例其中days5所以会流向hrRecord任务。查询任务访问GET http://localhost:8080/api/flowable/tasks?assigneewangwu。你应该能看到一个名为 “HR备案” 的任务分配给wangwu。完成任务拿到上一步返回的taskId访问POST http://localhost:8080/api/flowable/complete/{taskId}。任务完成流程继续向后执行直到结束。你可以通过GET http://localhost:8080/api/flowable/tasks?assigneelisi查询经理的任务或者修改days2重新启动一个实例观察任务如何分配给经理。5. 集成 bpmn-js 流程设计器前端部分后端引擎已经就绪现在我们需要一个前端页面来可视化设计流程。bpmn-js 是当前最流行的 BPMN 2.0 流程建模工具库。5.1 前端项目准备简化版为了快速演示我们直接在 Spring Boot 项目中提供静态页面。在实际项目中你可能会使用 Vue、React 等前端框架。在src/main/resources/static目录下创建modeler文件夹。下载 bpmn-js 库。你可以通过 npm 安装也可以直接使用 CDN。这里我们使用 CDN 方式简化。在static/modeler下创建index.html。5.2 创建基础的流程设计器页面以下是index.html的完整内容它创建了一个包含工具栏和画布的基础设计器。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleBPMN 2.0 流程设计器/title !-- 引入 bpmn-js 及其依赖的样式和脚本 (使用 CDN) -- link relstylesheet hrefhttps://unpkg.com/bpmn-js14.0.0/dist/assets/diagram-js.css link relstylesheet hrefhttps://unpkg.com/bpmn-js14.0.0/dist/assets/bpmn-font/css/bpmn.css link relstylesheet hrefhttps://unpkg.com/bpmn-js14.0.0/dist/assets/bpmn-js.css style * { margin: 0; padding: 0; box-sizing: border-box; font-family: Helvetica Neue, Arial, sans-serif; } body { height: 100vh; display: flex; flex-direction: column; background-color: #f5f5f5; } .header { padding: 15px 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; display: flex; justify-content: space-between; align-items: center; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .header h1 { font-size: 1.5rem; font-weight: 300; } .toolbar { display: flex; gap: 10px; background-color: #fff; padding: 10px 20px; border-bottom: 1px solid #ddd; flex-wrap: wrap; } .toolbar button { padding: 8px 16px; border: 1px solid #ccc; background-color: #f9f9f9; border-radius: 4px; cursor: pointer; font-size: 14px; transition: all 0.2s; } .toolbar button:hover { background-color: #e9e9e9; border-color: #999; } .toolbar button.primary { background-color: #4CAF50; color: white; border-color: #4CAF50; } .toolbar button.primary:hover { background-color: #45a049; } .toolbar button.danger { background-color: #f44336; color: white; border-color: #f44336; } .toolbar button.danger:hover { background-color: #d32f2f; } .content { display: flex; flex: 1; overflow: hidden; } #palette-container { width: 80px; background-color: #fff; border-right: 1px solid #ddd; overflow-y: auto; } #canvas-container { flex: 1; background-color: #fafafa; position: relative; } #canvas { width: 100%; height: 100%; } #properties-panel { width: 300px; background-color: #fff; border-left: 1px solid #ddd; overflow-y: auto; padding: 15px; display: none; /* 默认隐藏高级功能需要引入 properties-panel 模块 */ } .status-bar { padding: 8px 20px; background-color: #fff; border-top: 1px solid #ddd; font-size: 12px; color: #666; display: flex; justify-content: space-between; } .modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); justify-content: center; align-items: center; } .modal-content { background-color: white; padding: 30px; border-radius: 8px; min-width: 400px; box-shadow: 0 5px 15px rgba(0,0,0,0.3); } .modal-content h3 { margin-bottom: 20px; color: #333; } .modal-content textarea { width: 100%; height: 300px; padding: 10px; border: 1px solid #ccc; border-radius: 4px; font-family: monospace; font-size: 13px; resize: vertical; margin-bottom: 15px; } .modal-actions { display: flex; justify-content: flex-end; gap: 10px; } /style /head body div classheader h1 BPMN 2.0 流程设计器/h1 div基于 bpmn-js Spring Boot Flowable/div /div div classtoolbar button onclickcreateNewDiagram() title新建流程图新建/button button onclickopenFile() title打开本地BPMN文件打开.../button button onclicksaveXML() classprimary title下载BPMN XML保存XML/button button onclicksaveSVG() title下载为SVG图片保存SVG/button button onclickshowImportXMLModal() title导入XML字符串导入XML/button button onclickzoomIn() title放大/button button onclickzoomOut() title缩小-/button button onclickzoomFit() title适应画布适应/button button onclickundo() title撤销撤销/button button onclickredo() title重做重做/button div styleflex-grow: 1;/div button onclickdeployToServer() classprimary部署到服务器/button button onclickclearCanvas() classdanger清空/button /div div classcontent div idpalette-container/div div idcanvas-container div idcanvas/div /div div idproperties-panel h3属性面板/h3 p需要引入 codebpmn-js-properties-panel/code 模块以启用属性编辑功能。/p /div /div div classstatus-bar div idstatus就绪/div div提示使用鼠标拖拽左侧元素到画布连接线请从元素边缘拖出/div /div !-- 导入XML的模态框 -- div idimportModal classmodal div classmodal-content h3导入 BPMN 2.0 XML/h3 textarea idxmlInput placeholder请将 BPMN 2.0 XML 内容粘贴到这里.../textarea div classmodal-actions button onclickimportXML()导入/button button onclickcloseImportModal()取消/button /div /div /div !-- 引入 bpmn-js 及其依赖 -- script srchttps://unpkg.com/bpmn-js14.0.0/dist/bpmn-viewer.development.js/script script srchttps://unpkg.com/bpmn-js14.0.0/dist/bpmn-modeler.development.js/script !-- 注意properties-panel 需要额外引入此处省略以简化 -- script // 全局变量 let bpmnModeler null; let currentZoom 1.0; // 初始化 BPMN 设计器 window.onload function() { const container document.getElementById(canvas); bpmnModeler new BpmnJS({ container: container, // 可以在此配置更多选项例如 propertiesPanel // propertiesPanel: { // parent: #properties-panel // } }); // 创建默认的空流程图 createNewDiagram(); // 将设计器实例挂载到 window 方便调试 window.bpmnModeler bpmnModeler; }; // 创建新的空白流程图 function createNewDiagram() { const newDiagramXml ?xml version1.0 encodingUTF-8? definitions xmlnshttp://www.omg.org/spec/BPMN/20100524/MODEL xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance targetNamespacehttp://bpmn.io/schema/bpmn process idProcess_1 isExecutablefalse startEvent idStartEvent_1 / /process /definitions; openDiagram(newDiagramXml); updateStatus(已创建新流程图); } // 打开/导入流程图 XML function openDiagram(xml) { bpmnModeler.importXML(xml, function(err) { if (err) { console.error(导入XML失败:, err); updateStatus(导入失败: (err.message || 未知错误)); alert(导入失败请检查XML格式是否正确。\n错误信息 err.message); } else { console.log(流程图导入成功); updateStatus(流程图已加载); // 导入成功后将画布缩放至适应视图 zoomFit(); } }); } // 生成并下载 XML 文件 function saveXML() { bpmnModeler.saveXML({ format: true }, function(err, xml) { if (err) { console.error(保存XML失败:, err); updateStatus(保存XML失败); return; } const blob new Blob([xml], { type: application/xml }); const url URL.createObjectURL(blob); const a document.createElement(a); a.href url; a.download diagram.bpmn20.xml; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); updateStatus(XML文件已下载); }); } // 生成并下载 SVG 图片 function saveSVG() { bpmnModeler.saveSVG(function(err, svg) { if (err) { console.error(保存SVG失败:, err); updateStatus(保存SVG失败); return; } const blob new Blob([svg], { type: image/svgxml }); const url URL.createObjectURL(blob); const a document.createElement(a); a.href url; a.download diagram.svg; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); updateStatus(SVG图片已下载); }); } // 打开本地文件 function openFile() { const input document.createElement(input); input.type file; input.accept .bpmn,.bpmn20.xml,.xml; input.onchange function(event) { const file event.target.files[0]; if (!file) return; const reader new FileReader(); reader.onload function(e) { openDiagram(e.target.result); }; reader.readAsText(file); }; input.click(); } // 显示导入XML的模态框 function showImportXMLModal() { document.getElementById(importModal).style.display flex; document.getElementById(xmlInput).focus(); } function closeImportModal() { document.getElementById(importModal).style.display none; document.getElementById(xmlInput).value ; } function importXML() { const xml document.getElementById(xmlInput).value; if (!xml.trim()) { alert(请输入XML内容); return; } openDiagram(xml); closeImportModal(); } // 缩放控制 function zoomIn() { currentZoom 0.1; bpmnModeler.get(canvas).zoom(currentZoom); updateStatus(缩放: (currentZoom * 100).toFixed(0) %); } function zoomOut() { currentZoom Math.max(0.2, currentZoom - 0.1); bpmnModeler.get(canvas).zoom(currentZoom); updateStatus(缩放: (currentZoom * 100).toFixed(0) %); } function zoomFit() { bpmnModeler.get(canvas).zoom(fit-viewport); currentZoom bpmnModeler.get(canvas).zoom(); updateStatus(已适应画布); } // 撤销/重做 (需要启用历史模块) function undo() { const commandStack bpmnModeler.get(commandStack); if (commandStack commandStack.canUndo()) { commandStack.undo(); updateStatus(已撤销); } else { updateStatus(无法撤销); } } function redo() { const commandStack bpmnModeler.get(commandStack); if (commandStack commandStack.canRedo()) { commandStack.redo(); updateStatus(已重做); } else { updateStatus(无法重做); } } // 清空画布 function clearCanvas() { if (confirm(确定要清空画布吗所有未保存的更改将丢失。)) { createNewDiagram(); } } // 部署到后端服务器 (需要实现后端接口) function deployToServer() { bpmnModeler.saveXML({ format: true }, function(err, xml) { if (err) { alert(生成XML失败: err.message); return; } // 这里调用后端的部署接口 fetch(/api/flowable/deploy-from-xml, { method: POST, headers: { Content-Type: application/xml, }, body: xml }) .then(response { if (response.ok) { return response.text(); } else { throw new Error(部署失败状态码: response.status); } }) .then(data { alert(部署成功\n data); updateStatus(流程已部署到服务器); }) .catch(error { console.error(部署错误:, error); alert(部署失败: error.message); updateStatus(部署失败); }); }); } // 更新状态栏 function updateStatus(message) { document.getElementById(status).textContent message; console.log(状态:, message); } /script /body /html5.3 启动并访问设计器确保你的 Spring Boot 应用正在运行。打开浏览器访问http://localhost:8080/modeler/index.html。你应该能看到一个功能完整的 BPMN 流程设计器界面。你可以从左侧拖拽元素开始事件、用户任务、网关等到画布连接它们并下载生成的 XML。至此我们已经完成了 SpringBoot 与 Flowable 工作流引擎的集成并搭建了一个基础的 bpmn-js 流程设计器前端。在下一篇下中我们将深入探讨如何实现前后端联动将设计器绘制的流程部署到引擎、如何实现动态用户任务分配、流程变量管理、以及如何集成业务表单构建一个真正可用的工作流系统。