feat(REQ-4418) - 提交
This commit is contained in:
parent
344bdfd2ee
commit
033b938766
@ -158,9 +158,8 @@ public class WorkflowEngineStarterAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ImplementationReadyChecker implementationReadyChecker(WorkflowCoreService workflowCoreService,
|
||||
Environment environment) {
|
||||
return new ImplementationReadyChecker(workflowCoreService, environment);
|
||||
public ImplementationReadyChecker implementationReadyChecker(WorkflowCoreService workflowCoreService) {
|
||||
return new ImplementationReadyChecker(workflowCoreService);
|
||||
}
|
||||
|
||||
// @Bean
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
package cn.axzo.workflow.starter.api;
|
||||
|
||||
import cn.axzo.workflow.common.annotation.InvokeMode;
|
||||
import cn.axzo.workflow.common.enums.AdminDataSource;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.model.dto.SignFileDTO;
|
||||
import cn.axzo.workflow.common.model.dto.SimpleDocDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.activity.BpmnActivityTimeoutCallbackDTO;
|
||||
@ -141,16 +139,12 @@ public interface WorkflowCoreService {
|
||||
@InvokeMode(SYNC)
|
||||
Boolean setTimeoutCallback(@Validated @RequestBody BpmnActivityTimeoutCallbackDTO dto);
|
||||
|
||||
@Operation(summary = "获取指定枚举类型的枚举值信息")
|
||||
@GetMapping("/api/function/enum/admin-data-source/get")
|
||||
@InvokeMode(SYNC)
|
||||
AdminDataSource getAdminDataSourceEnum(@RequestParam String enumValue);
|
||||
|
||||
@Operation(summary = "获取指定枚举类型的枚举值信息")
|
||||
@GetMapping("/api/function/enum/process-instance-result/get")
|
||||
@InvokeMode(SYNC)
|
||||
BpmnProcessInstanceResultEnum getFileTypeEnum(@RequestParam String enumValue);
|
||||
|
||||
/**
|
||||
* 用于 Starter 检测必接事件的告警
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "发送钉钉消息")
|
||||
@PostMapping("/api/function/dingtalk/alter")
|
||||
@InvokeMode(SYNC)
|
||||
|
||||
@ -2,6 +2,8 @@ package cn.axzo.workflow.starter.api;
|
||||
|
||||
import cn.axzo.workflow.common.annotation.InvokeMode;
|
||||
import cn.axzo.workflow.common.annotation.Manageable;
|
||||
import cn.axzo.workflow.common.enums.AdminDataSource;
|
||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||
import cn.axzo.workflow.common.model.dto.print.PrintFieldDTO;
|
||||
import cn.axzo.workflow.common.model.request.admin.ProcessAdminCreateDTO;
|
||||
import cn.axzo.workflow.common.model.request.admin.ProcessAdminDeleteDTO;
|
||||
@ -194,6 +196,18 @@ public interface WorkflowManageService {
|
||||
@InvokeMode(SYNC)
|
||||
Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId);
|
||||
|
||||
@Operation(summary = "获取指定枚举类型的枚举值信息")
|
||||
@GetMapping("/api/function/enum/admin-data-source/get")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
AdminDataSource getAdminDataSourceEnum(@RequestParam String enumValue);
|
||||
|
||||
@Operation(summary = "获取指定枚举类型的枚举值信息")
|
||||
@GetMapping("/api/function/enum/process-instance-result/get")
|
||||
@Manageable
|
||||
@InvokeMode(SYNC)
|
||||
BpmnProcessInstanceResultEnum getFileTypeEnum(@RequestParam String enumValue);
|
||||
|
||||
@PostMapping("/api/form/admin/form/page")
|
||||
@InvokeMode(SYNC)
|
||||
@Manageable
|
||||
|
||||
@ -1,15 +1,23 @@
|
||||
package cn.axzo.workflow.starter.mq.check;
|
||||
|
||||
import cn.axzo.framework.rocketmq.DefaultEventConsumer;
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventHandler;
|
||||
import cn.axzo.framework.rocketmq.EventHandlerRepository;
|
||||
import cn.axzo.workflow.common.enums.ProcessInstanceEventEnum;
|
||||
import cn.axzo.workflow.common.model.request.feature.DingTalkStarterAlterDTO;
|
||||
import cn.axzo.workflow.common.model.response.mq.ProcessInstanceDTO;
|
||||
import cn.axzo.workflow.starter.api.WorkflowCoreService;
|
||||
import cn.axzo.workflow.starter.handler.ProcessInstanceEventHandler;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -34,28 +42,60 @@ public class ImplementationReadyChecker implements ApplicationListener<Applicati
|
||||
"onAborted"
|
||||
);
|
||||
|
||||
private static final List<Event.EventCode> EVENT_CODES = Arrays.asList(
|
||||
ProcessInstanceEventEnum.PROCESS_INSTANCE_COMPLETED.getEventCode(),
|
||||
ProcessInstanceEventEnum.PROCESS_INSTANCE_CANCELLED.getEventCode(),
|
||||
ProcessInstanceEventEnum.PROCESS_INSTANCE_REJECTED.getEventCode(),
|
||||
ProcessInstanceEventEnum.PROCESS_INSTANCE_ABORTED.getEventCode()
|
||||
);
|
||||
private final WorkflowCoreService workflowCoreService;
|
||||
private final Environment environment;
|
||||
|
||||
public ImplementationReadyChecker(WorkflowCoreService workflowCoreService,
|
||||
Environment environment) {
|
||||
public ImplementationReadyChecker(WorkflowCoreService workflowCoreService) {
|
||||
this.workflowCoreService = workflowCoreService;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent event) {
|
||||
ApplicationContext context = event.getApplicationContext();
|
||||
// 获取所有实现了目标接口的Bean
|
||||
Map<String, ProcessInstanceEventHandler> handlers = context.getBeansOfType(TARGET_INTERFACE);
|
||||
if (handlers.isEmpty()) {
|
||||
log.warn("未找到实现 {} 接口的Bean, 请确保至少有一个实现类被正确扫描和注册。", TARGET_INTERFACE.getName());
|
||||
boolean[] methodImplemented = checkUnImplementedMethodsWithInterface(context);
|
||||
if (getBinaryResult(methodImplemented) == 15) {
|
||||
log.info("Congratulations, passed the verification!");
|
||||
log.info("祝贺,已通过必接事件的校验!但仍然请确保您的实现类逻辑正确无误,不允许出现空实现,否则生产问题自行负责!");
|
||||
return;
|
||||
}
|
||||
log.info("将继续通过 EventConsumer 进行检查...");
|
||||
methodImplemented = checkUnImplementedMethodsWithEventConsumer(context);
|
||||
if (getBinaryResult(methodImplemented) == 15) {
|
||||
log.info("Congratulations, passed the verification!");
|
||||
log.info("祝贺,已通过必接事件的校验!但仍然请确保您的实现类逻辑正确无误,不允许出现空实现,否则生产问题自行负责!");
|
||||
} else {
|
||||
log.error("----------------------------------------");
|
||||
log.error("警告:未通过必接事件的校验!未实现的方法:{},请确保使用了实现了 {} 接口的Bean被Spring扫描,或者在EventConsumer注册了 ProcessInstanceEventEnum 的 EventCode。", String.join(", ", getUnImplementedMethods(methodImplemented)), TARGET_INTERFACE.getName());
|
||||
log.error("----------------------------------------");
|
||||
sendAlter(context, getUnImplementedMethods(methodImplemented));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sendAlter(ApplicationContext context, List<String> unImplementedMethods) {
|
||||
Environment environment = context.getEnvironment();
|
||||
DingTalkStarterAlterDTO dto = new DingTalkStarterAlterDTO();
|
||||
dto.setApplicationName(environment.getProperty("spring.application.name"));
|
||||
dto.setProfile(environment.getProperty("spring.profiles.active"));
|
||||
dto.setAlterContent("必接事件实现类检查未通过,未实现的方法: " + String.join(", ", unImplementedMethods) + "。请确保至少有一个实现类覆盖这些方法以处理相应的事件。");
|
||||
workflowCoreService.sendDingtalk(dto);
|
||||
}
|
||||
|
||||
private static boolean[] checkUnImplementedMethodsWithInterface(ApplicationContext context) {
|
||||
// 记录每个方法是否被实现
|
||||
boolean[] methodImplemented = new boolean[4];
|
||||
Arrays.fill(methodImplemented, false);
|
||||
// 获取所有实现了目标接口的Bean
|
||||
Map<String, ProcessInstanceEventHandler> handlers = context.getBeansOfType(TARGET_INTERFACE);
|
||||
if (handlers.isEmpty()) {
|
||||
log.warn("未找到实现 {} 接口的Bean ", TARGET_INTERFACE.getName());
|
||||
return methodImplemented;
|
||||
}
|
||||
|
||||
// 检查每个实现类
|
||||
for (ProcessInstanceEventHandler handler : handlers.values()) {
|
||||
@ -75,7 +115,58 @@ public class ImplementationReadyChecker implements ApplicationListener<Applicati
|
||||
}
|
||||
}
|
||||
}
|
||||
int binaryResult = getBinaryResult(methodImplemented);
|
||||
List<String> unimplementedMethods = getUnImplementedMethods(methodImplemented);
|
||||
log.info("实现 {} 接口的Bean数量: {}", TARGET_INTERFACE.getName(), handlers.size());
|
||||
log.info("方法实现情况:(二进制:{}),(十进制:{})", String.format("%4s", Integer.toBinaryString(binaryResult)).replace(' ', '0'), binaryResult);
|
||||
if (!unimplementedMethods.isEmpty()) {
|
||||
log.warn("未通过 Starter 提供的 {} 接口实现中找到以下方法的实现: {}。请确保至少有一个实现类覆盖这些方法以处理相应的事件。", TARGET_INTERFACE.getName(), String.join(", ", unimplementedMethods));
|
||||
}
|
||||
return methodImplemented;
|
||||
}
|
||||
|
||||
private static boolean[] checkUnImplementedMethodsWithEventConsumer(ApplicationContext context) {
|
||||
// 记录每个方法是否被实现
|
||||
boolean[] methodImplemented = new boolean[4];
|
||||
Arrays.fill(methodImplemented, false);
|
||||
|
||||
Map<String, EventConsumer> beansOfType = context.getBeansOfType(EventConsumer.class);
|
||||
beansOfType.forEach((name, c) -> {
|
||||
if (c instanceof DefaultEventConsumer) {
|
||||
try {
|
||||
Field repoField = DefaultEventConsumer.class.getDeclaredField("handlerRepository");
|
||||
repoField.setAccessible(true);
|
||||
EventHandlerRepository repo = (EventHandlerRepository) repoField.get(c);
|
||||
|
||||
Field handlersField = EventHandlerRepository.class.getDeclaredField("handlers");
|
||||
handlersField.setAccessible(true);
|
||||
@SuppressWarnings("unchecked")
|
||||
ListMultimap<Event.EventCode, EventHandler> eventHandlers =
|
||||
(ListMultimap<Event.EventCode, EventHandler>) handlersField.get(repo);
|
||||
|
||||
for (int i = 0; i < EVENT_CODES.size(); i++) {
|
||||
methodImplemented[i] = eventHandlers.keySet().contains(EVENT_CODES.get(i));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("通过 EventConsumer 检测必接事件异常:{}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
return methodImplemented;
|
||||
}
|
||||
|
||||
private static List<String> getUnImplementedMethods(boolean[] methodImplemented) {
|
||||
// 收集未实现的方法
|
||||
List<String> unimplementedMethods = new ArrayList<>();
|
||||
for (int i = 0; i < methodImplemented.length; i++) {
|
||||
if (!methodImplemented[i]) {
|
||||
unimplementedMethods.add(METHOD_NAMES.get(i));
|
||||
}
|
||||
}
|
||||
return unimplementedMethods;
|
||||
}
|
||||
|
||||
private static int getBinaryResult(boolean[] methodImplemented) {
|
||||
// 生成4位二进制数
|
||||
int binaryResult = 0;
|
||||
for (int i = 0; i < methodImplemented.length; i++) {
|
||||
@ -85,27 +176,6 @@ public class ImplementationReadyChecker implements ApplicationListener<Applicati
|
||||
binaryResult += weight;
|
||||
}
|
||||
}
|
||||
|
||||
// 收集未实现的方法
|
||||
List<String> unimplementedMethods = new ArrayList<>();
|
||||
for (int i = 0; i < methodImplemented.length; i++) {
|
||||
if (!methodImplemented[i]) {
|
||||
unimplementedMethods.add(METHOD_NAMES.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
log.info("实现 {} 接口的Bean数量: {}", TARGET_INTERFACE.getName(), handlers.size());
|
||||
log.info("方法实现情况:(二进制:{}),(十进制:{})", String.format("%4s", Integer.toBinaryString(binaryResult)).replace(' ', '0'), binaryResult);
|
||||
if (!unimplementedMethods.isEmpty()) {
|
||||
log.error("以下方法未被任何实现类覆盖: {}。请确保至少有一个实现类覆盖这些方法以处理相应的事件。", String.join(", ", unimplementedMethods));
|
||||
DingTalkStarterAlterDTO dto = new DingTalkStarterAlterDTO();
|
||||
dto.setApplicationName(environment.getProperty("spring.application.name"));
|
||||
dto.setProfile(environment.getProperty("spring.profiles.active"));
|
||||
dto.setAlterContent("必接事件实现类检查未通过,未实现的方法: " + String.join(", ", unimplementedMethods) + "。请确保至少有一个实现类覆盖这些方法以处理相应的事件。");
|
||||
workflowCoreService.sendDingtalk(dto);
|
||||
} else {
|
||||
log.info("Congratulations, passed the verification!");
|
||||
log.info("祝贺,已通过必接事件的校验!但仍然请确保您的实现类逻辑正确无误,不允许出现空实现,否则生产问题自行负责!");
|
||||
}
|
||||
return binaryResult;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user