feat(flow): 添加流程执行模块编码支持实现事件精确分发

- 在AimaAlarm实体类中添加详细的字段注释和类文档说明
- 为AimaPhone实体类的各个属性添加中文注释说明
- 在AimaFlowExecutionListener中实现getModuleCode方法返回AIMA模块编码
- 在InspectionFlowExecutionListener中实现getModuleCode方法返回INSPECTION模块编码
- 修改AimaTaskInstanceServiceImpl和InspectionTaskInstanceServiceImpl传入模块编码参数
- 在FlowExecutionEvent中新增moduleCode字段用于模块识别
- 在FlowBeforeInterceptor和FlowAfterInterceptor中传递模块编码到事件对象
- 在FlowExecutionEventPublisher中实现基于模块编码的事件分发过滤机制
- 创建FlowExecutionModuleCodes常量类统一管理模块编码值
- 在FlowTaskRuntimeEntry中注册任务上下文时包含模块编码信息
- 在TaskContext和TaskInstHolder中增加对模块编码的处理和传递逻辑
This commit is contained in:
lixiaolong 2026-07-13 10:41:13 +08:00
parent 736c510270
commit 659073db03
16 changed files with 206 additions and 12 deletions

View File

@ -14,8 +14,11 @@ import com.cmvr.common.core.domain.BaseEntity;
import java.util.Date; import java.util.Date;
/** /**
* 爱玛告警管理对象 aima_alarm * 爱玛告警实体
* * <p>
* 用于描述任务执行过程中产生的告警信息包含任务设备车辆用例
* 告警详情以及处理结果等数据
*
* @author cmvr-iot * @author cmvr-iot
* @since 2026-06-22 * @since 2026-06-22
*/ */
@ -26,92 +29,115 @@ import java.util.Date;
@ApiModel("爱玛告警管理") @ApiModel("爱玛告警管理")
public class AimaAlarm extends BaseEntity public class AimaAlarm extends BaseEntity
{ {
/** 序列化版本号。 */
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 主键ID。 */
@ApiModelProperty("主键ID") @ApiModelProperty("主键ID")
@TableId(value = "id", type = IdType.ASSIGN_UUID) @TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id; private String id;
/** 告警编码。 */
@Excel(name = "告警编码") @Excel(name = "告警编码")
@ApiModelProperty("告警编码") @ApiModelProperty("告警编码")
private String alarmCode; private String alarmCode;
/** 任务执行实例ID。 */
@Excel(name = "任务执行实例ID") @Excel(name = "任务执行实例ID")
@ApiModelProperty("任务执行实例ID") @ApiModelProperty("任务执行实例ID")
private String taskInstanceId; private String taskInstanceId;
/** 任务ID。 */
@Excel(name = "任务ID") @Excel(name = "任务ID")
@ApiModelProperty("任务ID") @ApiModelProperty("任务ID")
private String taskId; private String taskId;
/** 任务名称。 */
@Excel(name = "任务名称") @Excel(name = "任务名称")
@ApiModelProperty("任务名称") @ApiModelProperty("任务名称")
private String taskName; private String taskName;
/** 手机ID。 */
@Excel(name = "手机ID") @Excel(name = "手机ID")
@ApiModelProperty("手机ID") @ApiModelProperty("手机ID")
private String phoneId; private String phoneId;
/** 手机名称。 */
@Excel(name = "手机名称") @Excel(name = "手机名称")
@ApiModelProperty("手机名称") @ApiModelProperty("手机名称")
private String phoneName; private String phoneName;
/** 车辆ID。 */
@Excel(name = "车辆ID") @Excel(name = "车辆ID")
@ApiModelProperty("车辆ID") @ApiModelProperty("车辆ID")
private String vehicleId; private String vehicleId;
/** 车辆车架号。 */
@Excel(name = "车架号") @Excel(name = "车架号")
@ApiModelProperty("车架号") @ApiModelProperty("车架号")
private String vin; private String vin;
/** 测试用例ID。 */
@Excel(name = "测试用例ID") @Excel(name = "测试用例ID")
@ApiModelProperty("测试用例ID") @ApiModelProperty("测试用例ID")
private String testCaseId; private String testCaseId;
/** 测试用例名称。 */
@Excel(name = "用例名称") @Excel(name = "用例名称")
@ApiModelProperty("用例名称") @ApiModelProperty("用例名称")
private String caseName; private String caseName;
/** 告警级别1提示2警告3严重。 */
@Excel(name = "告警级别") @Excel(name = "告警级别")
@ApiModelProperty("告警级别(1提示 2警告 3严重)") @ApiModelProperty("告警级别(1提示 2警告 3严重)")
private String alarmLevel; private String alarmLevel;
/** 告警类型1设备异常2测试异常3通信异常4性能异常。 */
@Excel(name = "告警类型") @Excel(name = "告警类型")
@ApiModelProperty("告警类型(1设备异常 2测试异常 3通信异常 4性能异常)") @ApiModelProperty("告警类型(1设备异常 2测试异常 3通信异常 4性能异常)")
private String alarmType; private String alarmType;
/** 告警标题。 */
@Excel(name = "告警标题") @Excel(name = "告警标题")
@ApiModelProperty("告警标题") @ApiModelProperty("告警标题")
private String alarmTitle; private String alarmTitle;
/** 告警内容详情。 */
@Excel(name = "告警内容") @Excel(name = "告警内容")
@ApiModelProperty("告警内容") @ApiModelProperty("告警内容")
private String alarmContent; private String alarmContent;
/** 告警发生位置或执行步骤。 */
@Excel(name = "告警位置") @Excel(name = "告警位置")
@ApiModelProperty("告警位置/步骤") @ApiModelProperty("告警位置/步骤")
private String alarmLocation; private String alarmLocation;
/** 告警发生时间。 */
@Excel(name = "告警时间") @Excel(name = "告警时间")
@ApiModelProperty("告警时间") @ApiModelProperty("告警时间")
private Date alarmTime; private Date alarmTime;
/** 处理状态0未处理1处理中2已处理3已忽略。 */
@Excel(name = "处理状态") @Excel(name = "处理状态")
@ApiModelProperty("处理状态(0未处理 1处理中 2已处理 3已忽略)") @ApiModelProperty("处理状态(0未处理 1处理中 2已处理 3已忽略)")
private String handleStatus; private String handleStatus;
/** 告警处理人。 */
@Excel(name = "处理人") @Excel(name = "处理人")
@ApiModelProperty("处理人") @ApiModelProperty("处理人")
private String handler; private String handler;
/** 告警处理时间。 */
@Excel(name = "处理时间") @Excel(name = "处理时间")
@ApiModelProperty("处理时间") @ApiModelProperty("处理时间")
private Date handleTime; private Date handleTime;
/** 处理说明或备注。 */
@Excel(name = "处理说明") @Excel(name = "处理说明")
@ApiModelProperty("处理说明") @ApiModelProperty("处理说明")
private String handleRemark; private String handleRemark;
/** 告警相关图片证据。 */
@ApiModelProperty("图片证据") @ApiModelProperty("图片证据")
private String evidenceImage; private String evidenceImage;

View File

@ -26,34 +26,58 @@ public class AimaPhone extends BaseEntity
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ApiModelProperty("主键ID") @ApiModelProperty("主键ID")
@TableId(value = "id", type = IdType.ASSIGN_UUID) @TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id; private String id;
/**
* 手机名称
*/
@Excel(name = "手机名称") @Excel(name = "手机名称")
@ApiModelProperty("手机名称") @ApiModelProperty("手机名称")
private String phoneName; private String phoneName;
/**
* 手机型号
*/
@Excel(name = "手机型号") @Excel(name = "手机型号")
@ApiModelProperty("手机型号") @ApiModelProperty("手机型号")
private String phoneModel; private String phoneModel;
/**
* 操作系统(Android/iOS)
*/
@Excel(name = "操作系统") @Excel(name = "操作系统")
@ApiModelProperty("操作系统(Android/iOS)") @ApiModelProperty("操作系统(Android/iOS)")
private String osSystem; private String osSystem;
/**
* 系统版本
*/
@Excel(name = "系统版本") @Excel(name = "系统版本")
@ApiModelProperty("系统版本") @ApiModelProperty("系统版本")
private String osVersion; private String osVersion;
/**
* 规格参数
*/
@Excel(name = "规格参数") @Excel(name = "规格参数")
@ApiModelProperty("规格参数") @ApiModelProperty("规格参数")
private String specifications; private String specifications;
/**
* 厂商
*/
@Excel(name = "厂商") @Excel(name = "厂商")
@ApiModelProperty("厂商") @ApiModelProperty("厂商")
private String manufacturer; private String manufacturer;
/**
* 状态(0正常 1停用)
*/
@Excel(name = "状态") @Excel(name = "状态")
@ApiModelProperty("状态(0正常 1停用)") @ApiModelProperty("状态(0正常 1停用)")
private String status; private String status;

View File

@ -10,6 +10,7 @@ import com.cmvr.aima.service.IAimaTaskInstanceService;
import com.cmvr.aima.service.IAimaTestLogService; import com.cmvr.aima.service.IAimaTestLogService;
import com.cmvr.test.flow.runtime.event.FlowExecutionEvent; import com.cmvr.test.flow.runtime.event.FlowExecutionEvent;
import com.cmvr.test.flow.runtime.event.FlowExecutionListener; import com.cmvr.test.flow.runtime.event.FlowExecutionListener;
import com.cmvr.test.flow.runtime.event.FlowExecutionModuleCodes;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -42,6 +43,11 @@ public class AimaFlowExecutionListener implements FlowExecutionListener {
this.messagePushService = messagePushService; this.messagePushService = messagePushService;
} }
@Override
public String getModuleCode() {
return FlowExecutionModuleCodes.AIMA;
}
@Override @Override
public void onEvent(FlowExecutionEvent event) { public void onEvent(FlowExecutionEvent event) {
String instId = event.getInstId(); String instId = event.getInstId();

View File

@ -10,6 +10,7 @@ import com.cmvr.common.exception.ServiceException;
import com.cmvr.common.utils.SecurityUtils; import com.cmvr.common.utils.SecurityUtils;
import com.cmvr.test.flow.control.FlowControlService; import com.cmvr.test.flow.control.FlowControlService;
import com.cmvr.test.flow.runtime.engine.FlowTaskRuntimeService; import com.cmvr.test.flow.runtime.engine.FlowTaskRuntimeService;
import com.cmvr.test.flow.runtime.event.FlowExecutionModuleCodes;
import com.cmvr.test.model.vo.TeTaskExecuteNormalVO; import com.cmvr.test.model.vo.TeTaskExecuteNormalVO;
import com.cmvr.test.service.ITeTaskOrchestrationService; import com.cmvr.test.service.ITeTaskOrchestrationService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -146,6 +147,7 @@ public class AimaTaskInstanceServiceImpl extends ServiceImpl<AimaTaskInstanceMap
String insId = flowTaskRuntimeService.executeTask( String insId = flowTaskRuntimeService.executeTask(
TeTaskExecuteNormalVO.builder() TeTaskExecuteNormalVO.builder()
.taskId(aimaTask.getTaskConfigId()) .taskId(aimaTask.getTaskConfigId())
.moduleCode(FlowExecutionModuleCodes.AIMA)
.runParams(runParams) .runParams(runParams)
.build() .build()
); );

View File

@ -12,6 +12,7 @@ import com.cmvr.inspection.service.IInspectionTaskInstanceService;
import com.cmvr.inspection.service.IInspectionTaskLogService; import com.cmvr.inspection.service.IInspectionTaskLogService;
import com.cmvr.test.flow.runtime.event.FlowExecutionEvent; import com.cmvr.test.flow.runtime.event.FlowExecutionEvent;
import com.cmvr.test.flow.runtime.event.FlowExecutionListener; import com.cmvr.test.flow.runtime.event.FlowExecutionListener;
import com.cmvr.test.flow.runtime.event.FlowExecutionModuleCodes;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -37,6 +38,11 @@ public class InspectionFlowExecutionListener implements FlowExecutionListener {
this.messagePushService = messagePushService; this.messagePushService = messagePushService;
} }
@Override
public String getModuleCode() {
return FlowExecutionModuleCodes.INSPECTION;
}
@Override @Override
public void onEvent(FlowExecutionEvent event) { public void onEvent(FlowExecutionEvent event) {
String instId = event.getInstId(); String instId = event.getInstId();
@ -185,4 +191,4 @@ public class InspectionFlowExecutionListener implements FlowExecutionListener {
log.info("消息推送异常,无订阅忽略,insId:{}", dbInsId, e); log.info("消息推送异常,无订阅忽略,insId:{}", dbInsId, e);
} }
} }
} }

