Flowable实战构建企业级请假审批系统的全流程指南在数字化转型浪潮中工作流引擎已成为企业应用的核心基础设施。作为Activiti的下一代产品Flowable凭借其轻量级架构和强大的BPMN 2.0支持正在成为Java开发者构建审批系统的首选方案。本文将带您从零开始通过一个完整的请假审批系统案例掌握Flowable与Spring Boot的深度整合技巧。1. 环境准备与BPMN设计1.1 开发环境配置开始前需确保具备以下环境JDK 11推荐Amazon CorrettoIntelliJ IDEA 2023社区版即可Maven 3.8MySQL 8.0或PostgreSQL 14创建Spring Boot项目时添加关键依赖dependency groupIdorg.flowable/groupId artifactIdflowable-spring-boot-starter/artifactId version6.7.2/version /dependency dependency groupIdcom.h2database/groupId artifactIdh2/artifactId scoperuntime/scope /dependency提示生产环境建议使用MySQL而非H2需额外配置数据源1.2 BPMN流程图设计安装Flowable BPMN插件后创建leave-approval.bpmn20.xml文件。典型请假审批流程应包含开始事件空启动事件用户任务提交申请、部门审批、HR备案排他网关处理审批结果分支结束事件审批通过/拒绝关键属性配置示例userTask iddeptApproval name部门审批 flowable:assignee${deptLeader} extensionElements flowable:formProperty idcomment name审批意见 typestring/ /extensionElements /userTask2. 流程部署策略对比Flowable提供多种部署方式各有适用场景部署方式适用场景优点缺点ClassPath固定流程简单可靠需重启更新文件流临时测试灵活快速无版本管理ZIP压缩包批量部署一次多流程需打包步骤文本格式动态生成内存操作无校验字节数组前端集成高性能内存占用推荐生产环境使用版本化部署GetMapping(/deployWithVersion) public String deployWithVersion() { Deployment deployment repositoryService.createDeployment() .addClasspathResource(processes/leave.bpmn20.xml) .name(请假流程V2.1) .key(leaveProcess) .category(HR) .deploy(); return 部署成功版本 repositoryService.createProcessDefinitionQuery() .deploymentId(deployment.getId()) .singleResult() .getVersion(); }3. 流程实例的智能启动3.1 参数化启动优化带参启动时可嵌入业务逻辑校验public ProcessInstance startProcessWithValidation(String processKey, MapString, Object variables) { // 验证请假天数 Integer days (Integer)variables.get(leaveDays); if(days 30) { throw new IllegalArgumentException(请假超过30天需特殊审批); } // 自动计算审批路径 if(days 5) { variables.put(needHrApproval, true); } return runtimeService.startProcessInstanceByKey( processKey, variables ); }3.2 动态任务分配通过监听器实现灵活的任务分配public class DynamicAssigneeListener implements TaskListener { Override public void notify(DelegateTask task) { String eventName task.getEventName(); if(EVENTNAME_CREATE.equals(eventName)) { String dept (String)task.getVariable(department); String leader orgService.queryLeaderByDept(dept); task.setAssignee(leader); } } }在BPMN中配置userTask iddeptApproval name部门审批 extensionElements flowable:taskListener eventcreate classcom.example.DynamicAssigneeListener/ /extensionElements /userTask4. 审批功能进阶实现4.1 多维度任务查询构建高效的任务查询接口public PageInfoTaskVO queryTasks(TaskQueryDTO query) { TaskQuery taskQuery taskService.createTaskQuery() .taskCandidateOrAssigned(query.getUserId()) .orderByTaskCreateTime().desc(); if(StringUtils.isNotBlank(query.getProcessKey())) { taskQuery.processDefinitionKey(query.getProcessKey()); } if(query.getDueDate() ! null) { taskQuery.taskDueBefore(query.getDueDate()); } ListTask tasks taskQuery.listPage( query.getPageNum() - 1, query.getPageSize() ); return new PageInfo(tasks.stream() .map(this::convertToVO) .collect(Collectors.toList())); }4.2 审批链设计模式实现多级审批的优雅方案public void completeWithChain(String taskId, MapString, Object variables) { Task currentTask taskService.createTaskQuery() .taskId(taskId).singleResult(); // 基础审批逻辑 taskService.complete(taskId, variables); // 判断是否需要下一级审批 Boolean needNextLevel (Boolean)variables.get(needNextLevel); if(needNextLevel ! null needNextLevel) { String nextAssignee calculateNextApprover( currentTask.getProcessInstanceId() ); Task nextTask taskService.createTaskQuery() .processInstanceId(currentTask.getProcessInstanceId()) .singleResult(); taskService.setAssignee(nextTask.getId(), nextAssignee); } }5. 流程可视化与监控5.1 动态流程图生成增强版的流程图生成方法GetMapping(/processDiagram) public void generateDiagram(HttpServletResponse response, RequestParam String processInstanceId) throws IOException { // 获取高亮节点 ListString activeActivities runtimeService.getActiveActivityIds(processInstanceId); // 获取历史路径 ListString highLightedFlows historyService.createHistoricActivityInstanceQuery() .processInstanceId(processInstanceId) .orderByHistoricActivityInstanceStartTime().asc() .list() .stream() .map(HistoricActivityInstance::getActivityId) .collect(Collectors.toList()); BpmnModel bpmnModel repositoryService.getBpmnModel( runtimeService.createProcessInstanceQuery() .processInstanceId(processInstanceId) .singleResult() .getProcessDefinitionId() ); try (InputStream is processDiagramGenerator.generateDiagram( bpmnModel, png, activeActivities, highLightedFlows, 宋体, 宋体, 宋体 )) { response.setContentType(image/png); IOUtils.copy(is, response.getOutputStream()); } }5.2 审批时间线分析通过历史数据生成审批时间线SELECT act.ACT_ID_ as nodeId, act.ACT_NAME_ as nodeName, MIN(act.START_TIME_) as startTime, MAX(act.END_TIME_) as endTime, TIMESTAMPDIFF(SECOND, MIN(act.START_TIME_), MAX(act.END_TIME_)) as duration FROM ACT_HI_ACTINST act WHERE act.PROC_INST_ID_ #{processInstanceId} GROUP BY act.ACT_ID_, act.ACT_NAME_ ORDER BY MIN(act.START_TIME_)6. 生产环境最佳实践6.1 性能优化配置在application.yml中添加关键配置flowable: async-executor: activate: true core-pool-size: 10 max-pool-size: 50 queue-size: 1000 database-schema-update: false history-level: audit6.2 异常处理策略实现全局流程异常处理器ControllerAdvice public class FlowableExceptionHandler { ExceptionHandler(FlowableException.class) public ResponseEntityErrorResponse handleFlowableException( FlowableException ex) { ErrorResponse error new ErrorResponse(); error.setTimestamp(LocalDateTime.now()); if(ex instanceof FlowableObjectNotFoundException) { error.setCode(PROCESS_NOT_FOUND); error.setMessage(流程资源不存在); return ResponseEntity.status(404).body(error); } // 其他异常处理... } }在项目实践中发现合理的流程版本管理策略能显著降低维护成本。建议采用语义化版本控制并在部署时自动归档旧版本流程图。对于复杂的审批场景可以考虑使用Flowable的DMN决策表来简化网关逻辑。
Flowable实战:从BPMN画图到Spring Boot集成,一个请假审批系统的保姆级搭建教程
Flowable实战构建企业级请假审批系统的全流程指南在数字化转型浪潮中工作流引擎已成为企业应用的核心基础设施。作为Activiti的下一代产品Flowable凭借其轻量级架构和强大的BPMN 2.0支持正在成为Java开发者构建审批系统的首选方案。本文将带您从零开始通过一个完整的请假审批系统案例掌握Flowable与Spring Boot的深度整合技巧。1. 环境准备与BPMN设计1.1 开发环境配置开始前需确保具备以下环境JDK 11推荐Amazon CorrettoIntelliJ IDEA 2023社区版即可Maven 3.8MySQL 8.0或PostgreSQL 14创建Spring Boot项目时添加关键依赖dependency groupIdorg.flowable/groupId artifactIdflowable-spring-boot-starter/artifactId version6.7.2/version /dependency dependency groupIdcom.h2database/groupId artifactIdh2/artifactId scoperuntime/scope /dependency提示生产环境建议使用MySQL而非H2需额外配置数据源1.2 BPMN流程图设计安装Flowable BPMN插件后创建leave-approval.bpmn20.xml文件。典型请假审批流程应包含开始事件空启动事件用户任务提交申请、部门审批、HR备案排他网关处理审批结果分支结束事件审批通过/拒绝关键属性配置示例userTask iddeptApproval name部门审批 flowable:assignee${deptLeader} extensionElements flowable:formProperty idcomment name审批意见 typestring/ /extensionElements /userTask2. 流程部署策略对比Flowable提供多种部署方式各有适用场景部署方式适用场景优点缺点ClassPath固定流程简单可靠需重启更新文件流临时测试灵活快速无版本管理ZIP压缩包批量部署一次多流程需打包步骤文本格式动态生成内存操作无校验字节数组前端集成高性能内存占用推荐生产环境使用版本化部署GetMapping(/deployWithVersion) public String deployWithVersion() { Deployment deployment repositoryService.createDeployment() .addClasspathResource(processes/leave.bpmn20.xml) .name(请假流程V2.1) .key(leaveProcess) .category(HR) .deploy(); return 部署成功版本 repositoryService.createProcessDefinitionQuery() .deploymentId(deployment.getId()) .singleResult() .getVersion(); }3. 流程实例的智能启动3.1 参数化启动优化带参启动时可嵌入业务逻辑校验public ProcessInstance startProcessWithValidation(String processKey, MapString, Object variables) { // 验证请假天数 Integer days (Integer)variables.get(leaveDays); if(days 30) { throw new IllegalArgumentException(请假超过30天需特殊审批); } // 自动计算审批路径 if(days 5) { variables.put(needHrApproval, true); } return runtimeService.startProcessInstanceByKey( processKey, variables ); }3.2 动态任务分配通过监听器实现灵活的任务分配public class DynamicAssigneeListener implements TaskListener { Override public void notify(DelegateTask task) { String eventName task.getEventName(); if(EVENTNAME_CREATE.equals(eventName)) { String dept (String)task.getVariable(department); String leader orgService.queryLeaderByDept(dept); task.setAssignee(leader); } } }在BPMN中配置userTask iddeptApproval name部门审批 extensionElements flowable:taskListener eventcreate classcom.example.DynamicAssigneeListener/ /extensionElements /userTask4. 审批功能进阶实现4.1 多维度任务查询构建高效的任务查询接口public PageInfoTaskVO queryTasks(TaskQueryDTO query) { TaskQuery taskQuery taskService.createTaskQuery() .taskCandidateOrAssigned(query.getUserId()) .orderByTaskCreateTime().desc(); if(StringUtils.isNotBlank(query.getProcessKey())) { taskQuery.processDefinitionKey(query.getProcessKey()); } if(query.getDueDate() ! null) { taskQuery.taskDueBefore(query.getDueDate()); } ListTask tasks taskQuery.listPage( query.getPageNum() - 1, query.getPageSize() ); return new PageInfo(tasks.stream() .map(this::convertToVO) .collect(Collectors.toList())); }4.2 审批链设计模式实现多级审批的优雅方案public void completeWithChain(String taskId, MapString, Object variables) { Task currentTask taskService.createTaskQuery() .taskId(taskId).singleResult(); // 基础审批逻辑 taskService.complete(taskId, variables); // 判断是否需要下一级审批 Boolean needNextLevel (Boolean)variables.get(needNextLevel); if(needNextLevel ! null needNextLevel) { String nextAssignee calculateNextApprover( currentTask.getProcessInstanceId() ); Task nextTask taskService.createTaskQuery() .processInstanceId(currentTask.getProcessInstanceId()) .singleResult(); taskService.setAssignee(nextTask.getId(), nextAssignee); } }5. 流程可视化与监控5.1 动态流程图生成增强版的流程图生成方法GetMapping(/processDiagram) public void generateDiagram(HttpServletResponse response, RequestParam String processInstanceId) throws IOException { // 获取高亮节点 ListString activeActivities runtimeService.getActiveActivityIds(processInstanceId); // 获取历史路径 ListString highLightedFlows historyService.createHistoricActivityInstanceQuery() .processInstanceId(processInstanceId) .orderByHistoricActivityInstanceStartTime().asc() .list() .stream() .map(HistoricActivityInstance::getActivityId) .collect(Collectors.toList()); BpmnModel bpmnModel repositoryService.getBpmnModel( runtimeService.createProcessInstanceQuery() .processInstanceId(processInstanceId) .singleResult() .getProcessDefinitionId() ); try (InputStream is processDiagramGenerator.generateDiagram( bpmnModel, png, activeActivities, highLightedFlows, 宋体, 宋体, 宋体 )) { response.setContentType(image/png); IOUtils.copy(is, response.getOutputStream()); } }5.2 审批时间线分析通过历史数据生成审批时间线SELECT act.ACT_ID_ as nodeId, act.ACT_NAME_ as nodeName, MIN(act.START_TIME_) as startTime, MAX(act.END_TIME_) as endTime, TIMESTAMPDIFF(SECOND, MIN(act.START_TIME_), MAX(act.END_TIME_)) as duration FROM ACT_HI_ACTINST act WHERE act.PROC_INST_ID_ #{processInstanceId} GROUP BY act.ACT_ID_, act.ACT_NAME_ ORDER BY MIN(act.START_TIME_)6. 生产环境最佳实践6.1 性能优化配置在application.yml中添加关键配置flowable: async-executor: activate: true core-pool-size: 10 max-pool-size: 50 queue-size: 1000 database-schema-update: false history-level: audit6.2 异常处理策略实现全局流程异常处理器ControllerAdvice public class FlowableExceptionHandler { ExceptionHandler(FlowableException.class) public ResponseEntityErrorResponse handleFlowableException( FlowableException ex) { ErrorResponse error new ErrorResponse(); error.setTimestamp(LocalDateTime.now()); if(ex instanceof FlowableObjectNotFoundException) { error.setCode(PROCESS_NOT_FOUND); error.setMessage(流程资源不存在); return ResponseEntity.status(404).body(error); } // 其他异常处理... } }在项目实践中发现合理的流程版本管理策略能显著降低维护成本。建议采用语义化版本控制并在部署时自动归档旧版本流程图。对于复杂的审批场景可以考虑使用Flowable的DMN决策表来简化网关逻辑。