Spring Boot项目集成Camunda工作流:从环境搭建到第一个审批流程的保姆级教程
Spring Boot项目集成Camunda工作流从环境搭建到第一个审批流程的保姆级教程想象一下这样的场景周一晨会上项目经理拍了拍你的肩膀说我们需要在下周迭代中为内部报销系统加入审批流程你来负责技术实现。作为刚接触工作流的开发者你可能会瞬间感到压力山大——该选哪个流程引擎如何快速搭建环境怎样避免那些教科书上没写的坑别担心这篇指南将手把手带你用Spring Boot和Camunda完成这个任务就像有个经验丰富的同事坐在你身边指导一样。Camunda作为当前最活跃的开源流程引擎之一其优势在于开箱即用的企业级功能和出色的性能表现。根据第三方压力测试在1000并发场景下Camunda比同类产品性能提升10-39%且零报错。更重要的是它与Spring Boot的整合异常简单甚至不需要你事先掌握BPMN规范细节。下面我们就从零开始用Docker快速搭建开发环境完成第一个报销审批流程。1. 开发环境准备1.1 Docker快速部署Camunda与MySQL现代开发讲究效率我们使用Docker Compose一键部署Camunda官方镜像和MySQL数据库。在你的项目根目录创建docker-compose.yml文件version: 3 services: camunda: image: camunda/camunda-bpm-platform:7.17.0 ports: - 8080:8080 environment: - DB_DRIVERcom.mysql.cj.jdbc.Driver - DB_URLjdbc:mysql://mysql:3306/camunda?characterEncodingUTF-8 - DB_USERNAMEcamunda - DB_PASSWORDcamunda depends_on: - mysql mysql: image: mysql:8.0 environment: - MYSQL_DATABASEcamunda - MYSQL_USERcamunda - MYSQL_PASSWORDcamunda - MYSQL_ROOT_PASSWORDroot volumes: - mysql_data:/var/lib/mysql volumes: mysql_data:启动服务只需执行docker-compose up -d注意首次启动可能需要2-3分钟初始化数据库访问http://localhost:8080/camunda-welcome/index.html 看到登录界面即表示成功。默认账号密码demo/demo1.2 Spring Boot项目基础配置使用Spring Initializr创建项目时除了基础的Web和JPA依赖需要特别添加!-- pom.xml -- dependency groupIdorg.camunda.bpm.springboot/groupId artifactIdcamunda-bpm-spring-boot-starter/artifactId version7.17.0/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency配置数据库连接和Camunda参数# application.properties spring.datasource.urljdbc:mysql://localhost:3306/camunda spring.datasource.usernamecamunda spring.datasource.passwordcamunda spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver camunda.bpm.admin-user.iddemo camunda.bpm.admin-user.passworddemo camunda.bpm.filter.createAll tasks2. 设计第一个BPMN审批流程2.1 安装Camunda Modeler可视化工具从Camunda官网下载对应系统的Modeler工具这是我们的流程设计利器。启动后新建BPMN文件我们将设计一个简易报销审批流程开始事件命名为报销申请提交用户任务添加部门经理审批节点排他网关设置金额5000的分支条件用户任务添加财务总监审批节点仅大额报销需要结束事件命名为报销流程完成关键配置点每个用户任务的Assignee字段设置为${approver}变量排他网关的条件表达式为${amount 5000}2.2 流程部署与验证将设计好的BPMN文件保存为reimbursement.bpmn复制到Spring Boot项目的src/main/resources/processes目录。启动应用时Camunda会自动部署该流程定义。验证部署是否成功SpringBootTest class ProcessDeploymentTest { Autowired private RepositoryService repositoryService; Test void shouldDeployProcessDefinition() { long count repositoryService.createProcessDefinitionQuery() .processDefinitionKey(reimbursement) .count(); assertTrue(count 0); } }3. 实现报销审批业务逻辑3.1 编写流程启动接口创建REST接口启动报销流程实例RestController RequestMapping(/api/reimbursement) public class ReimbursementController { Autowired private RuntimeService runtimeService; PostMapping(/start) public String startProcess(RequestBody ReimbursementRequest request) { MapString, Object variables new HashMap(); variables.put(employee, request.getEmployee()); variables.put(amount, request.getAmount()); variables.put(description, request.getDescription()); variables.put(approver, departmentManager); // 初始审批人 ProcessInstance instance runtimeService.startProcessInstanceByKey( reimbursement, variables ); return 流程已启动ID instance.getId(); } }3.2 处理用户审批任务实现任务查询和完成接口GetMapping(/tasks) public ListTaskDto getTasks(RequestParam String assignee) { return taskService.createTaskQuery() .taskAssignee(assignee) .list() .stream() .map(task - new TaskDto( task.getId(), task.getName(), (String) taskService.getVariable(task.getId(), employee), (Double) taskService.getVariable(task.getId(), amount) )) .collect(Collectors.toList()); } PostMapping(/complete/{taskId}) public String completeTask(PathVariable String taskId, RequestBody ApprovalDecision decision) { MapString, Object variables new HashMap(); variables.put(approved, decision.isApproved()); if(decision.isApproved() decision.getNextApprover() ! null) { variables.put(approver, decision.getNextApprover()); } taskService.complete(taskId, variables); return 审批操作已完成; }4. 生产环境优化与常见问题解决4.1 性能调优配置在高并发场景下建议调整以下参数# 异步执行器配置 camunda.bpm.job-execution.enabledtrue camunda.bpm.job-execution.wait-time-in-millis5000 camunda.bpm.job-execution.max-jobs-per-acquisition100 # 数据库连接池 spring.datasource.hikari.maximum-pool-size20 spring.datasource.hikari.minimum-idle54.2 中文乱码解决方案遇到流程图中文显示为方框时在application.properties中添加spring.http.encoding.forcetrue spring.http.encoding.charsetUTF-8 spring.http.encoding.enabledtrue server.tomcat.uri-encodingUTF-84.3 历史数据清理策略Camunda默认会保存所有历史数据生产环境需要配置自动清理Configuration public class CamundaConfig { Bean public ProcessEnginePlugin historyCleanupPlugin() { return new AbstractProcessEnginePlugin() { Override public void postInit(ProcessEngineConfigurationImpl config) { HistoryCleanupHandler handler config.getHistoryCleanupHandler(); handler.setBatchWindowStartTime(03:00); handler.setBatchSize(500); } }; } }5. 进阶动态审批人与业务规则集成5.1 使用DelegateTaskListener动态分配审批人实现更灵活的审批人分配逻辑Component public class ApproverAssignmentListener implements TaskListener { Override public void notify(DelegateTask task) { String department (String) task.getVariable(department); double amount (double) task.getVariable(amount); if(finance.equals(task.getTaskDefinitionKey())) { task.setAssignee(financeDirector); } else { String approver department Manager; task.setAssignee(approver); } if(amount 10000) { task.setVariable(requiresCEOApproval, true); } } }在BPMN中引用该监听器userTask iddepartmentApproval name部门审批 extensionElements camunda:taskListener eventcreate classcom.example.listener.ApproverAssignmentListener / /extensionElements /userTask5.2 集成DMN决策表实现智能路由对于复杂的审批规则可以使用Camunda的DMN引擎在Modeler中创建.dmn文件定义决策表部署到resources/decisions目录在流程中使用业务规则任务调用businessRuleTask idapprovalRouting camunda:decisionRefapprovalRoutingDecision extensionElements camunda:inputOutput camunda:inputParameter nameamount ${amount} /camunda:inputParameter /camunda:inputOutput /extensionElements /businessRuleTask实际项目中我们团队发现将审批规则外置到DMN后业务人员可以直接修改决策表而无需重新部署流程大大提高了系统的灵活性。特别是在金融行业合规要求频繁变更的场景下这种设计减少了约40%的发布次数。