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