View File

@ -14,6 +14,7 @@ import com.cmvr.inspection.enums.TaskStatusEnum;
import com.cmvr.inspection.service.IInspectionTaskService; import com.cmvr.inspection.service.IInspectionTaskService;
import com.cmvr.test.flow.control.FlowControlService; import com.cmvr.test.flow.control.FlowControlService;
import com.cmvr.test.flow.runtime.engine.FlowTaskRuntimeService; import com.cmvr.test.flow.runtime.engine.FlowTaskRuntimeService;
import com.cmvr.test.flow.runtime.event.FlowExecutionModuleCodes;
import com.cmvr.test.model.vo.TeTaskExecuteNormalVO; import com.cmvr.test.model.vo.TeTaskExecuteNormalVO;
import com.cmvr.test.service.ITeTaskOrchestrationService; import com.cmvr.test.service.ITeTaskOrchestrationService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -158,7 +159,11 @@ public class InspectionTaskInstanceServiceImpl extends ServiceImpl<InspectionTas
// 获取所有的检测项id // 获取所有的检测项id
teTaskOrchestrationService.queryByTaskId(inspectionTask.getTaskConfigId()).forEach(item -> runParams.put(item.getItemId(), new JSONObject())); teTaskOrchestrationService.queryByTaskId(inspectionTask.getTaskConfigId()).forEach(item -> runParams.put(item.getItemId(), new JSONObject()));
// 调用真正的执行 // 调用真正的执行
String insId = flowTaskRuntimeService.executeTask(TeTaskExecuteNormalVO.builder().taskId(inspectionTask.getTaskConfigId()).runParams(runParams).build()); String insId = flowTaskRuntimeService.executeTask(TeTaskExecuteNormalVO.builder()
.taskId(inspectionTask.getTaskConfigId())
.moduleCode(FlowExecutionModuleCodes.INSPECTION)
.runParams(runParams)
.build());
update.setTaskInsId(insId); update.setTaskInsId(insId);
return inspectionTaskInstanceMapper.updateInspectionTaskInstance(update); return inspectionTaskInstanceMapper.updateInspectionTaskInstance(update);
} }

