前言
????????Flowable 的流程圖是 Flowable Modeler 或 Process Editor 中,使用拖拽和屬性面板基于 BPMN 2.0 元素(如任務、網關、事件、序列流等)渲染出的業務流程圖形界面?。
一、將圖形導出可查看的作用
① 可視化建模
????????幫助業務分析師和開發者共同設計復雜流程,免去了理解純 XML 定義的障礙?。
②?流程部署與運行
????????確保流程結構符合預期,再由 Flowable 引擎解析 XML 并生成執行計劃。
③?增強透明度與協作
????????可視化流程圖讓技術、業務和管理層共同站在“同一頁面”審視流程邏輯,減少溝通歧義并加快決策速度?。
④?標準化與合規審計
????????BPMN 強制流程設計者將隱含或未文檔化的業務規則以圖形化符號和屬性形式顯式化,有助于流程審計與合規檢查?。
⑤?培訓與知識沉淀
????????流程圖與文字說明協同構成易于理解的知識庫,新成員可通過圖示快速上手,減少培訓成本并提升團隊整體效率?。
二、后端:創建請求對象
這里的請求是表明需要查看具體哪一個部署流程定義
package com.ceair.entity.request;import lombok.Data;import java.io.Serial;
import java.io.Serializable;/*** @author wangbaohai* @ClassName QueryImageOrXmlReq* @description: 查詢部署流程定義的圖片或xml文件請求對象* @date 2025年04月22日* @version: 1.0.0*/
@Data
public class QueryImageOrXmlReq implements Serializable {@Serialprivate static final long serialVersionUID = 1L;/*** 流程定義ID*/private String processDefinitionId;}
三、后端:創建服務接口
/*** 查詢圖片信息的函數。* <p>* 根據傳入的查詢請求對象,返回對應的圖片信息字符串。** @param queryImageOrXmlReq 查詢請求對象,包含查詢圖片所需的相關參數。* 該對象的具體結構和內容需符合業務邏輯要求。* @return 返回一個字符串,表示查詢到的圖片信息。* 如果查詢失敗或無結果,返回值的具體含義需根據業務邏輯定義。*/
String queryImage(QueryImageOrXmlReq queryImageOrXmlReq);
四、后端:實現服務接口
此實現是本文重點部分:
????????該方法 queryImage(QueryImageOrXmlReq queryImageOrXmlReq) 的主要功能是根據前端傳入的流程定義 ID,調用流程引擎(如 Activiti 或 Flowable)持久化服務,獲取對應的流程圖資源,并將其以 Base64 編碼的字符串形式返回給調用方。核心流程如下:
參數校驗:保證輸入對象和流程定義 ID 有效;
查詢流程定義:通過 getById 方法確認流程定義是否存在;
讀取流程圖資源流:調用 repositoryService.getResourceAsStream 獲取流程圖文件的字節流;
轉換并編碼:將字節流讀入內存,通過 Base64 編碼輸出;
異常處理:對空流、IO 異常及其他未知異常分別捕獲并封裝業務異常。
/*** 查詢流程圖的Base64編碼字符串。** @param queryImageOrXmlReq 請求對象,包含查詢流程圖所需的參數。* - 不能為空。* - 必須包含有效的流程定義ID(processDefinitionId)。* @return 返回流程圖的Base64編碼字符串。* - 如果流程定義不存在或資源流為空,則拋出異常。* @throws IllegalArgumentException 如果請求對象為空或流程定義ID無效。* @throws BusinessException 如果流程定義不存在、資源流為空或發生IO異常。*/
@Override
public String queryImage(QueryImageOrXmlReq queryImageOrXmlReq) {// 參數校驗:確保請求對象不為空if (queryImageOrXmlReq == null) {log.error("獲取流程圖失敗,原因:請求對象不能為空");throw new IllegalArgumentException("獲取流程圖失敗,原因:請求對象不能為空");}String processDefinitionId = queryImageOrXmlReq.getProcessDefinitionId();// 參數校驗:確保流程定義ID不為空或空字符串if (processDefinitionId == null || processDefinitionId.trim().isEmpty()) {log.error("獲取流程圖失敗,原因:流程定義ID不能為空或空字符串");throw new IllegalArgumentException("獲取流程圖失敗,原因:流程定義ID不能為空或空字符串");}// 根據流程定義ID查詢流程定義ActReProcdef actReProcdef = getById(processDefinitionId);if (actReProcdef == null) {log.error("獲取流程圖失敗,原因:流程定義不存在,流程定義ID:{}", processDefinitionId);throw new BusinessException("獲取流程圖失敗,原因:流程定義不存在,流程定義ID:" + processDefinitionId);}// 獲取流程圖資源流try (InputStream imageStream = repositoryService.getResourceAsStream(actReProcdef.getDeploymentId(),actReProcdef.getDgrmResourceName())) {if (imageStream == null) {log.error("獲取流程圖失敗,原因:資源流為空,流程定義ID:{}", processDefinitionId);throw new BusinessException("獲取流程圖失敗,原因:資源流為空,流程定義ID:" + processDefinitionId);}// 將資源流內容讀取為字節數組并進行Base64編碼ByteArrayOutputStream outputStream = new ByteArrayOutputStream();byte[] buffer = new byte[4096];int bytesRead;while ((bytesRead = imageStream.read(buffer)) != -1) {outputStream.write(buffer, 0, bytesRead);}return Base64.getEncoder().encodeToString(outputStream.toByteArray());} catch (IOException e) {// 捕獲IO異常并記錄日志log.error("獲取流程圖失敗,原因:IO異常,流程定義ID:{}", processDefinitionId, e);throw new BusinessException("獲取流程圖失敗,原因:IO異常", e);} catch (Exception e) {// 捕獲其他未知異常并記錄日志log.error("獲取流程圖失敗,原因:未知異常,流程定義ID:{}", processDefinitionId, e);throw new BusinessException("獲取流程圖失敗,原因:未知異常", e);}
}
五、后端:創建功能接口
提供接口以供前端調用
// 使用Spring Security的注解進行權限控制,確保只有擁有特定權限的用戶才能訪問此方法
@PreAuthorize("hasAnyAuthority('/api/v1/actReProcdef/queryImage')")
// 定義參數對象的元數據,用于API文檔生成
@Parameter(name = "queryImageOrXmlReq", description = "查詢流程定義圖片請求對象", required = true)
// 定義操作的元數據,用于API文檔生成
@Operation(summary = "查詢流程定義圖片")
// 聲明這是一個POST請求的處理方法
@PostMapping("/queryImage")
public Result<String> queryImage(@RequestBody QueryImageOrXmlReq queryImageOrXmlReq) {try {// 調用服務層方法執行流程定義操作,傳入請求對象并獲取操作結果String image = actReProcdefService.queryImage(queryImageOrXmlReq);// 返回操作成功的響應結果return Result.success(image);} catch (Exception e) {// 捕獲異常,記錄詳細的錯誤日志,并返回包含失敗原因的響應結果log.error("查詢流程定義圖片失敗 具體原因為 : {}", e.getMessage());return Result.error("查詢流程定義圖片失敗,失敗原因:" + e.getMessage());}
}
六、前端:創建請求參數
與后臺接口保持一致
// 查詢流程圖或者流程XML請求對象
export interface QueryImageOrXmlReq {
? processDefinitionId: string // 流程定義ID
}
七、前端:封裝請求接口
調用后臺提供的接口
// 查詢流程圖
export function queryImage(data: QueryImageOrXmlReq) {return request.post<any>({url: '/pm-process/api/v1/actReProcdef/queryImage',data,})
}
八、前端:增加功能方法
// 定義響應式數據 showImage 表示是否顯示流程定義的圖片對話框
const showImage = ref(false)// 定義響應式數據 imageData 表示流程定義的圖片數據
const imageData = ref('')/*** 異步函數:用于顯示流程定義的圖片* @param data ActReProcdefVO 類型的對象,包含流程定義的相關信息*/
async function onShowImage(data: ActReProcdefVO) {try {// 組裝查詢參數,包括流程定義 IDconst param: QueryImageOrXmlReq = {processDefinitionId: data.id,}// 調用后端接口獲取流程定義的圖片數據const result: any = await queryImage(param)// 判斷查詢結果是否成功if (result.success && result.code === 200) {// 如果成功,則更新流程定義的圖片數據imageData.value = result.data// 打開圖片對話框showImage.value = true}else {// 提示操作失敗的錯誤提示信息ElMessage({message: `查詢失敗原因:${result.message}`,type: 'error',})}}catch (error) {// 捕獲異常并提取錯誤信息let errorMessage = '未知錯誤'if (error instanceof Error) {errorMessage = error.message}// 顯示操作失敗的錯誤提示信息ElMessage({message: `查詢失敗: ${errorMessage || '未知錯誤'}`,type: 'error',})}
}
九、前端:增加界面
<el-button v-hasButton="`btn.actReProcdef.queryImage`" type="primary" @click="onShowImage(scope.row)">
? 查看流程圖
</el-button>
此處需注意,直接使用img標簽的base64解碼,將圖片文件的字符串轉碼成圖片?
<!-- 流程圖展示彈出框 -->
<el-dialog v-model="showImage" title="流程圖展示" width="80%">
? <div class="image-container">
? ? <img :src="`data:image/jpeg;base64,${imageData}`" alt="流程圖">
? </div>
</el-dialog>
.image-container {
? display: flex;
? justify-content: center;
? align-items: center;
? height: 100%;
}
.image-container img {
? max-width: 100%;
? max-height: 100%;
}
十、添加按鈕&分配權限
這一步是添加按鈕
這一步是把按鈕權限給到當前操作員的角色【超級管理員】
十一、結果查詢
十二、后記?
本篇文章的前后端倉庫地址請查詢專欄第一篇文章,后續打算把xml和流程圖片展示出來
本文的后端分支是 process-7
本文的前端分支是 process-9