# SmartApprove
**Repository Path**: wenbing123/smart-approve
## Basic Information
- **Project Name**: SmartApprove
- **Description**: SpringBoot 3 + Flowable 8 报销流程前后端系统
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2026-04-27
- **Last Updated**: 2026-05-22
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# SmartApprove - Flowable 工作流学习项目
基于 Spring Boot + Vue 3 的企业级报销审批系统,集成 Flowable 7 工作流引擎,适合作为 Flowable 学习入门项目。
## 项目简介
SmartApprove 是一个模拟企业内部报销审批流程的实战项目,通过实际业务场景帮助开发者快速掌握 Flowable 工作流的核心概念和开发技能。
## 技术架构
### 后端技术栈
| 技术 | 版本 | 说明 |
|------|------|------|
| Spring Boot | 3.2.5 | 基础框架 |
| Flowable | 7.0.1 | 工作流引擎 |
| MyBatis-Plus | 3.5.6 | ORM 框架 |
| MySQL | 8.0 | 数据库 |
| Redis | - | 缓存/消息队列 |
| JWT | 0.12.5 | 身份认证 |
| RabbitMQ | - | 消息队列 |
### 前端技术栈
| 技术 | 版本 | 说明 |
|------|------|------|
| Vue 3 | 3.x | 前端框架 |
| Vite | 5.x | 构建工具 |
| Element Plus | 2.x | UI 组件库 |
| Axios | 1.x | HTTP 客户端 |
## 快速开始
### 环境要求
- JDK 17+
- Node.js 18+
- MySQL 8.0+
- Maven 3.8+
### 1. 初始化数据库
```bash
# 创建数据库
mysql -u root -p < database/init.sql
```
### 2. 启动后端
```bash
cd backend
mvn spring-boot:run
```
后端启动后会自动:
- 初始化 Flowable 数据库表(17 张流程引擎表)
- 部署默认的报销审批流程
### 3. 启动前端
```bash
cd frontend
npm install
npm run dev
```
### 4. 访问系统
- 前端地址: http://localhost:5174
- 后端地址: http://localhost:3000
- API 文档: http://localhost:3000/doc.html (Knife4j)
## Flowable 核心概念学习
本项目完整演示了 Flowable 的核心概念,建议按以下顺序学习:
---
### 1. BPMN 2.0 流程定义
**文件位置**: `backend/src/main/resources/processes/expense-approval.bpmn20.xml`
```xml
```
**学习要点**:
- BPMN 2.0 是工作流的国际标准,Flowable 完全遵循该规范
- `process` 元素定义了一个完整的工作流
- `isExecutable="true"` 表示该流程可以被执行
- `id` 是流程的唯一标识,用于后续通过 Key 启动流程
---
### 2. 流程启动与实例管理
**服务层代码**: `backend/src/main/java/com/smartapprove/service/ProcessService.java`
```java
// 启动流程实例
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(
"expenseApproval", // 流程定义的 Key(与 BPMN 文件中 process 的 id 对应)
variables // 流程变量,如报销金额等
);
// 查询流程实例
ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery();
query.processInstanceId(processInstanceId);
// 删除流程实例
runtimeService.deleteProcessInstance(processInstanceId, "手动取消");
```
**Flowable 数据库表**:
| 表名 | 作用 |
|------|------|
| ACT_RU_EXECUTION | 运行时执行实例 |
| ACT_RU_VARIABLE | 运行时变量 |
| ACT_RU_TASK | 运行时任务 |
---
### 3. 用户任务与候选人查询
**查询待办任务**:
```java
TaskService taskService = processEngine.getTaskService();
TaskQuery query = taskService.createTaskQuery();
// 按候选人查询(用户属于某个角色组)
query.taskCandidateGroup("MANAGER");
// 按办理人查询(用户已认领的任务)
query.taskAssignee(userId.toString());
// 按流程实例ID查询
query.processInstanceId(processInstanceId);
List tasks = query.list();
```
**任务操作**:
```java
// 认领任务(抢单)
taskService.claim(taskId, userId.toString());
// 取消认领
taskService.unclaim(taskId);
// 完成任务
taskService.complete(taskId, variables);
// 转办
taskService.setAssignee(taskId, targetUserId);
```
**Flowable 数据库表**:
| 表名 | 作用 |
|------|------|
| ACT_RU_TASK | 运行时任务 |
| ACT_RU_IDENTITYLINK | 任务参与者关系 |
---
### 4. 排他网关(Exclusive Gateway)
排他网关用于根据条件选择唯一的执行路径。
```xml
5000 && approved}]]>
```
**执行效果**:
```
┌─────────────────────────────────────────────────────────────┐
│ 报销金额判断 │
└─────────────────────────────────────────────────────────────┘
│
┌──────────────┼──────────────┐
│ │ │
expenseAmount approved !approved
<= 5000 (驳回) (驳回)
│ │ │
▼ ▼ ▼
[结束] [财务审批] ←───── [驳回申请人]
│
└──> 返回部门经理审批
```
**学习要点**:
- 排他网关只会选择**一个**满足条件的分支
- 条件使用 UEL(Unified Expression Language)语法
- `approved` 是流程变量,由任务完成时设置
---
### 5. 任务监听器(Task Listener)
任务监听器用于在任务生命周期中执行自定义逻辑。
```xml
```
```java
public class DynamicApproverListener implements FlowableTaskListener {
@Override
public void notify(DelegateTask delegateTask) {
// 设置任务的办理人(而不是候选人组)
delegateTask.setAssignee("wangwu");
// 添加候选人
delegateTask.addCandidateUser("userId");
// 从流程变量中获取金额
Integer expenseAmount = delegateTask.getExecution()
.getVariable("expenseAmount", Integer.class);
}
}
```
**TaskListener 支持的事件**:
| 事件 | 触发时机 |
|------|----------|
| create | 任务被创建时 |
| assignment | 任务被分配时 |
| complete | 任务完成时 |
| delete | 任务被删除时 |
---
### 6. 执行监听器(Execution Listener)
执行监听器用于监听流程执行过程中的事件。
```xml
```
```java
public class ProcessStartListener implements FlowableExecutionListener {
@Override
public void notify(DelegateExecution execution) {
// 获取流程变量
Long reimbursementId = execution.getVariable("reimbursementId", Long.class);
// 获取流程定义信息
String processDefinitionId = execution.getProcessDefinitionId();
// 设置新的流程变量
execution.setVariable("startTime", new Date());
}
}
```
**ExecutionListener 支持的事件**:
| 事件 | 触发时机 |
|------|----------|
| start | 流程启动时 |
| end | 流程结束时 |
| take | 顺序流被执行时 |
---
### 7. 候选人组(Candidate Groups)
Flowable 的候选组机制是实现**动态审批人**的核心。
```xml
```
```java
// 查询某用户作为候选人的所有任务
TaskQuery query = taskService.createTaskQuery()
.taskCandidateUser(userId)
.taskCandidateGroup("MANAGER");
// Flowable 内部维护 IdentityLink 表管理用户-组关系
// 也能与 Spring Security 集成实现基于角色的任务分配
```
---
### 8. 流程变量(Process Variables)
流程变量在整个流程实例生命周期内可见。
```java
// 设置变量
runtimeService.setVariable(processInstanceId, "expenseAmount", 8000);
runtimeService.setVariableLocal(processInstanceId, "stepInfo", "当前在财务审批");
// 获取变量
Integer amount = (Integer) runtimeService.getVariable(processInstanceId, "expenseAmount");
// 任务级别的变量(只在该任务内可见)
taskService.setVariableLocal(taskId, "taskComment", "同意报销");
```
---
### 9. 流程历史(History)
Flowable 提供完整的历史查询能力。
```java
HistoryService historyService = processEngine.getHistoryService();
// 查询已完成的流程实例
HistoricProcessInstanceQuery query = historyService
.createHistoricProcessInstanceQuery()
.finished()
.processDefinitionKey("expenseApproval");
// 查询流程活动历史(节点流转记录)
List activities = historyService
.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceStartTime()
.asc()
.list();
// 查询任务历史
List tasks = historyService
.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId)
.finished()
.list();
// 查询变量历史
List variables = historyService
.createHistoricVariableInstanceQuery()
.processInstanceId(processInstanceId)
.list();
```
**Flowable 数据库表**:
| 表名 | 作用 |
|------|------|
| ACT_HI_PROCINST | 历史流程实例 |
| ACT_HI_TASKINST | 历史任务实例 |
| ACT_HI_ACTINST | 历史活动实例 |
| ACT_HI_VARINST | 历史变量 |
---
### 10. 流程图可视化
Flowable 支持生成 BPMN 流程图用于前端展示。
```java
ProcessDiagramGenerator generator = processEngine.getProcessEngineConfiguration()
.getProcessDiagramGenerator();
// 获取正在执行的活动节点
List currentActivityIds = runtimeService
.getActiveActivityIds(processInstanceId);
// 生成流程图 SVG/PNG
InputStream diagram = generator.generateDiagram(
bpmnModel,
"svg", // 输出格式
currentActivityIds, // 高亮的当前节点
Collections.emptyList(), // 高亮的流程线
"UTF-8"
);
```
---
## 项目业务功能
### 报销审批流程
```
申请人提交报销
│
▼
┌─────────────┐
│ 部门经理审批 │ ← 候选人组:MANAGER
└─────────────┘
│
▼
┌─────────────────┐
│ 金额判断网关 │
└─────────────────┘
│
├──── expenseAmount <= 5000 ────→ [结束] 审批通过
│
└──── expenseAmount > 5000 ────→ ┌─────────────┐
│ 财务审批 │ ← 动态指定审批人
└─────────────┘
│
┌────────┴────────┐
approved !approved
│ │
▼ ▼
[结束] [驳回给部门经理]
```
### 用户角色
| 角色 | 功能权限 |
|------|----------|
| EMPLOYEE | 提交报销、查看我的报销、撤销草稿 |
| MANAGER | 待办审批、已办审批、处理/认领任务 |
| FINANCE | 财务审批、查看流程实例 |
---
## API 接口
### 流程管理
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/process/todo` | GET | 获取我的待办任务 |
| `/api/process/done` | GET | 获取我的已办任务 |
| `/api/process/complete/{taskId}` | POST | 完成任务(审批) |
| `/api/process/claim/{taskId}` | POST | 认领任务 |
| `/api/process/unclaim/{taskId}` | POST | 取消认领 |
| `/api/process/reject/{taskId}` | POST | 驳回任务 |
| `/api/process/transfer/{taskId}` | POST | 转办任务 |
| `/api/process/history/{processInstanceId}` | GET | 获取流程历史 |
### 报销管理
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/expense/my` | GET | 获取我的报销列表 |
| `/api/expense/create` | POST | 创建报销单 |
| `/api/expense/submit/{id}` | POST | 提交报销 |
| `/api/expense/cancel/{id}` | POST | 撤销报销 |
| `/api/expense/detail/{id}` | GET | 报销单详情 |
---
## 常见问题
### 1. 流程定义更新
Flowable 支持多版本管理,更新 BPMN 文件后重新部署即可。
### 2. 动态审批人
通过 TaskListener 或表达式动态指定审批人,而不是固定的候选人组。
### 3. 会签(多实例审批)
Flowable 支持并行/串行多实例任务,可实现"多个审批人同时审批"场景。
### 4. 驳回/跳转
Flowable 原生不直接支持驳回,需要通过监听器操作 `execution` 实现驳回逻辑。
---
## 学习路径建议
1. **入门**: 阅读 BPMN 文件,理解流程定义
2. **实践**: 使用 Flowable UI(需单独部署)可视化操作流程
3. **进阶**: 学习任务监听器、执行监听器实现业务逻辑
4. **深入**: 研究 Flowable 数据库表,理解引擎内部机制
5. **扩展**: 学习 Flowable 与 Spring Security 集成、LDAP 集成
---
## 参考资料
- [Flowable 官方文档](https://flowable.com/open-source/docs/bpmn/ch03-Introduction)
- [Flowable GitHub](https://github.com/flowable/flowable-engine)
- [BPMN 2.0 规范](https://www.omg.org/spec/BPMN/2.0/)
## License
MIT License