一行代碼搞定 SpringBoot 極簡審批流!
兄弟們,今天咱們聊個職場剛需 —— 審批流。大家有沒有過這樣的經歷?寫個請假系統,為了實現 “員工提交→領導審批→HR 終審” 的流程,寫了幾百行 if-else,結果需求一變(比如超過 3 天要二級審批),代碼改得面目全非,最后自己都看不懂。
這還不算完,一旦流程復雜起來,什么狀態機、任務分配、分支判斷…… 簡直讓人頭禿。
但今天,我要告訴你一個秘密:審批流可以優雅到只用一行代碼!沒錯,就是那種 “寫完直接摸魚,需求隨便改” 的神器。
一、核心武器:Flowable,審批界的瑞士軍刀
1. 為什么是 Flowable?
在 Java 領域,提到審批流,繞不開兩個名字:Activiti 和 Flowable。
Activiti 是老前輩,但 Flowable 更像 “改良版”—— 它繼承了 Activiti 的核心團隊,還做了這些升級:
- 更輕量:移除了冗余模塊,專注 BPMN、CMMN、DMN 三大核心引擎。
- 更強兼容性:完美支持 Spring Boot 3.x,和最新的 Java 17 無縫對接。
- 更智能:內置動態流程定義、狀態監聽、郵件通知等功能,開箱即用。
2. 一行代碼的魔法:自動部署與默認配置
Flowable 有個 “懶人模式”:只要把流程定義文件(BPMN)放在 classpath:/processes 目錄下,Spring Boot 啟動時會自動部署。
舉個栗子:
創建一個 leave.bpmn 文件,畫個簡單的請假流程(員工提交→領導審批→結束),然后在代碼里只需要:
ProcessInstance instance = runtimeService.startProcessInstanceByKey("leave");就這一行,流程直接跑起來!Flowable 會自動解析 BPMN 文件,創建流程實例,分配任務,甚至生成數據庫表(沒錯,它會自動建表)。
這就像點外賣:你只需要下單(寫一行代碼),剩下的做菜、配送全交給外賣小哥(Flowable)。
二、實戰:用 Flowable 實現請假審批
1. 環境搭建:3 分鐘搞定依賴
首先,在 pom.xml 里加兩行依賴:
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>7.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>然后在 application.properties 里配置數據庫(這里用 H2 演示):
spring.datasource.url=jdbc:h2:mem:flowable;DB_CLOSE_DELAY=-1
spring.h2.console.enabled=true啟動項目,訪問 http://localhost:8080/h2-console,就能看到 Flowable 自動創建的 28 張表(別慌,大部分不用管)。
2. 流程設計:用流程圖代替代碼
打開 IDEA,安裝 actiBPM 插件,畫個請假流程:
- 開始事件 → 用戶任務(員工提交) → 排他網關 → 用戶任務(領導審批) → 結束事件
關鍵配置:
- 在 “員工提交” 任務里,設置 candidateGroups 為 employee(表示員工組可處理)。
- 在排他網關里,添加條件:${day > 3}(如果請假天數超過 3 天,進入下一級審批)。
- 在 “領導審批” 任務里,設置 candidateGroups 為 manager。
畫完保存到 src/main/resources/processes/leave.bpmn,Flowable 會自動部署。
3. 代碼實現:從提交到審批,絲滑體驗
(1)提交申請:啟動流程
@RestController
public class LeaveController {
@Autowired
private RuntimeService runtimeService;
@PostMapping("/apply")
public String applyLeave(@RequestParam Integer day) {
// 啟動流程,傳遞變量(請假天數)
runtimeService.startProcessInstanceByKey("leave", Collections.singletonMap("day", day));
return "申請已提交,等待領導審批";
}
}Flowable 做了什么?
- 解析 leave.bpmn,創建流程實例。
- 自動分配 “員工提交” 任務給 employee 組的用戶。
- 根據 day 變量判斷是否觸發二級審批。
(2)審批操作:處理任務
@Autowired
private TaskService taskService;
@PostMapping("/approve")
public String approveTask(@RequestParam String taskId, @RequestParam boolean approved) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
// 完成任務,傳遞審批結果
taskService.complete(taskId, Collections.singletonMap("approved", approved));
return approved ? "審批通過" : "審批駁回";
}Flowable 又做了什么?
- 找到對應的任務(根據 taskId)。
- 完成任務后,自動推進流程到下一個節點。
- 如果審批駁回,流程直接結束;如果通過,繼續下一步。
4. 查看狀態:流程走到哪了?
Flowable 提供了強大的查詢 API:
@Autowired
private HistoryService historyService;
@GetMapping("/status/{processInstanceId}")
public List<HistoricActivityInstance> getProcessStatus(@PathVariable String processInstanceId) {
return historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceStartTime().asc()
.list();
}返回的列表會告訴你流程經過了哪些節點,每個節點的處理時間,甚至審批人是誰。這就像快遞單號:你可以隨時查詢流程到哪了,有沒有被卡在某個環節。
三、進階玩法:讓審批流更智能
1. 動態流程:需求變了?不用改代碼!
有時候,流程需要根據業務規則動態調整。比如:
- 請假超過 3 天,需要 HR 審批。
- 報銷金額超過 1 萬,需要財務總監審批。
Flowable 支持動態修改流程定義,甚至在運行時替換流程。
舉個栗子:
創建一個 dynamic.bpmn,在排他網關里添加條件:
<conditionExpression xsi:type="tFormalExpression">
${amount > 10000}
</conditionExpression>然后在代碼里啟動流程時傳遞 amount 變量:
runtimeService.startProcessInstanceByKey("dynamic", Collections.singletonMap("amount", 15000));Flowable 會自動根據 amount 判斷是否觸發財務總監審批。這就像點菜:你可以根據預算(變量)選擇不同的菜品(流程分支)。
2. 狀態監聽:流程出事了?我來通知你!
Flowable 允許你在流程的關鍵節點(如任務創建、完成、流程結束)添加監聽器。
舉個栗子:
在 BPMN 文件里給 “領導審批” 任務添加一個監聽器:
<userTask id="managerApproval" name="領導審批">
<extensionElements>
<activiti:taskListener event="complete" class="com.example.listener.ApprovalListener"/>
</extensionElements>
</userTask>然后實現監聽器:
public class ApprovalListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
boolean approved = (boolean) delegateTask.getVariable("approved");
if (!approved) {
// 發送郵件通知員工
sendEmail(delegateTask.getVariable("employeeEmail"), "審批被駁回");
}
}
}這樣,當領導駁回申請時,員工會收到郵件通知。這就像智能門鎖:有人開門(任務完成),手機會收到提醒。
3. 郵件通知:審批結果自動發郵件
Flowable 內置郵件任務,只需在 BPMN 里拖一個 “服務任務”,配置郵件參數:
<serviceTask id="sendEmail" name="發送郵件" flowable:class="org.flowable.email.service.impl.EmailTaskExecutor">
<extensionElements>
<flowable:field name="to">${employeeEmail}</flowable:field>
<flowable:field name="subject">請假審批結果</flowable:field>
<flowable:field name="text">您的請假申請已 ${approved ? "通過" : "駁回"}</flowable:field>
</extensionElements>
</serviceTask>然后在 application.properties 里配置郵件服務器:
spring.mail.host=smtp.qq.com
spring.mail.username=your@qq.com
spring.mail.password=your-password
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true流程走到這個節點時,會自動發送郵件。這就像快遞簽收:包裹到了(流程結束),自動發個短信通知你。
四、深度解析:Flowable 的底層邏輯
1. 流程定義:BPMN 文件里的秘密
BPMN 是一種 XML 格式的流程定義語言,它定義了流程的節點、流向、條件等。
關鍵元素:
- StartEvent:流程起點。
- UserTask:需要人工處理的任務。
- ExclusiveGateway:條件分支(類似 if-else)。
- ServiceTask:自動執行的任務(如發送郵件)。
- EndEvent:流程終點。
Flowable 會解析 BPMN 文件,生成一個 ProcessDefinition 對象,包含流程的所有信息。
2. 流程實例:每個申請都是一個實例
當調用 startProcessInstanceByKey 時,Flowable 會創建一個 ProcessInstance,它是流程定義的 “運行時副本”。
每個流程實例有自己的變量、任務列表、執行路徑。
就像工廠流水線:流程定義是生產線圖紙,流程實例是正在生產的產品。
3. 任務分配:如何找到正確的審批人
Flowable 支持多種任務分配方式:
- 固定用戶:直接指定 assignee 為 zhangsan。
- 用戶組:設置 candidateGroups 為 manager,組內用戶都能處理。
- 表達式:用 EL 表達式動態計算審批人,如 ${employee.manager}。
舉個栗子:
在 BPMN 里給任務設置 assignee 為 ${managerId},啟動流程時傳遞 managerId 變量:
runtimeService.startProcessInstanceByKey("leave", Collections.singletonMap("managerId", "li4"));Flowable 會自動把任務分配給 li4。
五、避坑指南:新手常犯的 3 個錯誤
1. 流程定義文件放錯位置
Flowable 只掃描 classpath:/processes 目錄下的 BPMN 文件。如果放在其他地方(如 resources/bpmn),不會自動部署。
解決方案:檢查文件路徑,或者手動部署:
repositoryService.createDeployment()
.addClasspathResource("bpmn/leave.bpmn")
.deploy();2. 變量名與 BPMN 中的不一致
比如在 BPMN 里用 ${day > 3} 判斷,而啟動流程時傳遞的變量名是 days,會導致條件不生效。
解決方案:嚴格保持變量名一致,建議用 IDE 的插件校驗 BPMN 文件。
3. 數據庫連接問題
Flowable 默認使用 H2 內存數據庫,重啟后數據會丟失。如果需要持久化,換成 MySQL:
spring.datasource.url=jdbc:mysql://localhost:3306/flowable?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456六、高級技巧:讓審批流飛起來
1. 動態生成流程定義
如果流程需要根據用戶輸入動態變化(如審批節點數量),可以用代碼生成 BpmnModel:
BpmnModel bpmnModel = new BpmnModel();
Process process = bpmnModel.createProcess("dynamicProcess");
// 添加開始事件
StartEvent startEvent = new StartEvent();
startEvent.setId("start");
process.addFlowElement(startEvent);
// 添加用戶任務
UserTask task = new UserTask();
task.setId("task1");
task.setName("審批任務");
task.setAssignee("zhangsan");
process.addFlowElement(task);
// 添加結束事件
EndEvent endEvent = new EndEvent();
endEvent.setId("end");
process.addFlowElement(endEvent);
// 連線
process.addFlowElement(new SequenceFlow("start", "task1"));
process.addFlowElement(new SequenceFlow("task1", "end"));
// 部署流程
Deployment deployment = repositoryService.createDeployment()
.addBpmnModel("dynamic.bpmn", bpmnModel)
.deploy();這樣就能動態生成流程,無需手動畫 BPMN 文件。
2. 流程監控與調優
Flowable 提供了強大的監控 API:
// 查詢所有運行中的流程實例
runtimeService.createProcessInstanceQuery().list();
// 查詢任務積壓情況
taskService.createTaskQuery().taskAssignee("zhangsan").count();
// 查看數據庫性能
historyService.createHistoricProcessInstanceQuery().averageDuration();通過這些數據,可以優化流程設計,比如調整任務分配策略,減少審批延遲。
3. 與 Spring Security 集成
如果需要基于用戶權限控制審批,集成 Spring Security:
@Autowired
private SecurityContextHolder securityContextHolder;
@PostConstruct
public void init() {
FlowableSecurity.setAuthenticationProvider((Authentication authentication) -> {
return securityContextHolder.getContext().getAuthentication();
});
}然后在 BPMN 里用 candidateGroups 關聯 Spring Security 的角色。
七、總結
Flowable 用 “一行代碼” 實現了審批流的極簡開發,同時保留了高度的靈活性和擴展性。無論是簡單的請假流程,還是復雜的多級審批,Flowable 都能輕松應對。






























