審批流程系統設計與實現:狀態驅動、靈活擴展的企業級解決方案
本文基于實際企業級審批系統源碼,深入解析如何設計高擴展性、強一致性的審批流程引擎,涵蓋狀態機設計、多租戶隔離、文件服務集成等核心實現。
1. 系統設計概覽
審批系統的核心架構分為三大模塊:
- 公共模塊:枚舉定義、DTO對象、基礎轉換器
- 審批模塊:流程引擎核心實現、模板管理
- 業務模塊:具體業務審批處理器
2. 公共模塊設計精要
2.1 狀態枚舉設計
通過枚舉實現狀態機是審批系統的核心設計模式:
// 業務流程狀態機
public enum ApprovalStatus {PENDING("待提交"),SUBMITTED("已提交"),APPROVED("審批通過"),REJECTED("拒絕"),WITHDRAW("撤回");
}// 流程執行狀態
public enum ProcessStatus {IN_PROGRESS("處理中"),APPROVED("通過"),REJECTED("拒絕"),WITHDRAW("撤回");
}// 審批模式
public enum ApprovalMode {SERIAL, // 串簽:順序審批PARALLEL // 會簽:并行審批
}
設計亮點:
- 使用
@Schema
注解實現OpenAPI文檔自動生成 - 通過
description
字段支持多語言擴展 - 嚴格區分流程狀態與業務狀態
2.2 DTO對象設計
數據傳輸對象實現分層解耦:
// 審批流程DTO
public class ApprovalProcessDTO {private Long id;private int currentStep; // 當前步驟private ProcessStatus processStatus;private List<ApprovalStepDTO> approvalStepDTOList; // 步驟樹
}// 審批步驟DTO
public class ApprovalStepDTO {private Integer stepOrder;private StepStatus stepStatus;private ApprovalMode approvalMode; private List<ApproverDTO> approverDTOList; // 審批人列表
}
分層結構:
BusinessDTO └── ApprovalProcessDTO└── ApprovalStepDTO└── ApproverDTO
3. 審批流程引擎核心實現
3.1 狀態機流轉邏輯
3.2 多模式審批處理
會簽(Parallel)模式處理邏輯:
// ApprovalProcessService.java
private void checkStepCompletion(ApprovalStep step, ApprovalProcess process, ApprovalStatus currentStatus) {if (step.getApprovalMode() == ApprovalMode.PARALLEL) {// 會簽模式:任一拒絕即整體拒絕boolean anyRejected = approverList.stream().anyMatch(a -> a.getStatus() == ApproverStatus.REJECTED);if (anyRejected) {rejectProcess(process); // 觸發流程拒絕} // 所有審批人通過才進入下一步else if (allApproved(approverList)) {moveToNextStep(process);}}
}
串簽(Serial)模式處理邏輯:
private void moveToNextApproverOrStep(ApprovalStep step, ApprovalProcess process) {if (step.getApprovalMode() == ApprovalMode.SERIAL) {// 查找下一個待處理審批人Optional<ApprovalStepApprover> nextApprover = approverRepository.findFirstByStepIdAndStatusOrderById(step.getId(), ApproverStatus.PENDING);if (nextApprover.isPresent()) return; // 不移動步驟}moveToNextStep(process); // 移動到下一步
}
4. 文件服務深度集成
4.1 文件關聯設計
@Entity
public class ApprovalStepApprover {@Idprivate Long id;// 通過approverId關聯文件private String approverId;
}@Entity
public class BaseFile {private String approverId; // 關聯審批人private String objectName; // MinIO存儲標識
}
4.2 文件操作服務
@Service
public class MinioService {// 生成唯一存儲路徑private String generateObjectName(String suffix) {return "approval/" + UUID.randomUUID() + "." + suffix;}// 上傳并關聯審批人public void uploadFile(String objectName, MultipartFile file) {minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(file.getInputStream(), file.getSize(), -1).build());}// 生成臨時訪問鏈接public String getPresignedUrl(String objectName) {return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(objectName).expiry(3600) // 1小時有效.build());}
}
5. 擴展性設計
5.1 業務處理器注冊機制
@Service
public class ApprovalProcessService {private final Map<BusinessType, Consumer<FinishApprovalDTO>> approvalHandlers;@PostConstructvoid initHandlers() {// 注冊原油業務處理器EnumSet.of(BusinessType.CRUDE_OIL_PURCHASE_CONFIRM_ORDER,BusinessType.CRUDE_OIL_PURCHASE_PLAN).forEach(type -> approvalHandlers.put(type, crudeOilMngClient::finishApproval));// 注冊原材料業務處理器approvalHandlers.put(BusinessType.RAW_MATERIAL_PROCUREMENT_PLAN, rawMaterialMngClient::finishApproval);}private void finishApproval(FinishApprovalDTO dto) {approvalHandlers.get(dto.getBusinessType()).accept(dto);}
}
5.2 新增業務接入步驟
- 在
BusinessType
枚舉中添加新業務類型 - 實現
ApprovalHandler
接口
@Component
public class NewBusinessHandler implements ApprovalHandler {@Overridepublic BusinessType getSupportedType() {return BusinessType.NEW_BUSINESS;}@Overridepublic void handleApproval(Long businessId, ApprovalStatus status) {// 實現業務狀態更新邏輯}
}
- 在
FinishApprovalService
中自動注冊處理器
6. 性能優化實踐
6.1 審批流程保存優化
// 批量保存優化:減少DB交互
private List<ApprovalStepDTO> saveSteps(Long processId, List<ApprovalStepDTO> stepDTOs) {// 批量保存步驟List<ApprovalStep> steps = stepRepository.saveAll(stepDTOs.stream().map(dto -> {ApprovalStep step = new ApprovalStep();step.setProcessId(processId);return step;}).collect(Collectors.toList()));// 批量保存審批人List<ApprovalStepApprover> approvers = new ArrayList<>();steps.forEach(step -> {stepDTOs.get(step.getStepOrder()-1).getApproverDTOList().forEach(approverDTO -> {ApprovalStepApprover a = new ApprovalStepApprover();a.setStepId(step.getId());approvers.add(a);});});approverRepository.saveAll(approvers);return convertToDTOs(steps);
}
6.2 文件清理任務
@Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2點執行
public void clearOrphanFiles() {List<BaseFile> orphans = baseFileRepository.findOrphanFiles();List<String> objectNames = orphans.stream().map(BaseFile::getObjectName).collect(Collectors.toList());minioService.removeFiles(objectNames); // 批量刪除baseFileRepository.deleteAll(orphans);
}
7. 關鍵設計決策總結
設計選擇 | 優勢 | 應用場景 |
---|---|---|
枚舉狀態機 | 編譯時檢查、杜絕無效狀態 | 流程狀態管理 |
DTO分層結構 | 解耦持久層與展示層 | API接口設計 |
審批模式策略 | 靈活支持不同審批場景 | 會簽/串簽流程 |
處理器注冊機制 | 開閉原則支持擴展 | 新增業務審批 |
文件元數據分離 | 獨立管理存儲資源 | 附件管理 |
最佳實踐建議:
- 狀態驅動開發:所有業務邏輯圍繞狀態流轉實現
- 防腐層設計:通過DTO隔離領域模型與接口模型
- 冪等性保證:審批操作需支持重復提交
- 事件溯源:關鍵狀態變更記錄審計日志
- 資源隔離:按業務類型隔離審批流程實例
完整實現源碼將托管至unknown:TODO
通過本文展示的審批系統設計,開發者可快速構建支持復雜業務流程的企業級審批引擎,其模塊化設計和擴展機制能滿足各類業務場景的審批需求。