审批流程系统设计与实现:状态驱动、灵活扩展的企业级解决方案

本文基于实际企业级审批系统源码,深入解析如何设计高扩展性、强一致性的审批流程引擎,涵盖状态机设计、多租户隔离、文件服务集成等核心实现。

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 状态机流转逻辑
PENDING:
创建流程
PENDING
SUBMITTED:
提交
SUBMITTED
IN_PROGRESS:
启动审批
IN_PROGRESS
APPROVED:
最后一步通过
REJECTED:
任意步骤拒绝
APPROVED
REJECTED
WITHDRAW:
用户撤回
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 新增业务接入步骤
  1. BusinessType枚举中添加新业务类型
  2. 实现ApprovalHandler接口
@Component
public class NewBusinessHandler implements ApprovalHandler {@Overridepublic BusinessType getSupportedType() {return BusinessType.NEW_BUSINESS;}@Overridepublic void handleApproval(Long businessId, ApprovalStatus status) {// 实现业务状态更新逻辑}
}
  1. 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接口设计
审批模式策略灵活支持不同审批场景会签/串签流程
处理器注册机制开闭原则支持扩展新增业务审批
文件元数据分离独立管理存储资源附件管理

最佳实践建议

  1. 状态驱动开发:所有业务逻辑围绕状态流转实现
  2. 防腐层设计:通过DTO隔离领域模型与接口模型
  3. 幂等性保证:审批操作需支持重复提交
  4. 事件溯源:关键状态变更记录审计日志
  5. 资源隔离:按业务类型隔离审批流程实例

完整实现源码将托管至unknown:TODO

通过本文展示的审批系统设计,开发者可快速构建支持复杂业务流程的企业级审批引擎,其模块化设计和扩展机制能满足各类业务场景的审批需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/93001.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/93001.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/93001.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

汽车免拆诊断案例 | 2010款奥迪A4L车行驶中发动机偶尔自动熄火

故障现象 一辆2010款奥迪A4L车&#xff0c;搭载CDZ发动机 &#xff0c;累计行驶里程约为18.2万km。该车行驶中发动机偶尔自动熄火&#xff0c;有时熄火后能够立即重新起动着机&#xff0c;有时需要等待一会儿才能重新起动着机&#xff0c;故障频率较低。因该故障在其他维修厂陆…

Liam ERD:自动生成美观的交互式实体关系图

Liam ERD 是一个可以快速生成美观且具有交互性的数据库实体关系图&#xff08;ERD&#xff09;的工具&#xff0c;可以帮助用户实现复杂数据库结构的可视化。 Liam ERD 是一个免费开源的项目&#xff0c;代码托管在 GitHub&#xff1a; https://github.com/liam-hq/liam 功能…

网络协议序列化工具Protobuf

目录前言一、下载注意二、解压安装三、Protobuf的使用1、创建.proto文件2、利用protoc编译.proto文件前言 Protocol Buffers是Google的⼀种语⾔⽆关、平台⽆关、可扩展的序列化结构数据的⽅法&#xff0c;它可⽤于&#xff08;数据&#xff09;通信协议、数据存储等。 Protoco…

从表单校验到API网关:全链路输入安全防护指南

从表单校验到 API 网关:全链路输入安全防护指南 在软件系统的安全防御体系中,输入安全是第一道防线,而这道防线的坚固程度直接决定了系统抵御外部攻击的能力。从用户在浏览器中填写表单的那一刻起,到数据经过 API 网关流转至后端服务,每一个环节都可能成为输入攻击的突破…

Flask vs Django:微框架与一站式对决

Flask 简介 1、简介 Flask诞生于2010年&#xff0c;是Armin ronacher用Python语言基于Werkzeug工具箱编写的轻量级Web开发框架&#xff0c;又称之为微框架。 "微"的含义&#xff1a;Flask旨在保持核心简洁&#xff0c;本身相当于内核&#xff0c;其他功能需通过扩展…

真实业务场景:mysql慢查询优化(从17秒的查询优化到700毫秒)

慢查询业务场景:原先在我们系统中要统计一些人员的单位 部门信息的数据情况&#xff0c;比如总的男女人数&#xff0c;每个单位下的男女人数等等&#xff0c;然后原来的sql是这样写的 根据一个单位的id 然后对一张表做出多个子查询进行查询&#xff0c;这时候统计记录 由于加载…

远程影音访问:通过 cpolar 内网穿透服务使用 LibreTV

文章目录前言【视频教程】1.关于LibreTV2.docker部署LibreTV3.简单使用LibreTV4.安装cpolar内网穿透5.配置ward公网地址6.配置固定公网地址总结LibreTV 与 cpolar 的协同应用&#xff0c;为用户打造了一条通往高清观影自由的便捷之路。通过这一方案&#xff0c;用户不仅摆脱了商…

Apache ECharts 6 核心技术解密 – Vue3企业级可视化实战指南

简介 ECharts 是百度开源的一个使用 JavaScript 实现的开源可视化库&#xff0c;它能够生动、可交互地展示数据。在 Vue3 项目中集成 ECharts 可以让你的项目更加直观和动态地呈现数据信息。 核心优势 特性SVG渲染器Canvas渲染器缩放保真度★★★★★★★☆☆☆动态交互性能…

考公VS考研,拼哪个性价比高?

即将到来下半年&#xff0c;将迎来考公和考研是两个非常重要的考试&#xff0c;也是许多年轻人为之奋斗的目标。无论是获得一份稳定的“铁饭碗”&#xff0c;还是提升学历学位获得更高的竞争力&#xff0c;都是值得努力的方向。那么&#xff0c;考公vs考研&#xff0c;到底哪个…

python2操作neo4j

环境依赖 jdk、neo4j图数据库 操作一条数据完整demo import os,json,sys,io from py2neo import Graph,Nodetry:sys.stdout io.TextIOWrapper(sys.stdout.buffer, encodingutf-8)sys.stderr io.TextIOWrapper(sys.stderr.buffer, encodingutf-8) except Exception:passcla…

AI 编程实践:用 Trae 快速开发 HTML 贪吃蛇游戏

1. 背景与目标 贪吃蛇是最适合入门的 2D 网页小游戏之一&#xff1a;规则简单、反馈清晰、可扩展空间大&#xff08;穿墙模式、道具、多食物、排行榜……&#xff09;。 demo地址&#xff1a;https://game.haiyong.site/snake-game.html 本项目的目标是&#xff1a; 纯前端、…

FreeRTOS-C语言指针笔记

文章目录一级指针指针基本概念指针使用示例代码说明二、二级指针二级指针重点解析一级指针 C语言中的指针是一个非常重要的概念&#xff0c;它存储了变量的内存地址。指针的使用可以使程序更加高效&#xff0c;尤其在处理数组、字符串和动态内存分配时。 指针基本概念 指针变…

界面布局智能建议生成:从功能需求到专业UI的AI加速之路

内容简介: 传统界面设计让产品经理陷入"不懂设计、等设计师"的困境&#xff0c;效率低下还容易被挑刺。本文深度解析DeepSeek驱动的界面布局智能生成技术&#xff0c;通过DESIGN框架提示词模板&#xff0c;让产品经理在30分钟内生成3种专业级界面方案&#xff0c;实现…

【BLE系列-第三篇】数据链路层(LL):广播/连接/扫描流程详解

目录 引言 一、广播及连接建立 1.1 广播类型 1.2 扫描/连接请求与响应 1.2.1 广播流程说明 1.2.1.1 广播流程示例图 1.2.1.2 广播信息设置 1.2.1.3 信道广播 1.2.1.4 信道切换 1.2.1.5 广播间隔 1.2.1.6 接收窗口与理论最小传输时间 1.2.2 扫描/连接流程说明 1.2.…

JMeter 测试 WebSocket 接口的详细教程

1. 安装 WebSocket 插件 方法一&#xff1a;通过 Plugins Manager 下载并安装 JMeter Plugins Manager在 JMeter 中&#xff1a;Options → Plugins Manager搜索 WebSocket 并安装 方法二&#xff1a;手动安装 下载 jmeter-websocket-samplers 插件将 jar 文件放到 JMeter/…

飞算JavaAI智慧教育场景实践:从个性化学习到教学管理的全链路技术革新

目录一、智慧教育核心场景的技术突破1.1 个性化学习路径推荐系统1.1.1 学习者能力建模与评估1.2 智能教学管理系统1.2.1 自动化作业批改与学情分析1.3 教育资源智能管理系统1.3.1 教育资源智能标签与推荐二、智慧教育系统效能升级实践2.1 教育数据中台构建2.1.1 教育数据整合与…

Java面试场景题大全精简版

1.分布式系统下如何实现服务限流核心算法&#xff1a;固定窗口&#xff1a;将时间划分为固定窗口&#xff08;如 1 秒&#xff09;&#xff0c;统计窗口内请求数&#xff0c;超过阈值则限流。实现简单但存在临界值突发流量问题。滑动窗口&#xff1a;将固定窗口拆分为多个小窗口…

红帽 AI 推理服务 (vLLM) - 入门篇

《教程汇总》 RedHat AI Inference Server 和 vLLM vLLM (Virtual Large Language Model) 是一款专为大语言模型推理加速而设计的框架。它是由加州大学伯克利分校 (UC Berkeley) 的研究团队于 2023 年开源的项目&#xff0c;目前 UC Berkeley 和 RedHat 分别是 vLLM 开源社区…

Sql server 命令行和控制台使用二三事

近来遇到了几件关于sql server的事情。 第一&#xff1a;低版本sqlserver备份竟然无法还原到高版本 奇怪&#xff01;从来未碰到过。过程如下&#xff1a; 1.在低版本上中备份好了数据库 2.通过共享将文件拷贝到新服务器上 3.打开控制台&#xff0c;还原数据库&#xff0c;结果…

vue excel转json功能 xlsx

需求&#xff1a; 完成excel表格内容转json&#xff0c;excel表格内可能存在多个表格&#xff0c;要求全部解析出来。完成表格内合服功能&#xff0c;即&#xff1a;提取表格内老服务器与新服务器数据&#xff0c;多台老服务器对应合并到一台新服务器上 3.最终输出结果为:[{‘1…