Activiti 工作流引擎運行時生成的流程圖(BPMN 圖形)需在前端展示、高亮當前節點、支持審批軌跡追溯。本文介紹流程圖獲取的核心 API 與實現方案。
@Autowired
private RepositoryService repositoryService;
public InputStream getProcessDiagram(String processDefinitionId) {
// 獲取流程定義圖片資源名
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
.processDefinitionId(processDefinitionId)
.singleResult();
String diagramResourceName = pd.getDiagramResourceName();
if (diagramResourceName == null) {
return null; // 無圖形定義
}
// 返回圖片輸入流
return repositoryService.getResourceAsStream(pd.getDeploymentId(), diagramResourceName);
}
@Autowired
private RuntimeService runtimeService;
public Map> getHighlights(String processInstanceId) {
// 獲取當前活動的執行實例
List executions = runtimeService.createExecutionQuery()
.processInstanceId(processInstanceId)
.list();
Map> highlights = new HashMap<>();
for (Execution exe : executions) {
String activityId = exe.getActivityId();
if (activityId != null) {
// 從 BPMN 模型解析座標
BpmnModel bpmnModel = repositoryService.getBpmnModel(exe.getProcessDefinitionId());
FlowElement element = bpmnModel.getFlowElement(activityId);
if (element instanceof GraphicInfo) {
GraphicInfo gi = (GraphicInfo) element;
List coords = new ArrayList<>();
coords.add(new int[]{(int)gi.getX(), (int)gi.getY(),
(int)(gi.getX() + gi.getWidth()), (int)(gi.getY() + gi.getHeight())});
highlights.put(activityId, coords);
}
}
}
return highlights;
}
@GetMapping("/process/diagram/{processInstanceId}")
public void generateDiagram(@PathVariable String processInstanceId, HttpServletResponse response) {
// 1. 獲取原始圖片流
InputStream imageStream = getProcessDiagram(processInstanceId);
// 2. 獲取高亮座標
Map> highlights = getHighlights(processInstanceId);
// 3. 使用 Graphics2D 繪製高亮矩形
BufferedImage image = ImageIO.read(imageStream);
Graphics2D g2d = image.createGraphics();
g2d.setColor(Color.RED);
g2d.setStroke(new BasicStroke(3));
for (List coords : highlights.values()) {
for (int[] c : coords) {
g2d.drawRect(c[0], c[1], c[2] - c[0], c[3] - c[1]);
}
}
g2d.dispose();
// 4. 輸出圖片
response.setContentType("image/png");
ImageIO.write(image, "png", response.getOutputStream());
}
後端提供:
/api/process/image/{processDefinitionId}/api/process/highlights/{processInstanceId}前端使用 Canvas 或 SVG 疊加繪製,優點:
// 獲取 BPMN 模型
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
// 遍歷所有流程元素獲取座標
Collection flowElements = bpmnModel.getMainProcess().getFlowElements();
for (FlowElement element : flowElements) {
if (element instanceof GraphicInfo) {
GraphicInfo gi = (GraphicInfo) element;
// gi.getX(), gi.getY(), gi.getWidth(), gi.getHeight()
// 元素 ID: element.getId()
// 元素名稱: element.getName()
}
}
// 連線座標(SequenceFlow)
for (SequenceFlow flow : bpmnModel.getMainProcess().getSequenceFlows()) {
List waypoints = flow.getWaypoints();
// waypoints 包含折線轉折點座標
}
| 接口 | 方法 | 說明 |
|---|---|---|
| /api/process/image/{processDefinitionId} | GET | 獲取流程定義原始圖片 |
| /api/process/highlights/{processInstanceId} | GET | 獲取當前節點高亮座標 |
| /api/process/history/{processInstanceId} | GET | 獲取歷史節點軌跡座標 |
| /api/process/bpmn/{processDefinitionId} | GET | 獲取 BPMN XML 源文件 |
| 問題 | 原因 | 解決 |
|---|---|---|
| 圖片資源不存在 | 部署時未包含 .png/.jpg 圖形文件 | 建模工具導出時勾選「生成圖片」、或手動添加部署資源 |
| 座標偏移/不準確 | 圖片縮放比例與座標不匹配 | 前端記錄圖片顯示尺寸,按比例換算座標 |
| 子流程/多實例座標缺失 | GraphicInfo 僅在主流程層級 | 遞歸遍歷子流程 bpmnModel.getProcesses() |
| 高併發下圖片生成慢 | Graphics2D 繪製開銷大 | 改用前端渲染、或緩存生成的高亮圖片 |
Activiti 流程圖獲取核心在於 RepositoryService 讀取部署資源與 BpmnModel 解析圖形座標。現代架構推薦「後端提供數據 + 前端 Canvas/SVG 渲染」模式,實現高性能、可交互、易擴展的流程可視化能力。