反序列化问题。

This commit is contained in:
dengqichen 2024-12-23 10:41:49 +08:00
parent 2878d66e50
commit 0e430c3036
7 changed files with 301 additions and 17 deletions

View File

@ -16,7 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired;
* @param <L> Local变量类型
*/
@Slf4j
public abstract class BaseTaskDelegate<P, L> implements JavaDelegate {
public abstract class BaseNodeDelegate<P, L> implements JavaDelegate {
@Autowired
private ObjectMapper objectMapper;

View File

@ -0,0 +1,176 @@
package com.qqchen.deploy.backend.workflow.delegate;
import com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants;
import com.qqchen.deploy.backend.workflow.dto.definition.node.localVariables.ScriptNodeLocalVariables;
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.ScriptNodePanelVariables;
import com.qqchen.deploy.backend.workflow.enums.NodeLogTypeEnums;
import com.qqchen.deploy.backend.workflow.event.ShellLogEvent;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.BpmnError;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Shell脚本任务的委派者实现
*/
@Slf4j
@Component
public class JenkinsNodeDelegate extends BaseNodeDelegate<ScriptNodePanelVariables, ScriptNodeLocalVariables> {
@Resource
private ApplicationEventPublisher eventPublisher;
// 用于存储实时输出的Map
private static final Map<String, StringBuilder> outputMap = new ConcurrentHashMap<>();
private static final Map<String, StringBuilder> errorMap = new ConcurrentHashMap<>();
@Override
protected Class<ScriptNodePanelVariables> getPanelVariablesClass() {
return ScriptNodePanelVariables.class;
}
@Override
protected Class<ScriptNodeLocalVariables> getLocalVariablesClass() {
return ScriptNodeLocalVariables.class;
}
@Override
protected void executeInternal(DelegateExecution execution,
ScriptNodePanelVariables panelVariables,
ScriptNodeLocalVariables localVariables) {
if (panelVariables == null || panelVariables.getScript() == null) {
throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, "Script is required but not provided");
}
// try {
// log.info("准备执行脚本: {}", panelVariables.getScript());
// // 使用processInstanceId而不是executionId
// String processInstanceId = execution.getProcessInstanceId();
// outputMap.put(processInstanceId, new StringBuilder());
// errorMap.put(processInstanceId, new StringBuilder());
//
// // 创建进程构建器
// ProcessBuilder processBuilder = new ProcessBuilder();
//
// // 根据操作系统选择合适的shell
// String os = System.getProperty("os.name").toLowerCase();
// if (os.contains("win")) {
// // Windows系统使用cmd
// processBuilder.command("cmd", "/c", panelVariables.getScript());
// } else {
// // Unix-like系统使用bash
// processBuilder.command("bash", "-c", panelVariables.getScript());
// }
//
// // 设置工作目录
// if (StringUtils.hasText(localVariables.getWorkDir())) {
// // Windows系统路径处理
// String workDirValue = localVariables.getWorkDir();
// if (os.contains("win")) {
// // 确保使用Windows风格的路径分隔符
// workDirValue = workDirValue.replace("/", "\\");
// // 如果路径以\开头去掉第一个\
// if (workDirValue.startsWith("\\")) {
// workDirValue = workDirValue.substring(1);
// }
// }
// File workDirFile = new File(workDirValue);
// if (!workDirFile.exists()) {
// workDirFile.mkdirs();
// }
// processBuilder.directory(workDirFile);
// }
//
// // 设置环境变量
// if (localVariables.getEnv() != null) {
// processBuilder.environment().putAll(localVariables.getEnv());
// }
//
// // 执行命令
// log.info("执行shell脚本: {}", panelVariables.getScript());
// Process process = processBuilder.start();
//
// // 创建线程池处理输出
// ExecutorService executorService = Executors.newFixedThreadPool(2);
//
// // 处理标准输出
// Future<?> outputFuture = executorService.submit(() ->
// processInputStream(process.getInputStream(), processInstanceId, NodeLogTypeEnums.STDOUT));
//
// // 处理错误输出
// Future<?> errorFuture = executorService.submit(() ->
// processInputStream(process.getErrorStream(), processInstanceId, NodeLogTypeEnums.STDERR));
//
// // 等待进程完成
// int exitCode = process.waitFor();
//
// // 等待输出处理完成
// outputFuture.get(5, TimeUnit.SECONDS);
// errorFuture.get(5, TimeUnit.SECONDS);
//
// // 关闭线程池
// executorService.shutdown();
//
// // 设置最终结果
// StringBuilder finalOutput = outputMap.get(processInstanceId);
// StringBuilder finalError = errorMap.get(processInstanceId);
//
// execution.setVariable("shellOutput", finalOutput.toString());
// execution.setVariable("shellError", finalError.toString());
// execution.setVariable("shellExitCode", exitCode);
//
// // 清理缓存
// outputMap.remove(processInstanceId);
// errorMap.remove(processInstanceId);
//
// if (exitCode != 0) {
// log.error("Shell脚本执行失败退出码: {}", exitCode);
// execution.setVariable("errorDetail", "Shell脚本执行失败退出码: " + exitCode);
// throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, "Shell脚本执行失败退出码: " + exitCode);
// }
// log.info("Shell脚本执行成功");
// log.debug("脚本输出: {}", finalOutput);
//
// } catch (Exception e) {
// log.error("Shell脚本执行失败", e);
// throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, e.getMessage());
// }
}
private void processInputStream(InputStream inputStream, String processInstanceId, NodeLogTypeEnums logType) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = reader.readLine()) != null) {
// 发布日志事件
eventPublisher.publishEvent(new ShellLogEvent(processInstanceId, line, logType));
// 同时保存到StringBuilder中
if (logType == NodeLogTypeEnums.STDOUT) {
StringBuilder output = outputMap.get(processInstanceId);
synchronized (output) {
output.append(line).append("\n");
}
// log.info("Shell output: {}", line);
} else {
StringBuilder error = errorMap.get(processInstanceId);
synchronized (error) {
error.append(line).append("\n");
}
// log.error("Shell error: {}", line);
}
}
} catch (IOException e) {
log.error("Error reading process output", e);
}
}
}