View File

@ -31,6 +31,11 @@ public class TaskContext {
*/ */
private String taskId; private String taskId;
/**
* 模块编码
*/
private String moduleCode;
/** /**
* 当前检测项 ID * 当前检测项 ID
*/ */

View File

@ -55,13 +55,20 @@ public class TaskInstHolder {
syncStatus(instId, TaskStatusEnum.SUCCESS); syncStatus(instId, TaskStatusEnum.SUCCESS);
// 如果没有下一个检测项要执行 且是end节点 注销任务上下文 // 如果没有下一个检测项要执行 且是end节点 注销任务上下文
if (pendingItemCount == 0 && nodeType.equalsIgnoreCase(NodeTypeEnum.END.getCode())) { if (pendingItemCount == 0 && nodeType.equalsIgnoreCase(NodeTypeEnum.END.getCode())) {
// 先获取上下文在注销前
TaskContext ctx = taskContextManager.get(instId); TaskContext ctx = taskContextManager.get(instId);
String taskId = ctx != null ? ctx.getTaskId() : null;
String moduleCode = ctx != null ? ctx.getModuleCode() : null;
// 注销任务上下文
taskContextManager.unregister(instId); taskContextManager.unregister(instId);
// 发布任务完成事件 // 发布任务完成事件
eventPublisher.publishEvent(FlowExecutionEvent.builder() eventPublisher.publishEvent(FlowExecutionEvent.builder()
.eventType(FlowExecutionEvent.EventType.TASK_COMPLETED) .eventType(FlowExecutionEvent.EventType.TASK_COMPLETED)
.instId(instId) .instId(instId)
.taskId(ctx != null ? ctx.getTaskId() : null) .taskId(taskId)
.moduleCode(moduleCode)
.itemId(itemId) .itemId(itemId)
.status(TaskStatusEnum.SUCCESS) .status(TaskStatusEnum.SUCCESS)
.build()); .build());
@ -74,12 +81,20 @@ public class TaskInstHolder {
nodeInstService.logFailed(instId, taskId, itemId, nodeId, nodeType, operate, action, params, message,iterations); nodeInstService.logFailed(instId, taskId, itemId, nodeId, nodeType, operate, action, params, message,iterations);
syncStatus(instId, TaskStatusEnum.FAILED); syncStatus(instId, TaskStatusEnum.FAILED);
// 先获取上下文在注销前
TaskContext ctx = taskContextManager.get(instId);
String moduleCode = ctx != null ? ctx.getModuleCode() : null;
// 注销任务上下文
taskContextManager.unregister(instId); taskContextManager.unregister(instId);
// 发布任务失败事件 // 发布任务失败事件
eventPublisher.publishEvent(FlowExecutionEvent.builder() eventPublisher.publishEvent(FlowExecutionEvent.builder()
.eventType(FlowExecutionEvent.EventType.TASK_FAILED) .eventType(FlowExecutionEvent.EventType.TASK_FAILED)
.instId(instId) .instId(instId)
.taskId(taskId) .taskId(taskId)
.moduleCode(moduleCode)
.itemId(itemId) .itemId(itemId)
.status(TaskStatusEnum.FAILED) .status(TaskStatusEnum.FAILED)
.errorMessage(message) .errorMessage(message)
@ -110,12 +125,14 @@ public class TaskInstHolder {
eventPublisher.publishEvent(FlowExecutionEvent.builder() eventPublisher.publishEvent(FlowExecutionEvent.builder()
.eventType(FlowExecutionEvent.EventType.TASK_PAUSED) .eventType(FlowExecutionEvent.EventType.TASK_PAUSED)
.instId(instId).taskId(ctx.getTaskId()).itemId(ctx.getItemId()) .instId(instId).taskId(ctx.getTaskId()).itemId(ctx.getItemId())
.moduleCode(ctx.getModuleCode())
.status(status).build()); .status(status).build());
break; break;
case STOPPED: case STOPPED:
eventPublisher.publishEvent(FlowExecutionEvent.builder() eventPublisher.publishEvent(FlowExecutionEvent.builder()
.eventType(FlowExecutionEvent.EventType.TASK_STOPPED) .eventType(FlowExecutionEvent.EventType.TASK_STOPPED)
.instId(instId).taskId(ctx.getTaskId()).itemId(ctx.getItemId()) .instId(instId).taskId(ctx.getTaskId()).itemId(ctx.getItemId())
.moduleCode(ctx.getModuleCode())
.status(status).build()); .status(status).build());
break; break;
default: default:
@ -132,6 +149,7 @@ public class TaskInstHolder {
eventPublisher.publishEvent(FlowExecutionEvent.builder() eventPublisher.publishEvent(FlowExecutionEvent.builder()
.eventType(FlowExecutionEvent.EventType.TASK_RESUMED) .eventType(FlowExecutionEvent.EventType.TASK_RESUMED)
.instId(instId).taskId(ctx.getTaskId()).itemId(ctx.getItemId()) .instId(instId).taskId(ctx.getTaskId()).itemId(ctx.getItemId())
.moduleCode(ctx.getModuleCode())
.status(TaskStatusEnum.RUNNING).build()); .status(TaskStatusEnum.RUNNING).build());
} }

View File

@ -49,6 +49,7 @@ public class FlowTaskRuntimeEntry implements FlowTaskRuntimeService {
return executeTaskInternal( return executeTaskInternal(
taskExecuteNormalVO.getTerminalId(), taskExecuteNormalVO.getTerminalId(),
taskExecuteNormalVO.getTaskId(), taskExecuteNormalVO.getTaskId(),
taskExecuteNormalVO.getModuleCode(),
RunModeEnum.NORMAL, RunModeEnum.NORMAL,
taskExecuteNormalVO.getRunParams(), taskExecuteNormalVO.getRunParams(),
taskExecuteNormalVO taskExecuteNormalVO
@ -90,7 +91,7 @@ public class FlowTaskRuntimeEntry implements FlowTaskRuntimeService {
List<TeQueryTaskDetailDTO> details = CollUtil.newArrayList(teQueryTaskDetailDTO); List<TeQueryTaskDetailDTO> details = CollUtil.newArrayList(teQueryTaskDetailDTO);
// 注册上下文 // 注册上下文
registerTaskContext(instId, taskId, terminalId, itemId, RunModeEnum.TRIAL, runParams); registerTaskContext(instId, taskId, null, terminalId, itemId, RunModeEnum.TRIAL, runParams);
// 异步调度执行与正式任务一致只是模式为 TRIAL // 异步调度执行与正式任务一致只是模式为 TRIAL
flowTaskAsyncDispatcher.submit(instId, taskId, terminalId, RunModeEnum.TRIAL, details); flowTaskAsyncDispatcher.submit(instId, taskId, terminalId, RunModeEnum.TRIAL, details);
@ -113,6 +114,7 @@ public class FlowTaskRuntimeEntry implements FlowTaskRuntimeService {
return executeTaskInternal( return executeTaskInternal(
taskExecuteProjectVO.getTerminalId(), taskExecuteProjectVO.getTerminalId(),
taskExecuteProjectVO.getProjectId(), taskExecuteProjectVO.getProjectId(),
null,
RunModeEnum.VI_PROJECT, RunModeEnum.VI_PROJECT,
taskExecuteProjectVO.getRunParams(), taskExecuteProjectVO.getRunParams(),
taskExecuteProjectVO taskExecuteProjectVO
@ -120,7 +122,7 @@ public class FlowTaskRuntimeEntry implements FlowTaskRuntimeService {
} }
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public String executeTaskInternal(String terminalId, String taskId, public String executeTaskInternal(String terminalId, String taskId, String moduleCode,
RunModeEnum runMode, JSONObject runParams, Object originalVO) { RunModeEnum runMode, JSONObject runParams, Object originalVO) {
if (StrUtil.isEmpty(terminalId)) { if (StrUtil.isEmpty(terminalId)) {
// throw new GlobalException("终端ID不能为空"); // throw new GlobalException("终端ID不能为空");
@ -141,7 +143,7 @@ public class FlowTaskRuntimeEntry implements FlowTaskRuntimeService {
try { try {
// 注册上下文 // 注册上下文
registerTaskContext(instId, taskId, terminalId, null, runMode, runParams); registerTaskContext(instId, taskId, moduleCode, terminalId, null, runMode, runParams);
// 异步提交执行 // 异步提交执行
flowTaskAsyncDispatcher.submit(instId, taskId, terminalId, runMode, details); flowTaskAsyncDispatcher.submit(instId, taskId, terminalId, runMode, details);
@ -176,11 +178,12 @@ public class FlowTaskRuntimeEntry implements FlowTaskRuntimeService {
/** /**
* 注册上下文 * 注册上下文
*/ */
private void registerTaskContext(String instId, String taskId, String terminalId, private void registerTaskContext(String instId, String taskId, String moduleCode, String terminalId,
String itemId, RunModeEnum mode, JSONObject runParams) { String itemId, RunModeEnum mode, JSONObject runParams) {
TaskContext ctx = new TaskContext(); TaskContext ctx = new TaskContext();
ctx.setInstId(instId); ctx.setInstId(instId);
ctx.setTaskId(taskId); ctx.setTaskId(taskId);
ctx.setModuleCode(moduleCode);
ctx.setRunMode(mode); ctx.setRunMode(mode);
ctx.setTerminalId(terminalId); ctx.setTerminalId(terminalId);
ctx.setItemId(itemId); ctx.setItemId(itemId);

View File

@ -32,6 +32,11 @@ public class FlowExecutionEvent {
*/ */
private String taskId; private String taskId;
/**
* 模块编码
*/
private String moduleCode;
/** /**
* 节点数量 * 节点数量
*/ */

View File

@ -1,5 +1,6 @@
package com.cmvr.test.flow.runtime.event; package com.cmvr.test.flow.runtime.event;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -36,6 +37,9 @@ public class FlowExecutionEventPublisher {
return; return;
} }
for (FlowExecutionListener listener : listeners) { for (FlowExecutionListener listener : listeners) {
if (!shouldDispatch(listener, event)) {
continue;
}
try { try {
listener.onEvent(event); listener.onEvent(event);
} catch (Exception e) { } catch (Exception e) {
@ -44,4 +48,39 @@ public class FlowExecutionEventPublisher {
} }
} }
} }
/**
* 判断是否应该将事件分发给指定监听器
* <p>
* 分发规则
* 1. 如果事件的 moduleCode 为空则不发送给任何监听器避免无效调用
* 2. 如果监听器的 moduleCode 为空则不接收任何事件
* 3. 只有当两者的 moduleCode 匹配时才分发
*
* @param listener 监听器
* @param event 事件对象
* @return true 表示应该分发false 表示跳过
*/
private boolean shouldDispatch(FlowExecutionListener listener, FlowExecutionEvent event) {
// 事件或模块编码为空不分发
if (event == null || StrUtil.isBlank(event.getModuleCode())) {
log.warn("事件模块编码为空,跳过分发: eventType={}", event != null ? event.getEventType() : null);
return false;
}
// 监听器模块编码为空不接收事件
String listenerModuleCode = listener.getModuleCode();
if (StrUtil.isBlank(listenerModuleCode)) {
log.warn("监听器 [{}] 模块编码为空,不接收事件", listener.getClass().getSimpleName());
return false;
}
// 精确匹配模块编码忽略大小写
boolean matched = StrUtil.equalsIgnoreCase(event.getModuleCode(), listenerModuleCode);
if (!matched) {
log.debug("监听器 [{}] 模块编码 [{}] 与事件模块编码 [{}] 不匹配,跳过",
listener.getClass().getSimpleName(), listenerModuleCode, event.getModuleCode());
}
return matched;
}
} }

View File

@ -35,4 +35,6 @@ public interface FlowExecutionListener {
* @param event 流程执行事件 * @param event 流程执行事件
*/ */
void onEvent(FlowExecutionEvent event); void onEvent(FlowExecutionEvent event);
String getModuleCode();
} }

View File

@ -0,0 +1,23 @@
package com.cmvr.test.flow.runtime.event;
/**
* 流程执行模块编码常量
* <p>
* 用于标识不同业务模块的流程执行事件实现事件监听的精确分发
*/
public final class FlowExecutionModuleCodes {
/**
* 智能巡检模块
*/
public static final String INSPECTION = "INSPECTION";
/**
* 爱玛测试模块
*/
public static final String AIMA = "AIMA";
private FlowExecutionModuleCodes() {
// 防止实例化
}
}

View File

@ -1,5 +1,7 @@
package com.cmvr.test.flow.runtime.interceptor; package com.cmvr.test.flow.runtime.interceptor;
import com.cmvr.test.flow.context.TaskContext;
import com.cmvr.test.flow.context.TaskInstHolder;
import com.cmvr.test.flow.runtime.event.FlowExecutionEvent; import com.cmvr.test.flow.runtime.event.FlowExecutionEvent;
import com.cmvr.test.flow.runtime.event.FlowExecutionEventPublisher; import com.cmvr.test.flow.runtime.event.FlowExecutionEventPublisher;
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage; import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage;
@ -15,8 +17,11 @@ import java.util.function.Function;
@Order(6) @Order(6)
public class FlowAfterInterceptor extends AbstractFlowMsgPreInterceptor{ public class FlowAfterInterceptor extends AbstractFlowMsgPreInterceptor{
public FlowAfterInterceptor(FlowExecutionEventPublisher eventPublisher) { private final TaskInstHolder taskInstHolder;
public FlowAfterInterceptor(FlowExecutionEventPublisher eventPublisher, TaskInstHolder taskInstHolder) {
super(eventPublisher); super(eventPublisher);
this.taskInstHolder = taskInstHolder;
} }
@Override @Override
@ -32,12 +37,20 @@ public class FlowAfterInterceptor extends AbstractFlowMsgPreInterceptor{
errorMessage = result != null ? result.getErrorMsg() : "执行结果为空"; errorMessage = result != null ? result.getErrorMsg() : "执行结果为空";
} }
TaskContext taskContext = taskInstHolder.getContext(message.getInstId());
String moduleCode = taskContext != null ? taskContext.getModuleCode() : null;
if (moduleCode == null) {
log.warn("节点 [{}] 执行后,任务上下文 [{}] 的 moduleCode 为空,事件可能不会被监听器处理",
message.getNodeName(), message.getInstId());
}
FlowExecutionEvent event = FlowExecutionEvent.builder() FlowExecutionEvent event = FlowExecutionEvent.builder()
.eventType(eventType) .eventType(eventType)
.nodeName(message.getNodeName()) .nodeName(message.getNodeName())
.instId(message.getInstId()) .instId(message.getInstId())
.nodeName(message.getNodeName())
.taskId(message.getTaskId()) .taskId(message.getTaskId())
.moduleCode(moduleCode)
.itemId(message.getItemId()) .itemId(message.getItemId())
.nodeId(message.getNodeId()) .nodeId(message.getNodeId())
.nodeCount(message.getGraph().allNodeIds().size()) .nodeCount(message.getGraph().allNodeIds().size())

View File

@ -1,5 +1,7 @@
package com.cmvr.test.flow.runtime.interceptor; package com.cmvr.test.flow.runtime.interceptor;
import com.cmvr.test.flow.context.TaskContext;
import com.cmvr.test.flow.context.TaskInstHolder;
import com.cmvr.test.flow.runtime.event.FlowExecutionEvent; import com.cmvr.test.flow.runtime.event.FlowExecutionEvent;
import com.cmvr.test.flow.runtime.event.FlowExecutionEventPublisher; import com.cmvr.test.flow.runtime.event.FlowExecutionEventPublisher;
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage; import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage;
@ -15,16 +17,28 @@ import java.util.function.Function;
@Order(1) @Order(1)
public class FlowBeforeInterceptor extends AbstractFlowMsgPreInterceptor{ public class FlowBeforeInterceptor extends AbstractFlowMsgPreInterceptor{
public FlowBeforeInterceptor(FlowExecutionEventPublisher eventPublisher) { private final TaskInstHolder taskInstHolder;
public FlowBeforeInterceptor(FlowExecutionEventPublisher eventPublisher, TaskInstHolder taskInstHolder) {
super(eventPublisher); super(eventPublisher);
this.taskInstHolder = taskInstHolder;
} }
@Override @Override
public TaskNodeExecuteResult doIntercept(TaskNodeExecuteMessage message, Function<TaskNodeExecuteMessage, TaskNodeExecuteResult> next) { public TaskNodeExecuteResult doIntercept(TaskNodeExecuteMessage message, Function<TaskNodeExecuteMessage, TaskNodeExecuteResult> next) {
TaskContext taskContext = taskInstHolder.getContext(message.getInstId());
String moduleCode = taskContext != null ? taskContext.getModuleCode() : null;
if (moduleCode == null) {
log.warn("节点 [{}] 执行前,任务上下文 [{}] 的 moduleCode 为空,事件可能不会被监听器处理",
message.getNodeName(), message.getInstId());
}
FlowExecutionEvent event = FlowExecutionEvent.builder() FlowExecutionEvent event = FlowExecutionEvent.builder()
.eventType(FlowExecutionEvent.EventType.NODE_STARTED) .eventType(FlowExecutionEvent.EventType.NODE_STARTED)
.instId(message.getInstId()) .instId(message.getInstId())
.taskId(message.getTaskId()) .taskId(message.getTaskId())
.moduleCode(moduleCode)
.itemId(message.getItemId()) .itemId(message.getItemId())
.nodeId(message.getNodeId()) .nodeId(message.getNodeId())
.nodeCount(message.getGraph().allNodeIds().size()) .nodeCount(message.getGraph().allNodeIds().size())

View File

@ -20,6 +20,9 @@ public class TeTaskExecuteNormalVO {
@NotEmpty(message = "任务ID不能为空") @NotEmpty(message = "任务ID不能为空")
private String taskId; private String taskId;
@ApiModelProperty("模块编码")
private String moduleCode;
@ApiModelProperty("终端ID") @ApiModelProperty("终端ID")
@NotEmpty(message = "终端ID不能为空") @NotEmpty(message = "终端ID不能为空")
private String terminalId; private String terminalId;