工作流框架调研文档 – 支付系统人工审批流技术选型参考

# 工作流框架调研文档

> 支付系统人工审批流技术选型参考

## 目录

1. [Spring State Machine 简介](#1-spring-state-machine-简介)
2. [LiteFlow 简介](#2-liteflow-简介)
3. [自定义审批流方案(推荐)](#3-自定义审批流方案推荐)
4. [方案对比与选型建议](#4-方案对比与选型建议)

## 1. Spring State Machine 简介

Spring State Machine 是 Spring 官方出的状态机框架,基于 Spring Framework,用于构建状态机应用。

### 核心概念

**State (状态) + Event (事件) + Transition (转换)**

– **State**: 状态,如 PENDING、APPROVED
– **Event**: 事件,如 SUBMIT、APPROVE
– **Transition**: 状态转换,A –Event–> B
– **Guard**: 条件判断,决定是否能转换
– **Action**: 转换时执行的动作
– **StateMachine**: 状态机实例

### 三种持久化方式

| 方式 | 说明 |
|——|——|
| Ephemeral | 内存,重启丢失(测试用) |
| StateMachinePersist | 自定义持久化(Redis、DB) |
| JpaPersistingStateMachineListener | JPA 持久化(官方推荐) |

### 快速示例

**依赖:**

“`xml

org.springframework.statemachine
spring-statemachine-starter
4.0.0

“`

**1. 定义状态和事件:**

“`java
public enum PaymentState {
PENDING, RISK_CHECK, MANUAL_REVIEW, APPROVED, REJECTED
}

public enum PaymentEvent {
SUBMIT, RISK_PASS, RISK_REJECT, NEED_MANUAL, APPROVE, REJECT
}
“`

**2. 配置状态机:**

“`java
@Configuration
@EnableStateMachine
public class PaymentStateConfig extends StateMachineConfigurerAdapter {

@Override
public void configure(StateMachineStateConfigurer states) throws Exception {
states
.withStates()
.initial(PaymentState.PENDING)
.state(PaymentState.RISK_CHECK)
.state(PaymentState.MANUAL_REVIEW)
.end(PaymentState.APPROVED)
.end(PaymentState.REJECTED);
}

@Override
public void configure(StateMachineTransitionConfigurer transitions) throws Exception {
transitions
.withExternal().source(PaymentState.PENDING).target(PaymentState.RISK_CHECK)
.event(PaymentEvent.SUBMIT)
.action(ctx -> log.info(“提交风控”))
.and()
.withExternal().source(PaymentState.RISK_CHECK).target(PaymentState.APPROVED)
.event(PaymentEvent.RISK_PASS)
.and()
.withExternal().source(PaymentState.RISK_CHECK).target(PaymentState.MANUAL_REVIEW)
.event(PaymentEvent.NEED_MANUAL)
.and()
.withExternal().source(PaymentState.RISK_CHECK).target(PaymentState.REJECTED)
.event(PaymentEvent.RISK_REJECT)
.and()
.withExternal().source(PaymentState.MANUAL_REVIEW).target(PaymentState.APPROVED)
.event(PaymentEvent.APPROVE)
.and()
.withExternal().source(PaymentState.MANUAL_REVIEW).target(PaymentState.REJECTED)
.event(PaymentEvent.REJECT);
}
}
“`

**3. 使用状态机:**

“`java
@Service
@RequiredArgsConstructor
public class PaymentService {
private final StateMachine stateMachine;

public void submitPayment(Long paymentId) {
stateMachine.start();
Message message = MessageBuilder
.withPayload(PaymentEvent.SUBMIT)
.setHeader(“paymentId”, paymentId)
.build();
stateMachine.sendEvent(message);
log.info(“当前状态: {}”, stateMachine.getState().getId());
}

public void riskCheckComplete(Long paymentId, boolean pass) {
PaymentEvent event = pass ? PaymentEvent.RISK_PASS : PaymentEvent.RISK_REJECT;
stateMachine.sendEvent(event);
}
}
“`

### 注意事项

| 问题 | 说明 |
|——|——|
| 性能 | 单机单实例,高并发建议用 Redis 分布式锁 |
| 持久化 | 默认内存,需自行实现 StateMachinePersist 持久化 |
| 重试 | 内置 RetryInterceptor,需额外配置 |
| 调试 | 提供 @WithStateMachine 测试支持 |

### vs 自定义状态机

| 维度 | 自定义 | Spring State Machine |
|——|——–|———————|
| 代码量 | 少 | 中 |
| 可视化状态图 | ❌ | ✅(Spring State Machine Visualizer) |
| 持久化 | 自行实现 | 内置支持(需配置) |
| Guard/Action | 自行实现 | 内置 |
| 学习成本 | 低 | 中 |

## 2. LiteFlow 简介

LiteFlow 是国产的规则引擎框架(由 Yomahub 出品),主打轻量 + 高性能,适用于复杂业务规则路由,而非传统审批流。

### 定位

| 维度 | 说明 |
|——|——|
| 定位 | 规则引擎 / 流程编排 |
| 适用场景 | 规则路由、决策树、业务规则编排 |
| 不擅长 | 需要人工审批、多实例协作的长流程 |
| 许可证 | Apache 2.0(免费) |

### 核心概念

**Chain (链) = Node (节点) + Node (节点) + Node (节点)**

– **SWITCH(x)**: 条件分支,类似 if/else
– **WHEN(并行)**: 多节点并行执行
– **THEN(串行)**: 依次执行
– **BREAK**: 终止流程

### 快速示例

**依赖:**

“`xml

com.yomahub
liteflow-spring-boot-starter
2.11.0

“`

**1. 定义流程规则(flow.xml):**

“`xml



THEN(
“riskCheckNode”,
SWITCH($payment.getType())
.CASE(“NORMAL”, “normalPayNode”)
.CASE(“HIGH_RISK”, “highRiskPayNode”)
.CASE(“VIP”, “vipPayNode”),
“notifyNode”
);


“`

**2. 定义节点(Java):**

“`java
@Component
public class RiskCheckNode extends NodeComponent {
@Override
public void process() {
Payment payment = this.getContextData(Payment.class);

if (blacklistService.isBlacklisted(payment.getUserId())) {
this.setNextNodeId(“rejectNode”);
return;
}

int riskScore = riskService.calculateScore(payment);
payment.setRiskScore(riskScore);

if (riskScore > 80) {
this.setNextNodeId(“highRiskPayNode”);
}
}
}
“`

**3. 执行流程:**

“`java
@Service
@RequiredArgsConstructor
public class PaymentService {
private final FlowExecutor flowExecutor;

public PaymentResult routePayment(Payment payment) {
DefaultContext context = new DefaultContext();
context.set(“payment”, payment);

LiteFlowResponse response = flowExecutor.execute2Resp(
“paymentRoute”, context
);

if (response.isSuccess()) {
return (PaymentResult) response.getContextData(“result”);
} else {
throw new PaymentException(“路由失败”);
}
}
}
“`

### vs Spring State Machine

| 维度 | LiteFlow | Spring State Machine |
|——|———-|———————|
| 设计目标 | 规则路由编排 | 状态机 |
| 配置方式 | XML/YML(可视化友好) | Java 代码 |
| 适用场景 | 规则引擎、路由决策 | 状态流转、审批流 |
| 人工干预 | ❌ 不支持 | ✅ 支持任务领取 |
| 并行执行 | ✅ WHEN 原生支持 | ⚠️ 需额外配置 |
| 性能 | 高(无状态设计) | 中 |
| 状态持久化 | ❌ 无内置 | ✅ 可配置 |

### 典型使用场景

– **支付路由**: 根据金额、用户类型、风控分数选择不同支付通道
– **风控决策**: 多规则并行检查,最终决策
– **营销规则**: 优惠券、折扣、满减等规则编排
– **订单处理**: 根据订单类型、地区、商品类型走不同处理流程

### 总结

**LiteFlow = 规则引擎 ≠ 审批流引擎**

如果你的需求是根据条件选择不同的处理逻辑(路由、决策、规则编排),LiteFlow 非常合适。

如果你的需求是需要人工审批、多步骤流转、任务管理,Spring State Machine 或自定义状态机更合适。

## 3. 自定义审批流方案(推荐)

针对人工审批 + 多步骤流转场景的自定义轻量级解决方案。

### 设计思路

“`
┌──────────────────────────────────────────────────────┐
│ 审批流核心模型 │
│ │
│ WorkflowDef (流程定义) │
│ │ │
│ ├──► WorkflowStep (步骤定义) │
│ │ │ │
│ │ └──► 1. 步骤顺序 │
│ │ └──► 2. 审批者类型(角色/用户) │
│ │ └──► 3. 通过条件 │
│ │ │
│ WorkflowInstance (流程实例) ← 业务表关联 │
│ │ │
│ ├──► Task (待办任务) ← 人工审批入口 │
│ │ │
│ └──► TaskHistory (审批历史) ← 审计记录 │
└──────────────────────────────────────────────────────┘
“`

### 核心表结构

“`sql
— 流程定义表
CREATE TABLE workflow_def (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
workflow_code VARCHAR(64) NOT NULL UNIQUE, — ‘merchant_audit’
name VARCHAR(128), — ‘商户审核流程’
version INT DEFAULT 1,
status TINYINT DEFAULT 1, — 1启用 0禁用
created_at DATETIME,
updated_at DATETIME
);

— 步骤定义表
CREATE TABLE workflow_step (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
workflow_def_id BIGINT NOT NULL,
step_code VARCHAR(64), — ‘risk_check’
step_name VARCHAR(128), — ‘风控审核’
step_order INT NOT NULL, — 顺序
approver_type VARCHAR(32), — ‘ROLE’ / ‘USER’ / ‘EXPR’
approver_value VARCHAR(256), — ‘risk_team’ / ‘user_123’ / ‘${initiator}’
pass_condition VARCHAR(64), — ‘ALL_PASS’ / ‘ONE_PASS’
created_at DATETIME
);

— 流程实例表(绑定业务)
CREATE TABLE workflow_instance (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
workflow_def_id BIGINT NOT NULL,
biz_type VARCHAR(64), — ‘merchant’
biz_id BIGINT NOT NULL, — merchant_audit.id
initiator VARCHAR(64), — 发起人
current_step INT DEFAULT 1, — 当前步骤
status VARCHAR(32), — RUNNING / APPROVED / REJECTED
created_at DATETIME,
updated_at DATETIME
);

— 待办任务表
CREATE TABLE workflow_task (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
instance_id BIGINT NOT NULL,
step_code VARCHAR(64),
assignee VARCHAR(64), — 审批人
status VARCHAR(32), — PENDING / COMPLETED / REJECTED
result VARCHAR(32), — PASS / REJECT
comment TEXT, — 审批意见
created_at DATETIME,
completed_at DATETIME
);

— 审批历史表
CREATE TABLE workflow_history (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
instance_id BIGINT NOT NULL,
step_code VARCHAR(64),
operator VARCHAR(64),
action VARCHAR(32), — SUBMIT / APPROVE / REJECT
comment TEXT,
created_at DATETIME
);
“`

### 核心代码

**流程状态枚举:**

“`java
public enum WorkflowStatus {
PENDING, // 待审批
RUNNING, // 审批中
PASSED, // 审批通过
REJECTED, // 审批拒绝
CANCELLED // 已取消
}
“`

**流程服务:**

“`java
@Service
@Slf4j
public class WorkflowService {

@Autowired private WorkflowDefMapper workflowDefMapper;
@Autowired private WorkflowStepMapper stepMapper;
@Autowired private WorkflowInstanceMapper instanceMapper;
@Autowired private WorkflowTaskMapper taskMapper;
@Autowired private WorkflowHistoryMapper historyMapper;

/** 启动流程 */
public Long startWorkflow(String workflowCode, String bizType, Long bizId, String initiator) {
// 1. 获取流程定义
WorkflowDef def = workflowDefMapper.findByCode(workflowCode);
List steps = stepMapper.findByDefId(def.getId());

// 2. 创建流程实例
WorkflowInstance instance = new WorkflowInstance();
instance.setWorkflowDefId(def.getId());
instance.setBizType(bizType);
instance.setBizId(bizId);
instance.setInitiator(initiator);
instance.setCurrentStep(1);
instance.setStatus(WorkflowStatus.RUNNING.name());
instanceMapper.insert(instance);

// 3. 创建第一个任务
createTask(instance, steps.get(0), initiator);

// 4. 记录历史
saveHistory(instance, null, “SUBMIT”, initiator);

log.info(“启动流程实例: {}, 业务: {}:{}”, workflowCode, bizType, bizId);
return instance.getId();
}

/** 审批任务 */
public void approve(Long taskId, String operator, String result, String comment) {
WorkflowTask task = taskMapper.findById(taskId);
WorkflowInstance instance = instanceMapper.findById(task.getInstanceId());
List steps = stepMapper.findByDefId(instance.getWorkflowDefId());

// 1. 完成当前任务
task.setStatus(“COMPLETED”);
task.setResult(result);
task.setComment(comment);
task.setCompletedAt(LocalDateTime.now());
taskMapper.update(task);

// 2. 记录历史
saveHistory(instance, task.getStepCode(), result, operator);

// 3. 判断是否通过
WorkflowStep currentStep = steps.get(instance.getCurrentStep() – 1);
boolean stepPass = “PASS”.equals(result);

if (!stepPass) {
// 步骤未通过,流程结束
instance.setStatus(WorkflowStatus.REJECTED.name());
instanceMapper.update(instance);
log.info(“流程拒绝: {}”, instance.getId());
return;
}

// 4. 检查是否还有下一步
int nextStepIndex = instance.getCurrentStep();
if (nextStepIndex >= steps.size()) {
// 流程完成
instance.setStatus(WorkflowStatus.PASSED.name());
instanceMapper.update(instance);
log.info(“流程通过: {}”, instance.getId());
return;
}

// 5. 进入下一步
instance.setCurrentStep(nextStepIndex + 1);
instanceMapper.update(instance);

// 6. 创建下一步任务
WorkflowStep nextStep = steps.get(nextStepIndex);
String nextAssignee = resolveAssignee(nextStep, instance);
createTask(instance, nextStep, nextAssignee);

log.info(“流程流转至步骤: {}, 任务分配给: {}”, nextStep.getStepCode(), nextAssignee);
}

/** 查询待办任务 */
public List getPendingTasks(String assignee) {
return taskMapper.findPendingByAssignee(assignee);
}

private void createTask(WorkflowInstance instance, WorkflowStep step, String assignee) {
WorkflowTask task = new WorkflowTask();
task.setInstanceId(instance.getId());
task.setStepCode(step.getStepCode());
task.setAssignee(assignee);
task.setStatus(“PENDING”);
task.setCreatedAt(LocalDateTime.now());
taskMapper.insert(task);
}

private String resolveAssignee(WorkflowStep step, WorkflowInstance instance) {
if (“INITIATOR”.equals(step.getApproverValue())) {
return instance.getInitiator();
}
if (“EXPR”.equals(step.getApproverType())) {
// 动态表达式,如 ${initiator} 或 ${amount > 10000 ? ‘admin’ : ‘user’}
return evaluateExpression(step.getApproverValue(), instance);
}
return step.getApproverValue();
}

private void saveHistory(WorkflowInstance instance, String stepCode, String action, String operator) {
WorkflowHistory history = new WorkflowHistory();
history.setInstanceId(instance.getId());
history.setStepCode(stepCode);
history.setAction(action);
history.setOperator(operator);
history.setCreatedAt(LocalDateTime.now());
historyMapper.insert(history);
}
}
“`

**使用示例:**

“`java
@Service
@RequiredArgsConstructor
public class MerchantAuditService {

private final WorkflowService workflowService;

/** 商户提交审核 */
public void submitAudit(MerchantAudit audit) {
auditService.save(audit);
workflowService.startWorkflow(“merchant_audit”, “merchant_audit”, audit.getId(), audit.getApplicant());
}

/** 审批通过 */
public void approve(Long taskId, String operator) {
workflowService.approve(taskId, operator, “PASS”, “同意”);
}

/** 审批拒绝 */
public void reject(Long taskId, String operator, String reason) {
workflowService.approve(taskId, operator, “REJECT”, reason);
}

/** 查询待审批列表 */
public List getMyTasks(String operator) {
return workflowService.getPendingTasks(operator);
}
}
“`

### 优点

| 优点 | 说明 |
|——|——|
| **零依赖** | 仅 MySQL,无额外框架 |
| **完全可控** | 代码即文档,可自行扩展 |
| **轻量** | 核心代码 < 300 行 | | **灵活** | 可加会签、知会、加签、委托等 | | **可观测** | 完整的审批历史记录 | ### 可扩展功能 | 功能 | 难度 | 说明 | |------|------|------| | 会签(多人审批) | ⭐⭐ | 同一任务分配多人,需全部通过 | | 知会(非审批人) | ⭐ | 只通知,不阻塞流程 | | 加签 | ⭐⭐ | 审批中追加审批人 | | 委托 | ⭐ | 将任务转给他人 | | 催办 | ⭐ | 定时提醒未审批任务 | | 驳回 | ⭐⭐ | 驳回到指定步骤 | --- ## 4. 方案对比与选型建议 ### 方案对比 | 方案 | 人工审批 | 多步骤 | 复杂度 | 推荐场景 | 推荐度 | |------|:--------:|:------:|--------|----------|:------:| | **自定义状态机 + 任务表** | ✅ | ✅ | 低 | 简单流程(≤5状态) | ⭐⭐⭐⭐⭐ | | **Spring State Machine** | ✅ | ✅ | 中 | 中等流程,有持久化需求 | ⭐⭐⭐ | | **LiteFlow** | ❌ | ⚠️ | 中 | 规则路由、决策树 | ⭐⭐ | | **Camunda 7** | ✅ | ✅ | 高 | 复杂企业流程 | ⭐⭐ | | **Activiti** | ✅ | ✅ | 高 | 复杂企业流程 | ⭐ | ### 针对支付系统的建议 针对支付系统(风控审核、入账确认)场景,推荐使用自定义审批流方案: | 场景 | 推荐方案 | |------|----------| | 商户审核(简单多级审批) | 自定义状态机 + 审批任务表 | | 订单状态流转 | 枚举 + 状态机 | | 需要持久化/重启恢复 | Spring State Machine + JPA | | 费率/限额规则路由 | LiteFlow | ### 下一步 如需进一步集成到项目中,可提供以下支持: - [ ] 完整的数据库表结构(SQL 脚本) - [ ] Mapper、Service、Controller 代码生成 - [ ] 工作流定义配置(风控审核、人工复核等) - [ ] REST API 接口设计 --- *文档生成时间: 2026-04-30*

上一篇 NewAPI 渠道故障重试设置方法
目录
文章列表
1 JSON Web Token(JWT)使用步骤说明
JSON Web Token(JWT)使用步骤说明
2
Atlas加载bundle插件总结:ViewGroup中加载及本地startActivity方式
Atlas加载bundle插件总结:ViewGroup中加载及本地startActivity方式
3
Flutter页面间跳转和传参Navigator的使用
Flutter页面间跳转和传参Navigator的使用
4
悲观锁和乐观锁的原理及使用场景
悲观锁和乐观锁的原理及使用场景
5
Tinker热更新总结
Tinker热更新总结
最新评论
一位WordPress评论者
一位WordPress评论者
2月12日
您好,这是一条评论。若需要审核、编辑或删除评论,请访问仪表盘的评论界面。评论者头像来自 Gravatar。