跳到主要内容
基于 SpringBoot+Flowable 的通用审批流程架构 | 极客日志
Java java
基于 SpringBoot+Flowable 的通用审批流程架构 综述由AI生成 一种基于 SpringBoot 和 Flowable 工作流引擎的通用审批流程架构设计。该框架通过策略模式实现业务扩展,支持新增流程时仅需创建 BPMN 文件、配置业务类型及可选实现业务处理器。核心组件包括通用的 WorkflowService、业务处理器注册中心及统一的数据库模型(利用 JSON 存储扩展数据)。文章详细阐述了整体架构图、代码结构、数据库表设计、API 接口规范、流程变量命名规则以及新增流程的具体步骤指南,旨在降低维护成本并提升系统的可扩展性与灵活性。
赛博行者 发布于 2026/3/24 更新于 2026/5/6 13K 浏览基于 SpringBoot+Flowable 的通用审批流程架构
1. 概述
1.1 背景
企业业务系统中存在大量审批流程需求,如设备故障处理、请假申请、采购审批等。传统开发方式需要为每个流程创建独立的表结构、实体类、服务类和控制器,导致代码重复率高、维护成本大。
本框架基于 SpringBoot + Flowable 工作流引擎,设计了一套通用审批流程框架 ,通过策略模式实现业务扩展,让新增流程时只需:
创建 BPMN 流程定义文件
配置业务类型
实现业务处理器(可选)
1.2 技术栈
技术 版本 说明 Spring Boot 2.7.18 基础框架 Flowable 6.8.1 工作流引擎 MySQL 8.0+ 数据库 Flyway - 数据库版本管理 Nacos 2021.0.5.0 配置中心/服务发现
1.3 设计目标
可扩展性 :新增流程时代码改动最小化
通用性 :统一的 API 接口、统一的数据模型
灵活性 :支持复杂业务逻辑的定制扩展
可维护性 :清晰的代码结构、职责分离
2. 架构设计
2.1 整体架构图
┌──────────────────────────────────────────────────────────────────┐
│ 前端应用 │
└──────────────────────────────┬───────────────────────────────────┘
│ REST API
┌──────────────────────────────┴───────────────────────────────────┐
│ WorkflowController │
│ (通用 API: 启动流程、完成任务、查询等) │
└──────────────────────────────┬───────────────────────────────────┘
│
┌──────────────────────────────┴───────────────────────────────────┐
│ WorkflowService │
│ (通用业务逻辑层) │
└───────────┬──────────────────┴───────────────────┬───────────────┘
│ │
▼ ▼
┌───────────────────────┐ ┌───────────────────────────┐
│ BusinessHandlerRegistry│ │ Flowable Engine │
│ (业务处理器注册中心) │ │ RuntimeService │
└───────────┬───────────┘ │ TaskService │
│ │ HistoryService │
▼ └───────────────────────────┘
┌───────────────────────────────────────────────────────────────────┐
│ BusinessHandler (策略接口) │
├───────────────────┬───────────────────┬───────────────────────────┤
│ DeviceFaultHandler│ LeaveApplyHandler │ ...其他业务处理器 │
│ (设备故障处理) │ (请假申请) │ │
└───────────────────┴───────────────────┴───────────────────────────┘
│
┌──────────────────────────────┴───────────────────────────────────┐
│ 通用数据层 │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ BusinessOrderDao│ │ApprovalRecordDao│ │BusinessTypeConfigDao│
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└──────────────────────────────┬───────────────────────────────────┘
│
┌──────────────────────────────┴───────────────────────────────────┐
│ MySQL 数据库 │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │wf_business_order│ │wf_approval_record│ │wf_business_type_config│
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
2.2 代码结构 src/main/java/com/siwei/flowable/
├── common/
│ ├── DictConstant.java
│ └── DictService.java
├── conf/
│ ├── DatabaseInitConfig.java
│ ├── FaultProcessConfig.java
│ ├── FlowableConfig.java
│ ├── FlowableWebConfig.java
│ ├── SecurityConfig.java
│ └── SwaggerConfig.java
├── controller/
│ ├── GeneratorController.java
│ ├── GlobalExceptionHandler.java
│ ├── IndexController.java
│ ├── InfoController.java
│ ├── ProcessController.java
│ └── WorkflowController.java
├── dao/
│ ├── ApprovalRecordDao.java
│ ├── BusinessOrderDao.java
│ └── BusinessTypeConfigDao.java
├── delegate/
│ ├── ArchiveAndNotifyDelegate.java
│ ├── CloseFaultTaskDelegate.java
│ └── NotifyMarketDeptDelegate.java
├── dto/
│ ├── ApprovalRecordDTO.java
│ ├── BusinessOrderDTO.java
│ ├── BusinessTypeDTO.java
│ ├── OsDeptDTO.java
│ ├── OsUserDTO.java
│ └── TaskDTO.java
├── entity/
│ ├── ApprovalRecord.java
│ ├── BusinessOrder.java
│ └── BusinessTypeConfig.java
├── enums/
│ ├── ApprovalActionEnum.java
│ ├── OrderStatusEnum.java
│ └── PriorityEnum.java
├── handler/
│ ├── BusinessHandler.java
│ └── BusinessHandlerRegistry.java
├── request/
│ ├── CompleteTaskRequest.java
│ ├── StartProcessRequest.java
│ ├── TaskQueryRequest.java
│ └── WithdrawProcessRequest.java
├── service/
│ ├── OsIdmUserService.java
│ ├── OsUserAdapterService.java
│ ├── WorkflowConfigService.java
│ ├── WorkflowService.java
│ └── impl/
│ ├── OsIdmUserServiceImpl.java
│ ├── OsUserAdapterServiceImpl.java
│ ├── WorkflowConfigServiceImpl.java
│ └── WorkflowServiceImpl.java
└── FlowableApplication.java
注:所有业务处理器(Handler)现在统一放在 handler 包下,包括:
BusinessHandler.java(接口)
BusinessHandlerRegistry.java(注册器)
DeviceFaultHandler.java(设备故障处理器)
其他业务处理器...
2.3 数据库设计
2.3.1 表结构概览 表名 说明 wf_business_order通用业务工单表 wf_approval_record通用审批记录表 wf_cc_record流程抄送记录表 wf_business_type_config业务类型配置表
2.3.2 wf_business_order(通用业务工单表) CREATE TABLE `wf_business_order` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键 ID' ,
`order_no` VARCHAR (64 ) NOT NULL COMMENT '工单编号' ,
`business_type` VARCHAR (64 ) NOT NULL COMMENT '业务类型 (对应流程定义 Key)' ,
`title` VARCHAR (256 ) NOT NULL COMMENT '工单标题' ,
`description` TEXT DEFAULT NULL COMMENT '工单描述' ,
`priority` TINYINT NOT NULL DEFAULT 1 COMMENT '优先级:1-普通 2-重要 3-紧急' ,
`initiator_id` BIGINT NOT NULL COMMENT '发起人 ID' ,
`initiator_name` VARCHAR (64 ) NOT NULL COMMENT '发起人姓名' ,
`initiator_dept_id` BIGINT DEFAULT NULL COMMENT '发起人部门 ID' ,
`initiator_dept_name` VARCHAR (128 ) DEFAULT NULL COMMENT '发起人部门名称' ,
`process_instance_id` VARCHAR (64 ) DEFAULT NULL COMMENT '流程实例 ID' ,
`current_task_id` VARCHAR (64 ) DEFAULT NULL COMMENT '当前任务 ID' ,
`current_task_name` VARCHAR (128 ) DEFAULT NULL COMMENT '当前任务名称' ,
`order_status` TINYINT NOT NULL DEFAULT 0 COMMENT '工单状态' ,
`business_data` JSON DEFAULT NULL COMMENT '业务扩展数据' ,
`result_data` JSON DEFAULT NULL COMMENT '处理结果数据' ,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_order_no` (`order_no`),
KEY `idx_business_type` (`business_type`),
KEY `idx_process_instance_id` (`process_instance_id`)
);
business_type 区分不同业务流程
business_data 用 JSON 存储各业务特有字段,避免每个业务建独立表
result_data 存储处理结果
2.3.3 wf_business_type_config(业务类型配置表) CREATE TABLE `wf_business_type_config` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`business_type` VARCHAR (64 ) NOT NULL COMMENT '业务类型标识' ,
`business_name` VARCHAR (128 ) NOT NULL COMMENT '业务名称' ,
`process_definition_key` VARCHAR (64 ) NOT NULL COMMENT '流程定义 Key' ,
`description` VARCHAR (512 ) DEFAULT NULL COMMENT '描述' ,
`order_no_prefix` VARCHAR (16 ) DEFAULT 'WF' COMMENT '工单编号前缀' ,
`form_config` JSON DEFAULT NULL COMMENT '表单配置' ,
`enabled` TINYINT DEFAULT 1 COMMENT '是否启用' ,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_business_type` (`business_type`)
);
3. 核心组件设计
3.1 BusinessHandler(业务处理器接口) 这是框架的核心扩展点,通过策略模式实现不同业务流程的定制逻辑。
public interface BusinessHandler {
String getBusinessType () ;
default void validateOnStart (StartProcessRequest request) {}
default Map<String, Object> beforeStart (StartProcessRequest request, BusinessOrder order) {
return null ;
}
default void afterStart (BusinessOrder order, String processInstanceId) {}
default void validateOnComplete (CompleteTaskRequest request, Task task, BusinessOrder order) {}
default Map<String, Object> beforeComplete (CompleteTaskRequest request, Task task, BusinessOrder order) {
return null ;
}
default void afterComplete (CompleteTaskRequest request, Task task, BusinessOrder order) {}
default void onProcessEnd (BusinessOrder order, boolean isApproved) {}
default Map<String, Object> enrichBusinessData (Map<String, Object> businessData) {
return businessData;
}
}
3.2 BusinessHandlerRegistry(处理器注册中心) 自动发现并注册所有 BusinessHandler 实现类。
@Component
public class BusinessHandlerRegistry {
private final Map<String, BusinessHandler> handlerMap = new HashMap <>();
private final BusinessHandler defaultHandler = new DefaultBusinessHandler ();
@Autowired(required = false)
private List<BusinessHandler> handlers;
@PostConstruct
public void init () {
if (handlers != null ) {
for (BusinessHandler handler : handlers) {
handlerMap.put(handler.getBusinessType(), handler);
}
}
}
public BusinessHandler getHandler (String businessType) {
return handlerMap.getOrDefault(businessType, defaultHandler);
}
}
3.3 WorkflowService(通用工作流服务) public interface WorkflowService {
BusinessOrderDTO startProcess (StartProcessRequest request) ;
void completeTask (CompleteTaskRequest request) ;
void claimTask (String taskId) ;
void withdrawProcess (Long orderId, String comment) ;
List<TaskDTO> getMyTodoTasks (TaskQueryRequest request) ;
List<TaskDTO> getMyDoneTasks (TaskQueryRequest request) ;
BusinessOrderDTO getOrderDetail (Long orderId) ;
List<ApprovalRecordDTO> getApprovalHistory (Long orderId) ;
}
4. API 接口设计
4.1 接口清单 接口 方法 说明 /api/workflow/startPOST 启动流程 /api/workflow/task/completePOST 完成任务 /api/workflow/task/claim/{taskId}POST 认领任务 /api/workflow/task/unclaim/{taskId}POST 取消认领 /api/workflow/withdraw/{orderId}POST 撤回流程 /api/workflow/task/todoGET 获取待办任务 /api/workflow/task/doneGET 获取已办任务 /api/workflow/order/my-initiatedGET 获取我发起的工单 /api/workflow/order/{orderId}GET 获取工单详情 /api/workflow/order/{orderId}/historyGET 获取审批历史 /api/workflow/business-typesGET 获取业务类型列表
4.2 启动流程请求 POST /api/workflow/start
{
"businessType" : "DEVICE_FAULT" ,
"title" : "生产线 A-设备 01 故障" ,
"description" : "设备运行异常,需要处理" ,
"priority" : 2 ,
"businessData" : {
"deviceId" : "DEVICE-001" ,
"deviceName" : "设备 01" ,
"faultReason" : "设备运行异常,温度过高" ,
"faultLevel" : 2 ,
"initiatorType" : 1
} ,
"processVariables" : {
}
}
4.3 完成任务请求 POST /api/workflow/task/complete
{
"taskId" : "12345" ,
"action" : "APPROVE" ,
"comment" : "同意,需要派工程师现场处理" ,
"actionData" : {
"needOnsite" : true ,
"assignedEngineerId" : 100 ,
"assignedEngineerName" : "张工"
} ,
"processVariables" : {
}
}
4.4 审批动作类型 Action 说明 APPROVE通过 REJECT拒绝 DELEGATE转办 ROLLBACK退回 COMMENT评论(不推进流程)
5. 流程变量命名规范 为了保证框架的通用性,流程变量需要遵循以下命名规范:
5.1 系统变量(框架自动设置) 变量名 类型 说明 orderIdLong 工单 ID orderNoString 工单编号 businessTypeString 业务类型 initiatorIdString 发起人 ID initiatorNameString 发起人姓名 initiatorDeptIdString 发起人部门 ID
5.2 审批变量(用于流程流转) 变量名 类型 说明 approvedBoolean 是否通过(用于排他网关判断)
5.3 候选组命名规范
运营中心候选组:dept_1
市场部候选组:dept_2
6. 后续新增流程指南
6.1 新增流程步骤总览 ┌─────────────────────────────────────────────────────────────┐
│ 新增审批流程步骤 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 步骤 1: 创建 BPMN 流程定义文件 │
│ └─ src/main/resources/processes/xxx-process.bpmn20.xml│
│ │
│ 步骤 2: 配置业务类型 │
│ └─ INSERT INTO wf_business_type_config ... │
│ │
│ 步骤 3: 实现业务处理器(可选) │
│ └─ handler/XxxHandler.java │
│ │
│ 步骤 4: 实现委托任务(可选) │
│ └─ delegate/XxxDelegate.java │
│ │
└─────────────────────────────────────────────────────────────┘
6.2 详细步骤说明
步骤 1: 创建 BPMN 流程定义文件 在 src/main/resources/processes/ 目录下创建流程定义文件。
示例:请假申请流程 leave-apply-process.bpmn20.xml
<?xml version="1.0" encoding="UTF-8" ?>
<definitions xmlns ="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:flowable ="http://flowable.org/bpmn"
targetNamespace ="http://www.siwei.com/flowable/leave" >
<process name ="请假申请流程" isExecutable ="true" >
<startEvent name ="提交申请" />
<userTask name ="部门经理审批"
flowable:candidateGroups ="${deptManagerGroupId}" />
<userTask name ="人事审批"
flowable:candidateGroups ="${hrGroupId}" />
<exclusiveGateway name ="请假天数判断" />
<endEvent name ="流程结束" />
<sequenceFlow sourceRef ="startEvent" targetRef ="deptManagerApproval" />
<sequenceFlow sourceRef ="deptManagerApproval" targetRef ="daysGateway" />
<sequenceFlow sourceRef ="daysGateway" targetRef ="hrApproval" >
<conditionExpression > ${leaveDays > 3}</conditionExpression >
</sequenceFlow >
<sequenceFlow sourceRef ="daysGateway" targetRef ="endEvent" >
<conditionExpression > ${leaveDays <= 3}</conditionExpression >
</sequenceFlow >
<sequenceFlow sourceRef ="hrApproval" targetRef ="endEvent" />
</process >
</definitions >
process id 必须唯一,作为流程定义 Key
候选组使用 ${变量名} 表达式,在业务处理器中设置
网关条件使用流程变量进行判断
步骤 2: 配置业务类型 在数据库 wf_business_type_config 表中插入配置:
INSERT INTO wf_business_type_config
(business_type, business_name, process_definition_key, description, order_no_prefix, enabled) VALUES
('LEAVE_APPLY' , '请假申请' , 'leaveApplyProcess' , '员工请假申请审批流程' , 'LA' , 1 );
字段 说明 business_type业务类型标识,全局唯一 business_name业务名称,用于前端展示 process_definition_key对应 BPMN 中的 process id order_no_prefix工单编号前缀
步骤 3: 实现业务处理器(可选) 创建文件: src/main/java/com/siwei/flowable/handler/LeaveApplyHandler.java
package com.siwei.flowable.handler;
import com.siwei.flowable.dto.BusinessOrderDTO;
import com.siwei.flowable.entity.BusinessOrder;
import com.siwei.flowable.handler.BusinessHandler;
import com.siwei.flowable.request.CompleteTaskRequest;
import com.siwei.flowable.request.StartProcessRequest;
import lombok.extern.slf4j.Slf4j;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Component
public class LeaveApplyHandler implements BusinessHandler {
public static final String BUSINESS_TYPE = "LEAVE_APPLY" ;
@Override
public String getBusinessType () {
return BUSINESS_TYPE;
}
@Override
public void validateOnStart (StartProcessRequest request) {
Map<String, Object> data = request.getBusinessData();
if (data == null ) {
throw new IllegalArgumentException ("业务数据不能为空" );
}
if (data.get("leaveType" ) == null ) {
throw new IllegalArgumentException ("请假类型不能为空" );
}
if (data.get("leaveDays" ) == null ) {
throw new IllegalArgumentException ("请假天数不能为空" );
}
if (data.get("startDate" ) == null || data.get("endDate" ) == null ) {
throw new IllegalArgumentException ("请假日期不能为空" );
}
}
@Override
public Map<String, Object> beforeStart (StartProcessRequest request, BusinessOrder order) {
Map<String, Object> variables = new HashMap <>();
Map<String, Object> data = request.getBusinessData();
Object leaveDays = data.get("leaveDays" );
variables.put("leaveDays" , leaveDays instanceof Number ?
((Number) leaveDays).intValue() : Integer.parseInt(leaveDays.toString()));
variables.put("deptManagerGroupId" , "dept_manager_" + order.getInitiatorDeptId());
variables.put("hrGroupId" , "dept_hr" );
return variables;
}
@Override
public Map<String, Object> enrichBusinessData (Map<String, Object> businessData) {
if (businessData == null ) {
return null ;
}
Map<String, Object> enriched = new HashMap <>(businessData);
Object leaveType = businessData.get("leaveType" );
if (leaveType != null ) {
int type = leaveType instanceof Number ? ((Number) leaveType).intValue() :
Integer.parseInt(leaveType.toString());
String typeDesc = switch (type) {
case 1 -> "年假" ;
case 2 -> "事假" ;
case 3 -> "病假" ;
case 4 -> "婚假" ;
case 5 -> "产假" ;
default -> "其他" ;
};
enriched.put("leaveTypeDesc" , typeDesc);
}
return enriched;
}
@Override
public void onProcessEnd (BusinessOrder order, boolean isApproved) {
log.info("请假申请流程结束,orderId={}, isApproved={}" , order.getId(), isApproved);
}
}
步骤 4: 实现委托任务(可选) 如果流程中有自动执行的服务任务(ServiceTask),创建委托类。
@Slf4j
@Component("leaveNotifyDelegate")
public class LeaveNotifyDelegate implements JavaDelegate {
@Override
public void execute (DelegateExecution execution) {
String processInstanceId = execution.getProcessInstanceId();
log.info("发送请假通知,processInstanceId={}" , processInstanceId);
}
}
6.3 不同复杂度流程的实现方式
简单流程(无特殊逻辑) 只需完成步骤 1 和步骤 2,框架会使用默认处理器。
适用场景: 简单的多级审批流程,无特殊校验和业务逻辑。
中等流程(需要校验和变量设置)
validateOnStart() - 启动校验
beforeStart() - 设置流程变量
enrichBusinessData() - 数据展示增强
复杂流程(需要自动任务)
所有处理器方法
委托任务类(JavaDelegate)
7. 配置说明
7.1 Nacos 配置
spring:
flyway:
enabled: true
locations: classpath:db/migration
baseline-on-migrate: true
fault:
process:
operation-center-dept-id: ${FAULT_OPERATION_CENTER_DEPT_ID:1}
market-dept-id: ${FAULT_MARKET_DEPT_ID:2}
engineer-dept-id: ${FAULT_ENGINEER_DEPT_ID:3}
leave:
process:
hr-dept-id: ${LEAVE_HR_DEPT_ID:10}
7.2 环境变量 变量名 说明 默认值 FAULT_OPERATION_CENTER_DEPT_ID运营中心部门 ID 1 FAULT_MARKET_DEPT_ID市场部部门 ID 2 FAULT_ENGINEER_DEPT_ID工程师部门 ID 3
8. 扩展点说明
8.1 通知服务扩展 // 1. 站内消息
// 2. 邮件通知
// 3. 短信通知
// 4. 企业微信/钉钉通知
8.2 表单配置扩展 wf_business_type_config.form_config 字段可以存储表单配置:
{
"fields" : [
{ "name" : "leaveType" , "label" : "请假类型" , "type" : "select" , "required" : true } ,
{ "name" : "leaveDays" , "label" : "请假天数" , "type" : "number" , "required" : true } ,
{ "name" : "reason" , "label" : "请假原因" , "type" : "textarea" , "required" : true }
]
}
9. 注意事项
9.1 开发规范
业务处理器类名以 Handler 结尾
委托任务类名以 Delegate 结尾
业务类型使用大写下划线命名,如 DEVICE_FAULT
流程定义 Key 使用小驼峰命名,如 deviceFaultProcess
9.2 性能考虑
businessData JSON 字段不建议存储过大数据
复杂查询场景可能需要为 JSON 字段创建虚拟列索引
高并发场景注意数据库连接池配置
9.3 版本管理
使用 Flyway 管理数据库版本
流程定义变更需要考虑版本兼容性
重大变更建议创建新的流程定义版本
10. 附录
10.1 工单状态流转图 ┌─────────┐
│ 草稿 │
│ DRAFT │
└────┬────┘
│ 提交
▼
┌─────────┐
┌─────────│ 审批中 │─────────┐
│APPROVING│
└────┬────┘
│
│
│ 撤回 │ 通过 │ 拒绝
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 已撤回 │ │ 已完成 │ │ 已拒绝 │
│WITHDRAWN│ │COMPLETED│ │REJECTED │
└─────────┘ └─────────┘ └─────────┘
10.2 审批动作与状态对应关系 动作 流程变化 工单状态变化 APPROVE 流转到下一节点 保持 APPROVING APPROVE (最后节点) 流程结束 变为 COMPLETED REJECT 流程结束 变为 REJECTED DELEGATE 任务转办 保持 APPROVING WITHDRAW 流程删除 变为 WITHDRAWN
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online