diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/config/FlowableConfig.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/config/FlowableConfig.java index 9a0ff148..957f254e 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/config/FlowableConfig.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/config/FlowableConfig.java @@ -1,12 +1,11 @@ package com.qqchen.deploy.backend.workflow.config; -import com.qqchen.deploy.backend.workflow.listener.FlowableEventDispatcher; +import com.qqchen.deploy.backend.workflow.listener.event.FlowableEventDispatcher; import jakarta.annotation.Resource; import org.flowable.spring.SpringProcessEngineConfiguration; import org.flowable.spring.boot.EngineConfigurationConfigurer; import org.springframework.context.annotation.Configuration; -import java.util.Arrays; import java.util.Collections; /** diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/WorkflowNodeDefinitionDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/WorkflowNodeDefinitionDTO.java index 887b184a..2a9e454f 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/WorkflowNodeDefinitionDTO.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/dto/WorkflowNodeDefinitionDTO.java @@ -32,7 +32,7 @@ public class WorkflowNodeDefinitionDTO extends BaseDTO { @Schema(description = "X6图形配置JSON") private JsonNode graphConfig; - + @Schema(description = "排序号") private Integer orderNum; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/FlowableEventDispatcher.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/FlowableEventDispatcher.java similarity index 79% rename from backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/FlowableEventDispatcher.java rename to backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/FlowableEventDispatcher.java index 3b4a4752..f0c19faa 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/FlowableEventDispatcher.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/FlowableEventDispatcher.java @@ -1,12 +1,10 @@ -package com.qqchen.deploy.backend.workflow.listener; +package com.qqchen.deploy.backend.workflow.listener.event; -import com.qqchen.deploy.backend.workflow.listener.handler.IFlowableEventHandler; +import com.qqchen.deploy.backend.workflow.listener.event.handler.IFlowableEventHandler; import lombok.extern.slf4j.Slf4j; -import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent; import org.flowable.common.engine.api.delegate.event.FlowableEvent; import org.flowable.common.engine.api.delegate.event.FlowableEventListener; import org.flowable.engine.RuntimeService; -import org.flowable.job.service.impl.persistence.entity.JobEntityImpl; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @@ -14,8 +12,6 @@ import jakarta.annotation.Resource; import java.util.List; -import static com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants.ASYNC_CONTINUATION; - @Slf4j @Component public class FlowableEventDispatcher implements FlowableEventListener { diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ActivityEventHandler.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/handler/ActivityEventHandler.java similarity index 81% rename from backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ActivityEventHandler.java rename to backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/handler/ActivityEventHandler.java index e9868422..8e6d9ca0 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ActivityEventHandler.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/handler/ActivityEventHandler.java @@ -1,4 +1,4 @@ -package com.qqchen.deploy.backend.workflow.listener.handler; +package com.qqchen.deploy.backend.workflow.listener.event.handler; import com.qqchen.deploy.backend.workflow.enums.WorkflowNodeInstanceStatusEnums; import com.qqchen.deploy.backend.workflow.event.WorkflowNodeInstanceStatusChangeEvent; @@ -13,7 +13,6 @@ import jakarta.annotation.Resource; import java.time.LocalDateTime; import java.util.Arrays; -import java.util.Collections; import java.util.List; import static com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants.BOUNDARY_EVENT_ERROR_PREFIX; @@ -38,8 +37,6 @@ public class ActivityEventHandler implements IFlowableEventHandler { if (!(event instanceof FlowableActivityEvent activityEvent)) { return; } -// log.info("Processing Flowable event: {}, id: {}, name:{}", eventType, activityEvent.getActivityId(), activityEvent.getActivityName()); - List ignoredList = Arrays.asList(BOUNDARY_EVENT_ERROR_PREFIX, END_EVENT_ERROR_PREFIX); boolean ignored = ignoredList.stream().anyMatch(v -> activityEvent.getActivityId().contains(v)); @@ -56,8 +53,7 @@ public class ActivityEventHandler implements IFlowableEventHandler { .nodeName(StringUtils.isEmpty(activityEvent.getActivityName()) ? activityEvent.getActivityId() : activityEvent.getActivityName()) .nodeType(activityEvent.getActivityType()) .status(status) - .startTime(status == WorkflowNodeInstanceStatusEnums.RUNNING ? LocalDateTime.now() : null) - .endTime(status.isFinalState() ? LocalDateTime.now() : null) + .endTime(LocalDateTime.now()) .build() ); } @@ -65,8 +61,6 @@ public class ActivityEventHandler implements IFlowableEventHandler { private WorkflowNodeInstanceStatusEnums convertToNodeStatus(String eventType) { return switch (eventType) { - case "ACTIVITY_STARTED" -> WorkflowNodeInstanceStatusEnums.RUNNING; - case "ACTIVITY_COMPLETED" -> WorkflowNodeInstanceStatusEnums.COMPLETED; case "ACTIVITY_CANCELLED" -> WorkflowNodeInstanceStatusEnums.TERMINATED; case "ACTIVITY_ERROR_RECEIVED" -> WorkflowNodeInstanceStatusEnums.FAILED; default -> null; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/IFlowableEventHandler.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/handler/IFlowableEventHandler.java similarity index 84% rename from backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/IFlowableEventHandler.java rename to backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/handler/IFlowableEventHandler.java index c5ea01b8..5531a4d1 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/IFlowableEventHandler.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/handler/IFlowableEventHandler.java @@ -1,9 +1,7 @@ -package com.qqchen.deploy.backend.workflow.listener.handler; +package com.qqchen.deploy.backend.workflow.listener.event.handler; import org.flowable.common.engine.api.delegate.event.FlowableEvent; -import java.util.List; - /** * Flowable事件处理器接口 */ diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/JobEventHandler.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/handler/JobEventHandler.java similarity index 83% rename from backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/JobEventHandler.java rename to backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/handler/JobEventHandler.java index 79283f15..0500f837 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/JobEventHandler.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/handler/JobEventHandler.java @@ -1,10 +1,7 @@ -package com.qqchen.deploy.backend.workflow.listener.handler; +package com.qqchen.deploy.backend.workflow.listener.event.handler; -import cn.hutool.core.date.DateUtil; -import cn.hutool.json.JSON; import cn.hutool.json.JSONUtil; import com.qqchen.deploy.backend.workflow.enums.WorkflowNodeInstanceStatusEnums; -import com.qqchen.deploy.backend.workflow.event.WorkflowNodeInstanceStatusChangeEvent; import lombok.extern.slf4j.Slf4j; import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent; import org.flowable.common.engine.api.delegate.event.FlowableEvent; @@ -14,10 +11,6 @@ import org.springframework.stereotype.Component; import jakarta.annotation.Resource; -import java.time.LocalDateTime; -import java.util.Collections; -import java.util.List; - @Slf4j @Component public class JobEventHandler implements IFlowableEventHandler { @@ -36,9 +29,9 @@ public class JobEventHandler implements IFlowableEventHandler { if (!(event instanceof FlowableEngineEntityEvent entityEvent)) { return; } - log.info("Processing job event: {}, jobType: {}", eventType, entityEvent.getType()); + //log.info("Processing job event: {}, jobType: {}", eventType, entityEvent.getType()); JobEntityImpl job = (JobEntityImpl) entityEvent.getEntity(); - log.info("Processing job event: {}", JSONUtil.toJsonStr(job)); + //log.info("Processing job event: {}", JSONUtil.toJsonStr(job)); WorkflowNodeInstanceStatusEnums status = convertToNodeStatus(eventType); if (status != null) { // publisher.publishEvent(WorkflowNodeInstanceStatusChangeEvent.builder() diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ProcessEventHandler.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/handler/ProcessEventHandler.java similarity index 95% rename from backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ProcessEventHandler.java rename to backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/handler/ProcessEventHandler.java index f22c6798..666593da 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/handler/ProcessEventHandler.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/event/handler/ProcessEventHandler.java @@ -1,4 +1,4 @@ -package com.qqchen.deploy.backend.workflow.listener.handler; +package com.qqchen.deploy.backend.workflow.listener.event.handler; import cn.hutool.core.date.DateUtil; import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums; @@ -14,9 +14,6 @@ import org.springframework.stereotype.Component; import jakarta.annotation.Resource; -import java.util.Collections; -import java.util.List; - @Slf4j @Component public class ProcessEventHandler implements IFlowableEventHandler { diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/execution/GlobalExecutionListener.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/execution/GlobalExecutionListener.java new file mode 100644 index 00000000..5f50ccac --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/listener/execution/GlobalExecutionListener.java @@ -0,0 +1,62 @@ +package com.qqchen.deploy.backend.workflow.listener.execution; + +import com.qqchen.deploy.backend.workflow.enums.WorkflowNodeInstanceStatusEnums; +import com.qqchen.deploy.backend.workflow.event.WorkflowNodeInstanceStatusChangeEvent; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.ExecutionListener; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; + +import jakarta.annotation.Resource; + +import java.time.LocalDateTime; + +@Slf4j +@Component("globalNodeExecutionListener") +public class GlobalExecutionListener implements ExecutionListener { + + @Resource + private ApplicationEventPublisher eventPublisher; + + @Override + public void notify(DelegateExecution execution) { + // 获取当前节点信息 + FlowElement flowElement = execution.getCurrentFlowElement(); + String eventName = execution.getEventName(); + String processInstanceId = execution.getProcessInstanceId(); + String executionId = execution.getId(); + String nodeId = execution.getCurrentActivityId(); + String nodeName = flowElement.getName(); + String nodeType = flowElement.getClass().getSimpleName(); + log.debug("Node execution event: {}, processInstanceId: {}, nodeId: {}, nodeType: {}, nodeName:{}", eventName, processInstanceId, nodeId, nodeType, nodeName); + LocalDateTime now = LocalDateTime.now(); + WorkflowNodeInstanceStatusEnums status = null; + LocalDateTime startTime = null; + LocalDateTime endTime = null; + switch (eventName) { + case ExecutionListener.EVENTNAME_START: + status = WorkflowNodeInstanceStatusEnums.RUNNING; + startTime = now; + break; + case ExecutionListener.EVENTNAME_END: + status = WorkflowNodeInstanceStatusEnums.COMPLETED; + endTime = now; + break; + default: + log.warn("Unexpected event type: {}", eventName); + return; + } + eventPublisher.publishEvent(WorkflowNodeInstanceStatusChangeEvent.builder() + .processInstanceId(processInstanceId) + .executionId(executionId) + .nodeId(nodeId) + .nodeName(nodeName) + .nodeType(nodeType) + .status(status) + .startTime(startTime) + .endTime(endTime) + .build()); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/BpmnConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/BpmnConverter.java index 2d377df7..84280c5b 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/BpmnConverter.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/workflow/util/BpmnConverter.java @@ -12,6 +12,7 @@ import org.springframework.stereotype.Component; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -118,26 +119,37 @@ public class BpmnConverter { * @param process 当前流程 */ private void configureFlowElement(FlowElement element, WorkflowDefinitionNode node, Process process) { + // 为所有节点添加执行监听器 + Map> extensionElements = new HashMap<>(); + List executionListeners = new ArrayList<>(); + + // 开始事件监听器 + ExtensionElement startListener = createExecutionListener("start", "${globalNodeExecutionListener}"); + executionListeners.add(startListener); + + // 结束事件监听器 + ExtensionElement endListener = createExecutionListener("end", "${globalNodeExecutionListener}"); + executionListeners.add(endListener); + + extensionElements.put("executionListener", executionListeners); + + // 根据节点类型进行特定配置 if (element instanceof ServiceTask) { ServiceTask serviceTask = (ServiceTask) element; // 设置委托表达式 String delegate = (String) node.getConfig().get("delegate"); -// serviceTask.setImplementationType("class"); -// serviceTask.setImplementation("com.qqchen.deploy.backend.workflow.delegate.ShellTaskDelegate"); serviceTask.setImplementationType("delegateExpression"); serviceTask.setImplementation(delegate); -// serviceTask.setAsynchronous(false); // 设置为异步执行 - // 设置失败时不重试 - ExtensionElement failedJobRetryTimeCycle = new ExtensionElement(); - failedJobRetryTimeCycle.setName("failedJobRetryTimeCycle"); - failedJobRetryTimeCycle.setNamespace("http://flowable.org/bpmn"); - failedJobRetryTimeCycle.setNamespacePrefix("flowable"); - failedJobRetryTimeCycle.setElementText("R0/PT1H"); // 设置为0次重试 + // 配置重试策略 + ExtensionElement retryConfig = new ExtensionElement(); + retryConfig.setName("failedJobRetryTimeCycle"); + retryConfig.setNamespace("http://flowable.org/bpmn"); + retryConfig.setNamespacePrefix("flowable"); + retryConfig.setElementText("R0/PT1H"); // 设置为0次重试 - Map> extensionElements = new HashMap<>(); List retryElements = new ArrayList<>(); - retryElements.add(failedJobRetryTimeCycle); + retryElements.add(retryConfig); extensionElements.put("failedJobRetryTimeCycle", retryElements); // 添加字段注入 @@ -150,16 +162,53 @@ public class BpmnConverter { fieldExtensions.add(fieldExtension); } }); + + // 设置到服务任务 serviceTask.setFieldExtensions(fieldExtensions); serviceTask.setExtensionElements(extensionElements); // 添加错误边界事件 addErrorBoundaryEventHandler(process, serviceTask); + } else if (element instanceof StartEvent || element instanceof EndEvent) { + // 为开始节点和结束节点设置监听器 + element.setExtensionElements(extensionElements); } } /** - * 为服务任务添加错误边界事件和错误结束事件 + * 创建执行监听器扩展元素 + * + * @param event 事件类型(start/end) + * @param delegateExpression 委托表达式 + * @return 配置好的监听器扩展元素 + */ + private ExtensionElement createExecutionListener(String event, String delegateExpression) { + ExtensionElement listener = new ExtensionElement(); + listener.setName("executionListener"); + listener.setNamespace("http://flowable.org/bpmn"); + listener.setNamespacePrefix("flowable"); + + // 设置事件属性 + ExtensionAttribute eventAttr = new ExtensionAttribute(); + eventAttr.setName("event"); + eventAttr.setValue(event); + + // 设置委托表达式属性 + ExtensionAttribute delegateAttr = new ExtensionAttribute(); + delegateAttr.setName("delegateExpression"); + delegateAttr.setValue(delegateExpression); + + // 添加属性到监听器 + Map> attributes = new HashMap<>(); + attributes.put("event", Collections.singletonList(eventAttr)); + attributes.put("delegateExpression", Collections.singletonList(delegateAttr)); + listener.setAttributes(attributes); + + return listener; + } + + /** + * 为服务任务添加错误边界事件和错误结���事件 * 当服务任务执行失败时,会触发错误边界事件,并流转到错误结束事件 * * @param process BPMN流程定义