优化flowable流程和节点状态查询

This commit is contained in:
2025-12-01 20:00:00 +08:00
parent fc0760b8d9
commit f4721f8150
7 changed files with 92 additions and 109 deletions

View File

@@ -9,12 +9,11 @@ import java.util.Date;
public class ProcessInstanceInfo {
private String processInstanceId;
private String processDefinitionId;
private String businessKey;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date startTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date endTime;
private Long durationInMillis;
private String durationFormatted;
private String status; // "running" 或 "completed"
private String status; // "pending""running" 或 "completed"
}

View File

@@ -76,10 +76,10 @@ public class FlowableClientFeignClientImpl implements IFlowableFeignClient {
}
@Override
public SdmResponse<ProcessInstanceDetailResponse> getProcessAndNodeDetailByInstanceId(String processInstanceId) {
public SdmResponse<ProcessInstanceDetailResponse> getProcessAndNodeDetailByInstanceId(String processDefinitionId,String processInstanceId) {
SdmResponse<ProcessInstanceDetailResponse> response;
try {
response = flowableFeignClient.getProcessAndNodeDetailByInstanceId(processInstanceId);
response = flowableFeignClient.getProcessAndNodeDetailByInstanceId(processDefinitionId,processInstanceId);
log.info("查询流程状态以及节点状态:"+ response);
return response;
} catch (Exception e) {
@@ -87,17 +87,4 @@ public class FlowableClientFeignClientImpl implements IFlowableFeignClient {
return SdmResponse.failed("查询流程状态以及节点状态失败");
}
}
@Override
public SdmResponse<List<NodeStructureInfo>> listNodesByProcessDefinitionId(String processDefinitionId) {
SdmResponse<List<NodeStructureInfo>> response;
try {
response = flowableFeignClient.listNodesByProcessDefinitionId(processDefinitionId);
log.info("获取流程定义节点详细信息:"+ response);
return response;
} catch (Exception e) {
log.error("获取流程定义节点详细信息失败", e);
return SdmResponse.failed("获取流程定义节点详细信息失败");
}
}
}

View File

@@ -32,9 +32,5 @@ public interface IFlowableFeignClient {
SdmResponse updateNodeParamProcessInstanceId(@RequestParam String processDefinitionId, @RequestParam String processInstanceId);
@GetMapping("/process/getProcessAndNodeDetailByInstanceId")
SdmResponse<ProcessInstanceDetailResponse> getProcessAndNodeDetailByInstanceId(@RequestParam String processInstanceId);
@GetMapping("/listNodesByProcessDefinitionId")
SdmResponse<List<NodeStructureInfo>> listNodesByProcessDefinitionId(@RequestParam String processDefinitionId);
SdmResponse<ProcessInstanceDetailResponse> getProcessAndNodeDetailByInstanceId(@RequestParam String processDefinitionId,@RequestParam(required = false) String processInstanceId);
}

View File

@@ -128,7 +128,9 @@ public class ProcessController implements IFlowableFeignClient {
}
/**
* 根据流程实例 ID 查询流程状态以及节点状态
* 查询流程实例及所有节点的详细状态(返回结构化 DTO
* 如果只传了processDefinitionId根据流程定义返回流程基本信息和节点信息
* 如果还传了processInstanceId再封装流程状态和节点状态
*/
@GetMapping("/getProcessAndNodeDetailByInstanceId")
public SdmResponse<ProcessInstanceDetailResponse> getProcessAndNodeDetailByInstanceId(@RequestParam String processDefinitionId,@RequestParam(required = false) String processInstanceId) {

View File

@@ -4,7 +4,6 @@ import com.sdm.common.common.SdmResponse;
import com.sdm.flowable.constants.FlowableConfig;
import com.sdm.flowable.delegate.UniversalDelegate;
import com.sdm.common.entity.flowable.dto.NodeDetailInfo;
import com.sdm.common.entity.flowable.dto.NodeStructureInfo;
import com.sdm.common.entity.flowable.dto.ProcessInstanceInfo;
import com.sdm.common.entity.flowable.dto.ProcessDefinitionDTO;
import com.sdm.flowable.dto.req.AsyncCallbackRequest;
@@ -140,12 +139,69 @@ public class ProcessService {
/**
* 查询流程实例及所有节点的详细状态(返回结构化 DTO
* 如果只传了processDefinitionId根据流程定义返回流程基本信息和节点信息
* 如果还传了processInstanceId再封装流程状态和节点状态
*/
public SdmResponse<ProcessInstanceDetailResponse> getProcessAndNodeDetailByInstanceId(String processDefinitionId,String processInstanceId) {
ProcessInstanceInfo processInfo = buildProcessInstanceInfo(processInstanceId);
List<NodeDetailInfo> nodes = buildNodeDetails(processInstanceId, processInfo.getProcessDefinitionId());
public SdmResponse<ProcessInstanceDetailResponse> getProcessAndNodeDetailByInstanceId(String processDefinitionId, String processInstanceId) {
ProcessInstanceDetailResponse response = new ProcessInstanceDetailResponse();
// 构建基础流程信息
ProcessInstanceInfo processInfo = new ProcessInstanceInfo();
processInfo.setProcessDefinitionId(processDefinitionId);
// 获取流程定义中的节点结构信息
List<FlowNode> orderedNodes = getOrderedFlowNodes(processDefinitionId);
List<NodeDetailInfo> nodes = orderedNodes.stream()
.map(this::buildNodeDetailInfoFromFlowNode) // 直接构建NodeDetailInfo
.peek(detail -> {
Map<String, Object> params = processNodeParamService.getParam(processDefinitionId, detail.getId());
detail.setUserParam(params);
})
.collect(Collectors.toList());
if (processInstanceId != null && !processInstanceId.isEmpty()) {
// 如果提供了流程实例ID则补充完整状态信息
processInfo = buildProcessInstanceInfo(processInstanceId);
// 补充节点状态信息
List<HistoricActivityInstance> historicActivities = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.list();
Map<String, HistoricActivityInstance> activityMap = historicActivities.stream()
.collect(Collectors.toMap(
HistoricActivityInstance::getActivityId,
Function.identity(),
(a, b) -> a
));
List<String> activeActivityIds = isProcessRunning(processInstanceId)
? runtimeService.getActiveActivityIds(processInstanceId)
: Collections.emptyList();
// 更新节点状态信息
for (NodeDetailInfo node : nodes) {
String nodeId = node.getId();
HistoricActivityInstance historicActivity = activityMap.get(nodeId);
boolean isActive = activeActivityIds.contains(nodeId);
boolean isFinished = historicActivity != null && historicActivity.getEndTime() != null;
node.setStatus(isFinished ? "finished" : (isActive ? "active" : "pending"));
if (historicActivity != null) {
node.setStartTime(historicActivity.getStartTime());
if (isFinished) {
node.setEndTime(historicActivity.getEndTime());
node.setDurationInMillis(historicActivity.getDurationInMillis());
if (historicActivity.getDurationInMillis() != null) {
node.setDurationFormatted(formatDuration(historicActivity.getDurationInMillis()));
}
}
}
}
}
response.setProcessInfo(processInfo);
response.setNodes(nodes);
return SdmResponse.success(response);
@@ -168,7 +224,6 @@ public class ProcessService {
ProcessInstanceInfo info = new ProcessInstanceInfo();
info.setProcessInstanceId(historicInstance.getId());
info.setProcessDefinitionId(historicInstance.getProcessDefinitionId());
info.setBusinessKey(historicInstance.getBusinessKey());
info.setStartTime(historicInstance.getStartTime());
info.setEndTime(historicInstance.getEndTime()); // 可能为 null
@@ -183,31 +238,7 @@ public class ProcessService {
return info;
}
//构建节点列表
private List<NodeDetailInfo> buildNodeDetails(String processInstanceId, String processDefinitionId) {
List<FlowNode> orderedNodes = getOrderedFlowNodes(processDefinitionId);
// 查询运行时 & 历史数据
List<HistoricActivityInstance> historicActivities = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.list();
Map<String, HistoricActivityInstance> activityMap = historicActivities.stream()
.collect(Collectors.toMap(
HistoricActivityInstance::getActivityId,
Function.identity(),
(a, b) -> a
));
List<String> activeActivityIds = isProcessRunning(processInstanceId)
? runtimeService.getActiveActivityIds(processInstanceId)
: Collections.emptyList();
// 按有序节点构建详情
return orderedNodes.stream()
.map(node -> buildNodeDetailInfo(node,processDefinitionId, activityMap, activeActivityIds))
.collect(Collectors.toList());
}
/**
* 根据流程定义 ID按流程执行顺序BFS返回所有可达的 FlowNode
@@ -264,55 +295,17 @@ public class ProcessService {
.count() > 0;
}
// --- 构建单个节点详情(返回 NodeDetailInfo---
private NodeDetailInfo buildNodeDetailInfo(
FlowNode node,
String processDefinitionId,
Map<String, HistoricActivityInstance> activityMap,
List<String> activeActivityIds) {
String nodeId = node.getId();
// 先构建静态结构
NodeStructureInfo base = buildNodeStructureInfo(node);
Map<String, Object> params = processNodeParamService.getParam(processDefinitionId, nodeId);
base.setUserParam(params);
// 再填充动态信息
/**
* 从FlowNode构建NodeDetailInfo基础信息(不含状态)
*/
private NodeDetailInfo buildNodeDetailInfoFromFlowNode(FlowNode node) {
NodeDetailInfo detail = new NodeDetailInfo();
detail.setId(base.getId());
detail.setName(base.getName());
detail.setType(base.getType());
detail.setNextNodeIds(base.getNextNodeIds());
detail.setExecuteConfig(base.getExecuteConfig());
// 动态状态逻辑
HistoricActivityInstance historicActivity = activityMap.get(nodeId);
boolean isActive = activeActivityIds.contains(nodeId);
boolean isFinished = historicActivity != null && historicActivity.getEndTime() != null;
detail.setStatus(isFinished ? "finished" : (isActive ? "active" : "pending"));
if (historicActivity != null) {
detail.setStartTime(historicActivity.getStartTime());
if (isFinished) {
detail.setEndTime(historicActivity.getEndTime());
detail.setDurationInMillis(historicActivity.getDurationInMillis());
if (historicActivity.getDurationInMillis() != null) {
detail.setDurationFormatted(formatDuration(historicActivity.getDurationInMillis()));
}
}
}
return detail;
}
private NodeStructureInfo buildNodeStructureInfo(FlowNode node) {
NodeStructureInfo info = new NodeStructureInfo();
info.setId(node.getId());
info.setName(node.getName() != null ? node.getName() : "");
info.setType(node.getClass().getSimpleName());
detail.setId(node.getId());
detail.setName(node.getName() != null ? node.getName() : "");
detail.setType(node.getClass().getSimpleName());
// 后续节点
info.setNextNodeIds(
detail.setNextNodeIds(
node.getOutgoingFlows().stream()
.map(SequenceFlow::getTargetRef)
.collect(Collectors.toList())
@@ -322,14 +315,13 @@ public class ProcessService {
if (node.getExtensionElements() != null) {
List<ExtensionElement> extList = node.getExtensionElements().get(FlowableConfig.EXECUTECONFIG);
if (extList != null && !extList.isEmpty()) {
info.setExecuteConfig(extList.get(0).getElementText());
detail.setExecuteConfig(extList.get(0).getElementText());
}
}
return info;
return detail;
}
// --- 工具方法:格式化耗时(毫秒 → 可读字符串)---
private String formatDuration(long millis) {
long seconds = millis / 1000;

View File

@@ -16,5 +16,5 @@ import java.util.Map;
public interface IProcessNodeParamService extends IService<ProcessNodeParam> {
void saveParamByProcessDefinitionId(String processDefinitionId, String nodeId, Map<String, Object> params);
void updateNodeParamProcessInstanceId(String processInstanceId, String processDefinitionId);
Map<String, Object> getParam(String procInstId, String nodeId);
Map<String, Object> getParam(String processDefinitionId, String nodeId);
}

View File

@@ -7,11 +7,13 @@ import com.sdm.flowable.entity.ProcessNodeParam;
import com.sdm.flowable.dao.ProcessNodeParamMapper;
import com.sdm.flowable.service.IProcessNodeParamService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.ObjectUtils;
import org.flowable.engine.RuntimeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@@ -54,10 +56,15 @@ public class ProcessNodeParamServiceImpl extends ServiceImpl<ProcessNodeParamMap
// 流程启动后更新流程实例ID
public void updateNodeParamProcessInstanceId(String processInstanceId, String processDefinitionId) {
ProcessNodeParam param = this.lambdaQuery().eq(ProcessNodeParam::getProcessDefinitionId, processDefinitionId).one();
if (param != null) {
param.setProcessInstanceId(processInstanceId);
this.updateById(param);
List<ProcessNodeParam> processNodeParams = this.lambdaQuery().eq(ProcessNodeParam::getProcessDefinitionId, processDefinitionId).list();
if (ObjectUtils.isNotEmpty(processNodeParams)) {
processNodeParams.forEach(param -> {
this.lambdaUpdate()
.eq(ProcessNodeParam::getId, param.getId())
.set(ProcessNodeParam::getProcessInstanceId, processInstanceId)
.update();
});
}
}