尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SpringBoot+Flowable构建订单审批工作流系统

SpringBoot+Flowable构建订单审批工作流系统 1. 项目概述在企业的日常运营中订单审批流程是最常见的工作流场景之一。传统的手工审批方式效率低下且难以追踪而基于工作流引擎的自动化审批系统能够显著提升业务处理效率。本文将详细介绍如何使用SpringBoot和Flowable这两个强大的开源框架构建一个完整的订单审批工作流系统。2. 技术选型解析2.1 为什么选择SpringBootSpringBoot作为当前Java领域最流行的微服务框架其优势在于自动配置简化了Spring应用的初始搭建和开发过程内嵌服务器无需部署WAR文件可直接运行丰富的starter依赖轻松集成各种常用组件生产就绪特性提供健康检查、指标监控等功能2.2 为什么选择FlowableFlowable是一个轻量级的工作流和业务流程管理(BPM)引擎相比Activiti等同类产品具有更简洁的API设计更优的性能表现更活跃的社区支持更完善的文档体系3. 环境准备与项目搭建3.1 基础环境配置首先确保开发环境满足以下要求JDK 1.8Maven 3.5MySQL 5.7或其他关系型数据库IDE推荐IntelliJ IDEA3.2 创建SpringBoot项目使用Spring Initializr创建项目时需要添加以下核心依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.flowable/groupId artifactIdflowable-spring-boot-starter/artifactId version6.7.0/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency3.3 数据库配置在application.properties中配置数据库连接spring.datasource.urljdbc:mysql://localhost:3306/flowable_db?useSSLfalseserverTimezoneUTC spring.datasource.usernameroot spring.datasource.passwordyourpassword spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver # Flowable配置 flowable.database-schema-updatetrue flowable.async-executor-activatefalse4. 工作流设计与实现4.1 订单审批流程设计我们设计一个典型的订单审批流程包含以下节点订单提交部门经理审批财务审核总经理审批仅限大额订单订单确认使用BPMN 2.0标准设计流程图可以在Flowable Modeler中可视化设计也可以直接编写XML。4.2 流程定义文件创建order-approval.bpmn20.xml文件definitions xmlnshttp://www.omg.org/spec/BPMN/20100524/MODEL xmlns:flowablehttp://flowable.org/bpmn targetNamespacehttp://flowable.org/bpmn process idorderApproval name订单审批流程 isExecutabletrue startEvent idstartEvent name订单提交/ userTask iddeptManagerApproval name部门经理审批 flowable:assignee${deptManager}/ sequenceFlow idflow1 sourceRefstartEvent targetRefdeptManagerApproval/ exclusiveGateway iddecisionGateway name金额判断/ sequenceFlow idflow2 sourceRefdeptManagerApproval targetRefdecisionGateway/ sequenceFlow idflow3 sourceRefdecisionGateway targetReffinanceApproval conditionExpression xsi:typetFormalExpression ![CDATA[${order.amount 10000}]] /conditionExpression /sequenceFlow sequenceFlow idflow4 sourceRefdecisionGateway targetRefgeneralManagerApproval conditionExpression xsi:typetFormalExpression ![CDATA[${order.amount 10000}]] /conditionExpression /sequenceFlow userTask idfinanceApproval name财务审核 flowable:assignee${financeStaff}/ userTask idgeneralManagerApproval name总经理审批 flowable:assignee${generalManager}/ sequenceFlow idflow5 sourceReffinanceApproval targetRefconfirmOrder/ sequenceFlow idflow6 sourceRefgeneralManagerApproval targetRefconfirmOrder/ endEvent idconfirmOrder name订单确认/ /process /definitions4.3 流程部署代码创建流程部署服务Service public class ProcessDeploymentService { Autowired private RepositoryService repositoryService; public void deployProcess() { repositoryService.createDeployment() .addClasspathResource(processes/order-approval.bpmn20.xml) .name(订单审批流程) .deploy(); } }5. 业务逻辑实现5.1 订单实体设计创建订单实体类Entity Table(name t_order) public class Order { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; private String orderNo; private String productName; private BigDecimal amount; private String applicant; private Date createTime; private String status; // 省略getter/setter }5.2 流程启动服务实现流程启动逻辑Service public class OrderApprovalService { Autowired private RuntimeService runtimeService; Autowired private OrderRepository orderRepository; Transactional public String startApprovalProcess(Order order) { // 保存订单 order.setStatus(审批中); order.setCreateTime(new Date()); orderRepository.save(order); // 设置流程变量 MapString, Object variables new HashMap(); variables.put(order, order); variables.put(deptManager, manager1); variables.put(financeStaff, finance1); variables.put(generalManager, ceo1); // 启动流程实例 ProcessInstance processInstance runtimeService.startProcessInstanceByKey( orderApproval, ORDER_ order.getId(), variables ); return processInstance.getId(); } }5.3 任务处理服务实现任务处理逻辑Service public class TaskService { Autowired private org.flowable.engine.TaskService taskService; Autowired private OrderRepository orderRepository; Transactional public void completeTask(String taskId, boolean approved, String comment) { // 获取当前任务 Task task taskService.createTaskQuery().taskId(taskId).singleResult(); // 设置流程变量 MapString, Object variables new HashMap(); variables.put(approved, approved); // 添加审批意见 if (StringUtils.isNotBlank(comment)) { taskService.addComment(taskId, task.getProcessInstanceId(), comment); } // 完成任务 taskService.complete(taskId, variables); // 如果是最后一个任务更新订单状态 if (confirmOrder.equals(task.getTaskDefinitionKey())) { String businessKey task.getProcessInstance().getBusinessKey(); Long orderId Long.parseLong(businessKey.replace(ORDER_, )); Order order orderRepository.findById(orderId).orElse(null); if (order ! null) { order.setStatus(已完成); orderRepository.save(order); } } } }6. 前端交互实现6.1 待办任务查询实现待办任务查询接口RestController RequestMapping(/api/tasks) public class TaskController { Autowired private org.flowable.engine.TaskService taskService; GetMapping(/{userId}) public ListTaskRepresentation getUserTasks(PathVariable String userId) { return taskService.createTaskQuery() .taskAssignee(userId) .orderByTaskCreateTime().desc() .list() .stream() .map(this::convertToRepresentation) .collect(Collectors.toList()); } private TaskRepresentation convertToRepresentation(Task task) { TaskRepresentation representation new TaskRepresentation(); representation.setId(task.getId()); representation.setName(task.getName()); representation.setProcessInstanceId(task.getProcessInstanceId()); representation.setCreateTime(task.getCreateTime()); // 获取流程变量 MapString, Object variables taskService.getVariables(task.getId()); representation.setVariables(variables); return representation; } }6.2 历史记录查询实现流程历史记录查询RestController RequestMapping(/api/history) public class HistoryController { Autowired private HistoryService historyService; GetMapping(/{processInstanceId}) public ListHistoricActivityInstance getProcessHistory( PathVariable String processInstanceId) { return historyService.createHistoricActivityInstanceQuery() .processInstanceId(processInstanceId) .orderByHistoricActivityInstanceStartTime().asc() .list(); } }7. 系统集成与扩展7.1 邮件通知集成在流程关键节点添加邮件通知Service public class NotificationService { Autowired private JavaMailSender mailSender; public void sendTaskNotification(String assignee, String taskName, String processInstanceId) { SimpleMailMessage message new SimpleMailMessage(); message.setTo(assignee company.com); message.setSubject(您有新的待办任务); message.setText(String.format( 您有一个新的待办任务%s\n流程实例ID%s\n请及时处理。, taskName, processInstanceId )); mailSender.send(message); } }7.2 多租户支持对于SaaS应用可以扩展实现多租户支持public class TenantAwareProcessEngineConfigurer implements ProcessEngineConfigurer { Override public void configure(SpringProcessEngineConfiguration configuration) { configuration.setTenantProvider(new DefaultTenantProvider() { Override public String getTenantId() { // 从当前线程上下文中获取租户ID return TenantContext.getCurrentTenant(); } }); } }8. 性能优化与监控8.1 异步执行器配置对于高并发场景启用异步执行器flowable.async-executor-activatetrue flowable.async-executor-core-pool-size10 flowable.async-executor-max-pool-size50 flowable.async-executor-queue-capacity10008.2 流程实例缓存配置流程实例缓存提高性能Configuration public class FlowableCacheConfig { Bean public ProcessEngineConfigurationConfigurer processEngineConfigurationConfigurer() { return configuration - { configuration.setProcessDefinitionCache(new DefaultDeploymentCacheProcessDefinitionEntity(100)); configuration.setProcessDefinitionInfoCache(new DefaultDeploymentCacheProcessDefinitionInfoCacheObject(100)); }; } }9. 常见问题与解决方案9.1 流程定义版本冲突当更新流程定义时Flowable会自动创建新版本。确保业务代码正确处理版本控制ProcessDefinition latestDefinition repositoryService.createProcessDefinitionQuery() .processDefinitionKey(orderApproval) .latestVersion() .singleResult();9.2 事务管理问题Flowable操作需要与业务操作在同一个事务中确保添加Transactional注解Transactional public void completeTaskWithBusinessOperation(String taskId) { // 业务操作 businessService.doSomething(); // 流程操作 taskService.complete(taskId); }9.3 高并发场景下的乐观锁异常在用户任务处理时添加重试机制Retryable(value FlowableOptimisticLockingException.class, maxAttempts 3) public void safeCompleteTask(String taskId) { taskService.complete(taskId); }10. 安全注意事项10.1 权限控制实现细粒度的权限控制PreAuthorize(hasPermission(#taskId, TASK, COMPLETE)) public void completeTask(String taskId) { // 任务处理逻辑 }10.2 敏感数据保护对于包含敏感信息的流程变量使用加密存储variables.put(encryptedData, encryptService.encrypt(sensitiveData));11. 测试策略11.1 单元测试编写流程单元测试SpringBootTest public class OrderApprovalProcessTest { Autowired private RuntimeService runtimeService; Autowired private TaskService taskService; Test public void testSmallAmountApproval() { // 启动流程 Order order new Order(); order.setAmount(new BigDecimal(5000)); MapString, Object variables new HashMap(); variables.put(order, order); variables.put(deptManager, testManager); variables.put(financeStaff, testFinance); ProcessInstance processInstance runtimeService.startProcessInstanceByKey( orderApproval, variables); // 验证任务 Task task taskService.createTaskQuery() .processInstanceId(processInstance.getId()) .singleResult(); assertEquals(部门经理审批, task.getName()); // 完成任务 taskService.complete(task.getId()); // 验证下一任务 task taskService.createTaskQuery() .processInstanceId(processInstance.getId()) .singleResult(); assertEquals(财务审核, task.getName()); } }11.2 性能测试使用JMeter进行并发测试重点关注流程启动响应时间任务查询性能高并发下的系统稳定性12. 部署方案12.1 本地开发环境使用内嵌H2数据库快速启动spring.datasource.urljdbc:h2:mem:flowable;DB_CLOSE_DELAY-1 spring.datasource.driver-class-nameorg.h2.Driver spring.datasource.usernamesa spring.datasource.password12.2 生产环境部署推荐使用Docker容器化部署FROM openjdk:11-jre-slim COPY target/order-approval.jar /app.jar ENTRYPOINT [java,-jar,/app.jar]配合数据库集群和负载均衡确保高可用性。13. 项目扩展方向13.1 动态表单集成集成动态表单引擎实现可视化表单设计// 动态表单绑定示例 FormService formService processEngine.getFormService(); TaskFormData taskFormData formService.getTaskFormData(taskId);13.2 移动端支持开发移动端审批应用支持待办任务推送移动端审批操作电子签名支持13.3 数据分析与报表基于流程历史数据构建分析报表审批时效分析流程瓶颈识别审批人效率统计14. 最佳实践总结在实际项目中应用该方案时建议遵循以下实践流程设计原则保持流程简单直观合理设置网关条件为每个用户任务定义清晰的审批人规则性能优化建议合理使用流程变量避免存储大对象对于高频查询添加适当缓存定期归档历史数据异常处理策略实现流程监控和预警机制提供流程干预接口记录详细的操作日志团队协作建议建立统一的流程设计规范版本控制流程定义文件编写详细的流程文档通过以上实现我们构建了一个完整的订单审批工作流系统。在实际应用中可以根据具体业务需求进行定制和扩展。
返回列表