工作流编辑与执行实战:基于Flowable与Spring Boot的流程自动化指南

发布时间:2026/8/9 9:47:51
工作流编辑与执行实战:基于Flowable与Spring Boot的流程自动化指南 在业务系统开发中你是否遇到过这样的场景一个审批流程需要经过多个部门一个数据处理任务需要按顺序执行多个步骤或者一个复杂的业务逻辑需要协调多个服务手动串联这些步骤不仅效率低下而且容易出错难以维护。这时工作流技术就成为了解决问题的利器。本文将围绕工作流的编辑与执行为你提供一套从概念理解到实战落地的完整指南。无论你是刚接触工作流的新手还是希望优化现有流程的开发者都能从中找到清晰的路径和可复用的代码。1. 工作流核心概念与价值在深入编辑与执行之前我们首先要理解工作流是什么以及它能为我们带来什么。1.1 什么是工作流工作流Workflow是对业务流程的一种形式化、自动化描述。它将一个复杂的业务过程分解为一系列定义好的、可自动执行的步骤或称为任务、活动并规定了这些步骤之间的执行顺序、流转规则以及数据传递关系。简单来说工作流就是将“谁在什么时候做什么事”的规则用计算机能理解的方式描述出来并驱动其自动运行。例如一个请假审批流程可以描述为员工提交申请 → 直属经理审批 →若请假天数3天部门总监审批 → HR备案 → 流程结束。1.2 工作流的核心组件一个典型的工作流引擎通常包含以下几个核心组件流程定义Process Definition业务流程的“蓝图”或“模板”使用特定的建模语言如BPMN 2.0描述。它定义了流程的结构包括有哪些任务、网关决策点、事件等。流程实例Process Instance根据流程定义启动的一个具体运行实例。例如员工张三发起一次请假就创建了一个基于“请假流程”定义的流程实例。活动/任务Activity/Task流程中的每一个步骤单元如“填写表单”、“发送邮件”、“调用API”。网关Gateway控制流程分支与合并的节点如并行网关所有分支同时执行、排他网关仅执行条件为真的一个分支。流转线Sequence Flow连接各个元素指明执行顺序的箭头。工作流引擎Workflow Engine负责解释流程定义、创建和管理流程实例、推动流程按规则流转的核心执行器。1.3 为什么需要工作流引入工作流主要带来以下价值提升效率与自动化将重复、规则明确的业务流程自动化减少人工干预和等待时间。提高过程可控性与透明度每个流程实例的状态、当前任务、处理人、处理历史都清晰可查便于管理和审计。增强灵活性与可维护性当业务流程需要变更时通常只需修改流程定义蓝图而无需大规模改动底层业务代码。促进业务与IT的协作使用BPMN等标准图形化建模语言业务人员也能参与流程设计降低沟通成本。理解了这些基础我们就可以开始动手学习如何“编辑”设计和“执行”运行一个工作流了。2. 环境准备与工具选型在开始实战前我们需要搭建开发环境并选择一个合适的工作流引擎。市面上有很多优秀的开源工作流引擎如Flowable,Activiti,Camunda等它们都基于BPMN 2.0标准功能强大。本文将以Flowable为例进行演示因为它社区活跃与Spring Boot集成友好且同时支持BPMN业务流程和CMMN案例管理标准。2.1 基础环境要求操作系统Windows 10/11, macOS, 或 Linux (如 Ubuntu 20.04)Java开发环境JDK 8 或 11 (推荐11 LTS版本)构建工具Maven 3.6 或 Gradle 6.xIDEIntelliJ IDEA, Eclipse 或 VS Code (需安装Java插件)数据库Flowable支持多种数据库如 H2 (内存数据库适合演示), MySQL 5.7, PostgreSQL 10。本文演示使用内嵌的H2数据库。2.2 创建Spring Boot项目我们使用 Spring Initializr 快速生成项目骨架。访问 Spring Initializr。选择项目信息Project: Maven ProjectLanguage: JavaSpring Boot: 选择最新的稳定版 (如 2.7.x 或 3.x 注意JDK版本对应关系)添加依赖搜索并添加Spring Web,Flowable,H2 Database,Lombok(可选简化代码)。点击“Generate”下载项目压缩包解压后用IDE打开。生成的pom.xml中应包含类似以下依赖版本号可能不同!-- Spring Boot Starter -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Flowable Spring Boot Starter -- dependency groupIdorg.flowable/groupId artifactIdflowable-spring-boot-starter/artifactId version6.7.2/version !-- 请使用最新稳定版 -- /dependency !-- H2 数据库 -- dependency groupIdcom.h2database/groupId artifactIdh2/artifactId scoperuntime/scope /dependency !-- Lombok -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency2.3 基础配置在src/main/resources/application.properties文件中进行简单配置# 应用端口 server.port8080 # H2 数据库配置 (控制台可用于查看流程数据) spring.datasource.urljdbc:h2:mem:flowable-db;DB_CLOSE_DELAY-1 spring.datasource.driverClassNameorg.h2.Driver spring.datasource.usernamesa spring.datasource.password # 启用H2控制台方便调试 spring.h2.console.enabledtrue spring.h2.console.path/h2-console # Flowable 配置 flowable.async-executor-activatefalse # 演示关闭异步执行器 flowable.database-schema-updatetrue # 自动创建/更新表结构启动应用后可以访问http://localhost:8080/h2-console查看数据库JDBC URL填写jdbc:h2:mem:flowable-db。3. 工作流编辑使用BPMN 2.0设计流程“编辑”工作流即使用建模工具设计流程定义。我们可以使用Flowable提供的在线设计器、Eclipse插件或者直接编写BPMN 2.0 XML文件。对于开发者理解BPMN XML结构至关重要。3.1 BPMN 2.0 基础元素BPMN 2.0是一种XML标准但我们可以通过图形化来理解它。一个最简单的顺序流程包含开始事件Start Event圆形绿色表示流程开始。用户任务User Task圆角矩形表示需要人工参与的任务。服务任务Service Task圆角矩形带齿轮图标表示自动执行的服务或逻辑。结束事件End Event圆形红色表示流程结束。顺序流Sequence Flow带箭头的实线连接各个元素。3.2 创建第一个流程定义文件在src/main/resources/processes/目录下如果没有则创建新建一个XML文件simple-approval.bpmn20.xml。?xml version1.0 encodingUTF-8? definitions xmlnshttp://www.omg.org/spec/BPMN/20100524/MODEL xmlns:flowablehttp://flowable.org/bpmn targetNamespacehttp://flowable.org/bpmn !-- 定义一个流程id是代码中引用的标识name是显示名称 -- process idsimpleApproval name简单审批流程 isExecutabletrue !-- 1. 开始事件 -- startEvent idstartEvent name开始/ !-- 2. 第一个用户任务提交申请 -- userTask idsubmitTask name提交请假申请 flowable:assignee${applicant} documentation员工填写请假信息/documentation /userTask !-- 3. 排他网关根据条件决定流向 -- exclusiveGateway iddecisionGateway name审批决策/ !-- 4. 经理审批任务 -- userTask idmanagerApproveTask name经理审批 flowable:candidateGroupsmanagers documentation直属经理审批申请/documentation /userTask !-- 5. 服务任务自动发送通知 -- serviceTask idsendNotificationTask name发送通知 flowable:classorg.example.flowable.service.SendNotificationService /serviceTask !-- 6. 结束事件 -- endEvent idendEvent name结束/ !-- 定义顺序流 -- !-- 从开始到提交 -- sequenceFlow idflow1 sourceRefstartEvent targetRefsubmitTask/ !-- 从提交到决策网关 -- sequenceFlow idflow2 sourceRefsubmitTask targetRefdecisionGateway/ !-- 决策网关到经理审批默认流无条件 -- sequenceFlow idflow3 sourceRefdecisionGateway targetRefmanagerApproveTask !-- 可以在这里添加条件例如 conditionExpression xsi:typetFormalExpression${days 3}/conditionExpression -- /sequenceFlow !-- 从经理审批到发送通知 -- sequenceFlow idflow4 sourceRefmanagerApproveTask targetRefsendNotificationTask/ !-- 从发送通知到结束 -- sequenceFlow idflow5 sourceRefsendNotificationTask targetRefendEvent/ /process /definitions关键点解释isExecutabletrue必须设置为true否则引擎不会部署。flowable:assignee${applicant}任务处理人使用表达式动态指定。${applicant}是一个流程变量。flowable:candidateGroupsmanagers任务候选组组名为“managers”的用户都可以认领此任务。flowable:class指定服务任务执行时调用的Java类全限定名。3.3 使用Flowable Modeler进行可视化编辑可选对于复杂流程可视化编辑更高效。你可以将Flowable Modeler一个Web应用集成到你的Spring Boot应用中或者使用独立的桌面建模工具。在pom.xml中添加设计器依赖dependency groupIdorg.flowable/groupId artifactIdflowable-ui-modeler/artifactId version6.7.2/version /dependency启动应用后访问http://localhost:8080/flowable-modeler即可进行拖拽式设计。设计完成后可以导出BPMN XML文件放入项目的resources/processes/目录。4. 工作流执行部署、启动与任务处理流程设计好之后下一步就是通过代码来“执行”它。这包括部署流程定义、启动流程实例、查询和处理任务等。4.1 核心服务注入Flowable Spring Boot Starter会自动配置一系列核心服务Bean我们直接注入使用即可。// 文件路径src/main/java/org/example/flowable/service/ProcessService.java package org.example.flowable.service; import lombok.RequiredArgsConstructor; 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.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.HashMap; import java.util.List; import java.util.Map; Service Slf4j RequiredArgsConstructor public class ProcessService { // 仓库服务管理流程定义BPMN文件的部署、查询等。 private final RepositoryService repositoryService; // 运行时服务管理正在运行的流程实例负责启动、触发信号等。 private final RuntimeService runtimeService; // 任务服务管理流程中的人工任务如查询、完成、指派等。 private final TaskService taskService; // 其他服务HistoryService(历史), ManagementService(管理)等按需注入 }4.2 部署流程定义部署是将BPMN文件解析并持久化到数据库的过程一个流程定义可以部署多次产生多个部署版本。// 在 ProcessService 中添加方法 public String deployProcess(String bpmnFileName) { // 从 classpath 的 processes/ 目录下加载文件 Deployment deployment repositoryService.createDeployment() .addClasspathResource(processes/ bpmnFileName) .name(简单审批流程部署) .deploy(); // 执行部署 log.info(流程部署成功部署ID: {}, 部署名称: {}, 部署时间: {}, deployment.getId(), deployment.getName(), deployment.getDeploymentTime()); return deployment.getId(); }4.3 启动流程实例部署成功后就可以根据流程定义的ID来启动一个具体的流程实例了。启动时可以传入业务数据作为流程变量。// 在 ProcessService 中添加方法 Transactional public ProcessInstance startProcessInstance(String processDefinitionKey, String businessKey, MapString, Object variables) { // processDefinitionKey 是BPMN文件中 process idsimpleApproval 的id // businessKey 通常关联业务主键如请假单ID ProcessInstance processInstance runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables); log.info(流程实例启动成功实例ID: {}, 业务Key: {}, 定义ID: {}, processInstance.getId(), processInstance.getBusinessKey(), processInstance.getProcessDefinitionId()); return processInstance; }4.4 查询与处理用户任务流程运行后会在人工任务节点暂停等待用户处理。// 在 ProcessService 中添加方法 // 1. 查询某个用户或候选组的待办任务 public ListTask getTasksByCandidateUser(String candidateUser) { return taskService.createTaskQuery() .taskCandidateUser(candidateUser) // 候选用户 .orderByTaskCreateTime().desc() // 按创建时间倒序 .list(); } public ListTask getTasksByCandidateGroup(String candidateGroup) { return taskService.createTaskQuery() .taskCandidateGroup(candidateGroup) // 候选组 .orderByTaskCreateTime().desc() .list(); } // 2. 认领任务将候选任务分配给具体用户 public void claimTask(String taskId, String userId) { taskService.claim(taskId, userId); log.info(任务 {} 已被用户 {} 认领, taskId, userId); } // 3. 完成任务并传递任务变量如表单数据、审批意见 Transactional public void completeTask(String taskId, MapString, Object taskVariables) { if (taskVariables ! null !taskVariables.isEmpty()) { taskService.complete(taskId, taskVariables); } else { taskService.complete(taskId); } log.info(任务 {} 已完成, taskId); }4.5 实现服务任务逻辑服务任务是自动执行的需要实现一个Java类。该类必须实现org.flowable.engine.delegate.JavaDelegate接口。// 文件路径src/main/java/org/example/flowable/service/SendNotificationService.java package org.example.flowable.service; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.delegate.JavaDelegate; import org.springframework.stereotype.Component; Component(sendNotificationService) // Bean名称与BPMN中 flowable:delegateExpression${sendNotificationService} 对应 Slf4j public class SendNotificationService implements JavaDelegate { Override public void execute(DelegateExecution execution) { // 可以从 execution 中获取流程变量 String processInstanceId execution.getProcessInstanceId(); String businessKey (String) execution.getVariable(businessKey); String applicant (String) execution.getVariable(applicant); // 模拟发送通知的逻辑 String message String.format(【流程通知】流程实例[%s], 业务单[%s], 申请人[%s]的审批流程已结束。, processInstanceId, businessKey, applicant); log.info(message); // 实际项目中这里可以调用邮件、短信、消息队列等服务 // emailService.send(...); } }注意在BPMN XML中我们之前用的是flowable:class属性直接指定类名。更灵活的方式是使用flowable:delegateExpression${sendNotificationService}这样可以直接引用Spring容器中的Bean。5. 完整实战构建一个请假审批REST API现在我们将上述所有步骤整合通过几个简单的REST API来体验工作流的完整生命周期。5.1 创建控制器// 文件路径src/main/java/org/example/flowable/controller/WorkflowController.java package org.example.flowable.controller; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.example.flowable.service.ProcessService; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.List; import java.util.Map; RestController RequestMapping(/api/workflow) Slf4j RequiredArgsConstructor public class WorkflowController { private final ProcessService processService; // 1. 部署流程 PostMapping(/deploy) public String deploy(RequestParam String bpmnFileName) { return processService.deployProcess(bpmnFileName); } // 2. 启动一个请假流程实例 PostMapping(/start-leave) public MapString, Object startLeaveProcess(RequestBody StartProcessRequest request) { MapString, Object variables new HashMap(); variables.put(applicant, request.getApplicant()); variables.put(days, request.getDays()); variables.put(reason, request.getReason()); // businessKey 可以关联你的业务表ID这里简单处理 String businessKey LEAVE_ System.currentTimeMillis(); ProcessInstance instance processService.startProcessInstance(simpleApproval, businessKey, variables); MapString, Object result new HashMap(); result.put(processInstanceId, instance.getId()); result.put(businessKey, businessKey); return result; } // 3. 查询我的待办任务 (根据候选人用户) GetMapping(/my-tasks) public ListTask getMyTasks(RequestParam String userId) { return processService.getTasksByCandidateUser(userId); } // 4. 查询组待办任务 (例如所有经理的审批任务) GetMapping(/group-tasks) public ListTask getGroupTasks(RequestParam String group) { return processService.getTasksByCandidateGroup(group); } // 5. 完成任务 (例如经理审批) PostMapping(/complete-task) public String completeTask(RequestBody CompleteTaskRequest request) { MapString, Object taskVars new HashMap(); taskVars.put(approvalResult, request.getApprovalResult()); // approved or rejected taskVars.put(comment, request.getComment()); processService.completeTask(request.getTaskId(), taskVars); return 任务处理完成; } // 内部请求对象 Data // 使用Lombok注解需在pom中引入 static class StartProcessRequest { private String applicant; private Integer days; private String reason; } Data static class CompleteTaskRequest { private String taskId; private String approvalResult; private String comment; } }5.2 运行与测试启动Spring Boot应用。部署流程使用Postman或curl调用POST http://localhost:8080/api/workflow/deploy?bpmnFileNamesimple-approval.bpmn20.xml。启动流程实例调用POST http://localhost:8080/api/workflow/start-leaveBody为JSON{ applicant: zhangsan, days: 5, reason: 年假 }返回的processInstanceId需要记下。查询经理待办调用GET http://localhost:8080/api/workflow/group-tasks?groupmanagers。此时应该能看到一个“经理审批”任务。处理任务从上一步获取taskId调用POST http://localhost:8080/api/workflow/complete-taskBody为{ taskId: 获取到的taskId, approvalResult: approved, comment: 同意 }观察日志在应用控制台你应该能看到SendNotificationService打印的通知日志表示流程已执行到服务任务并结束。通过H2控制台 (http://localhost:8080/h2-console)你可以查询ACT_RU_TASK运行中任务、ACT_HI_PROCINST历史流程实例等表直观看到流程数据的变化。6. 常见问题与排查思路在实际开发和集成工作流时你可能会遇到以下典型问题。问题现象可能原因排查思路与解决方案流程部署失败报XML parsing error1. BPMN XML文件语法错误。2. 使用了引擎不支持的BPMN元素或属性。1. 使用在线BPMN验证器或Flowable Modeler检查XML。2. 检查Flowable官方文档确认所用元素和属性是否被支持。启动流程实例失败报no processes deployed with key xxx1. 流程定义KeyprocessDefinitionKey拼写错误。2. 流程定义未部署成功或已被挂起。1. 检查BPMN文件中process id...的值。2. 通过repositoryService.createProcessDefinitionQuery().list()查询已部署的流程定义列表。用户任务查询不到1. 任务候选人/组设置错误。2. 任务已被他人认领。3. 流程未运行到该任务节点。1. 检查BPMN中flowable:assignee或flowable:candidateGroups的值和传入的查询参数。2. 查询ACT_RU_TASK表确认任务状态和负责人。3. 使用runtimeService.createActivityInstanceQuery()查看流程当前活动节点。服务任务/JavaDelegate未执行1. 实现类未正确实现JavaDelegate接口或未被Spring管理。2. BPMN中flowable:class类名错误或flowable:delegateExpression表达式错误。3. 方法内抛出未捕获的异常。1. 确保类上有Component注解并实现了execute方法。2. 检查类路径和Bean名称。使用delegateExpression时表达式应为${beanName}。3. 在execute方法内添加 try-catch 并打印详细日志。流程变量获取为null1. 变量未在启动流程或完成任务时正确设置。2. 变量作用域问题流程实例变量 vs 任务局部变量。1. 检查设置变量的代码确保Map被正确传递。2. 使用execution.getVariable()获取的是流程实例变量。任务变量需用taskService.getVariable()。理解变量作用域。事务回滚导致流程状态不一致在服务任务Delegate中操作数据库失败导致整体事务回滚但流程引擎可能已推进。考虑将业务操作和流程引擎操作放在不同的事务中或使用流程引擎的异步执行器。仔细设计异常处理逻辑。7. 最佳实践与工程建议将工作流集成到生产系统时遵循以下最佳实践可以避免很多坑。7.1 流程设计规范保持流程简洁一个流程应专注于一个核心业务目标。过于复杂的流程应拆分为子流程。使用有意义的ID和NameBPMN元素的ID在代码中引用应保持稳定且有意义如submitLeaveRequest。Name用于显示应清晰描述业务动作。合理使用网关明确并行网关(parallelGateway)和排他网关(exclusiveGateway)的使用场景。并行分支需同步排他分支则互斥。定义清晰的边界事件对于超时、错误等异常情况使用边界定时事件(boundaryTimerEvent)或边界错误事件(boundaryErrorEvent)进行处理使流程更健壮。7.2 代码集成与架构服务任务解耦服务任务Delegate中应只包含协调逻辑具体的业务操作如调用外部API、复杂计算应委托给独立的Spring Service Bean。这有利于测试和复用。使用Delegate Expression而非Class在BPMN中优先使用flowable:delegateExpression${myService}而不是flowable:class...。这样可以利用Spring的依赖注入和AOP等特性。流程变量管理明确哪些变量是流程实例全局的哪些是任务局部的。避免传递过大的对象作为变量可以考虑只传递业务主键在服务中根据主键查询完整数据。业务键(Business Key)必填启动流程实例时务必传入有意义的businessKey它通常是关联业务实体如订单号、请假单ID的唯一标识便于后续通过runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(key)快速查询。7.3 性能与运维数据库选择与优化生产环境务必使用MySQL、PostgreSQL等外部数据库。定期清理历史数据(ACT_HI_*表)Flowable提供了历史数据清理的配置和API。异步执行器对于非关键路径或耗时长的自动任务如服务任务启用异步执行器(asyncExecutor)避免阻塞流程引擎线程。监控与日志集成Spring Boot Actuator暴露Flowable的Health指标和Metrics。在关键节点流程启动、任务创建完成、节点流转记录结构化日志便于问题追踪和业务分析。版本控制与迁移流程定义变更后新部署会产生新版本。默认情况下新发起的流程实例会使用最新版本。对于已运行的旧版本实例需要有明确的迁移或完结策略。7.4 安全与权限任务权限控制结合Spring Security实现基于用户、角色、部门的任务查询和操作权限控制。Flowable的TaskService查询API支持丰富的权限过滤条件。流程启动权限在Controller层或使用Flowable的RuntimeService前校验当前用户是否有权限启动特定类型的流程。变量安全性不要通过流程变量传递敏感信息如密码、密钥。对于需要审计的审批意见等应妥善存储。工作流的编辑与执行是现代企业级应用开发的核心技能之一。通过本文你掌握了从零开始使用Flowable和Spring Boot设计、部署、运行一个完整工作流的方法。从理解BPMN图元到编写XML定义再到通过核心服务API驱动流程运转最后构建出可对外提供服务的RESTful接口这条路径覆盖了大部分基础开发场景。记住工作流引擎是工具核心在于你对业务流程的抽象和建模能力。在真实项目中先从简单的、核心的流程开始实践逐步迭代并始终关注流程的可维护性、性能和数据一致性。

相关新闻