审批流程系统设计与实现:状态驱动、灵活扩展的企业级解决方案
本文基于实际企业级审批系统源码,深入解析如何设计高扩展性、强一致性的审批流程引擎,涵盖状态机设计、多租户隔离、文件服务集成等核心实现。
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
通过本文展示的审批系统设计,开发者可快速构建支持复杂业务流程的企业级审批引擎,其模块化设计和扩展机制能满足各类业务场景的审批需求。