View File

@ -11,26 +11,20 @@ import org.flowable.engine.delegate.BpmnError;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
* Shell脚本任务的委派者实现
*/
@Slf4j
@Component
public class ShellTaskDelegate extends BaseTaskDelegate<ScriptNodePanelVariables, ScriptNodeLocalVariables> {
public class ShellNodeDelegate extends BaseNodeDelegate<ScriptNodePanelVariables, ScriptNodeLocalVariables> {
@Resource
private ApplicationEventPublisher eventPublisher;

View File

@ -0,0 +1,19 @@
package com.qqchen.deploy.backend.workflow.dto.definition.node.localVariables;
import com.qqchen.deploy.backend.workflow.annotation.SchemaProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class JenkinsNodeLocalVariables extends BaseNodeLocalVariables {
@SchemaProperty(
title = "委派者",
description = "委派者",
defaultValue = "${jenkinsNodeDelegate}",
required = true
)
private String delegate;
}

View File

@ -11,7 +11,7 @@ public class ScriptNodeLocalVariables extends BaseNodeLocalVariables {
@SchemaProperty(
title = "委派者",
description = "委派者",
defaultValue = "${shellTaskDelegate}",
defaultValue = "${shellNodeDelegate}",
required = true
)
private String delegate;

View File

@ -0,0 +1,66 @@
package com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables;
import com.qqchen.deploy.backend.workflow.annotation.SchemaProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 脚本执行器配置
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class JenkinsNodePanelVariables extends BaseNodePanelVariables {
@SchemaProperty(
title = "脚本代码",
description = "脚本代码",
required = true
)
private String script;
/**
* 脚本语言
*/
@SchemaProperty(
title = "脚本语言",
description = "脚本语言类型",
required = true,
enumValues = {"shell", "python", "javascript", "groovy"},
enumNames = {"Shell脚本 (已支持)", "Python脚本 (开发中)", "JavaScript脚本 (开发中)", "Groovy脚本 (开发中)"},
defaultValue = "shell"
)
private String language;
/**
* 解释器路径
*/
@SchemaProperty(
title = "解释器路径",
description = "脚本解释器的路径,例如:/bin/bash, /usr/bin/python3",
required = true
)
private String interpreter;
/**
* 成功退出码
*/
@SchemaProperty(
title = "成功标识",
description = "脚本执行成功时的标识",
required = true
)
private Integer successExitCode;
/**
* 支持的脚本语言列表
*/
@SchemaProperty(
title = "支持的脚本语言",
enumValues = {"shell", "python", "javascript", "groovy"}
)
private List<String> supportedLanguages;
}

View File

@ -35,21 +35,50 @@ VALUES
-- 初始化权限管理数据
-- --------------------------------------------------------------------------------------
-- 初始化菜单数据
-- --------------------------------------------------------------------------------------
-- 初始化权限管理数据
-- --------------------------------------------------------------------------------------
-- --------------------------------------------------------------------------------------
-- 初始化权限管理数据
-- --------------------------------------------------------------------------------------
-- 先清理已有数据
DELETE FROM sys_menu;
INSERT INTO sys_menu (id, name, path, component, icon, type, parent_id, sort, hidden, enabled, create_by, create_time, version, deleted)
VALUES
-- 首页
(99, '首页', '/dashboard', '/src/pages/dashboard/index', 'DashboardOutlined', 2, NULL, 0, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 系统管理
(1, '系统管理', '/system', 'LAYOUT', 'setting', 1, NULL, 1, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
(1, '系统管理', '/system', 'Layout', 'SettingOutlined', 1, NULL, 1, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 用户管理
(2, '用户管理', '/system/user', '/System/User/index', 'user', 2, 1, 10, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
(2, '用户管理', '/system/user', '/src/pages/system/user/index', 'UserOutlined', 2, 1, 10, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 角色管理
(3, '角色管理', '/system/role', '/System/Role/index', 'peoples', 2, 1, 20, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
(3, '角色管理', '/system/role', '/src/pages/system/role/index', 'TeamOutlined', 2, 1, 20, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 菜单管理
(4, '菜单管理', '/system/menu', '/System/Menu/index', 'tree-table', 2, 1, 30, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
(4, '菜单管理', '/system/menu', '/src/pages/system/menu/index', 'MenuOutlined', 2, 1, 30, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 部门管理
(5, '部门管理', '/system/department', '/System/Department/index', 'tree', 2, 1, 40, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
(5, '部门管理', '/system/department', '/src/pages/system/department/index', 'ApartmentOutlined', 2, 1, 40, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 三方系统
(70, '三方系统', '/system/external', '/System/External/index', 'api', 2, 1, 70, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE);
(70, '三方系统', '/system/external', '/src/pages/system/external/index', 'ApiOutlined', 2, 1, 70, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 工作流管理
(100, '工作流管理', '/workflow', 'Layout', 'DeploymentUnitOutlined', 1, NULL, 2, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 工作流设计
(101, '工作流设计', '/workflow/definition', '/src/pages/workflow/definition/index', 'EditOutlined', 2, 100, 10, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 工作流实例
(102, '工作流实例', '/workflow/instance', '/src/pages/workflow/instance/index', 'BranchesOutlined', 2, 100, 20, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 节点管理
(103, '节点管理', '/workflow/node-design', '/src/pages/workflow/nodedesign/design/index', 'ControlOutlined', 2, 100, 40, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 应用管理
(200, '应用管理', '/application', 'Layout', 'AppstoreOutlined', 1, NULL, 3, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 应用列表
(201, '应用列表', '/application/list', '/src/pages/application/list/index', 'UnorderedListOutlined', 2, 200, 10, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
-- 环境管理
(202, '环境管理', '/application/environment', '/src/pages/application/environment/index', 'CloudOutlined', 2, 200, 20, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE);
-- 初始化角色数据
INSERT INTO sys_role (id, create_time, code, name, type, description, sort)