首页接口重构

This commit is contained in:
2026-04-13 17:13:00 +08:00
parent 75de04086c
commit 91327f14fc
3 changed files with 1044 additions and 116 deletions

View File

@@ -5,93 +5,32 @@ import com.jeesite.modules.apps.Module.ContainerInfo;
import com.jeesite.modules.apps.Module.DockerResult;
import com.jeesite.modules.biz.entity.MySftpAccounts;
import java.io.*;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
/**
* Docker 容器管理工具
* <p>
* 通过 SSH 连接主机,基于 MySftpAccounts 凭证执行 docker 命令。
* 支持密码认证和私钥认证。
*/
public class DockerUtil {
private static final int SSH_TIMEOUT = 30000;
public static DockerResult start(MySftpAccounts accounts, String containerId) {
return exec(accounts, "docker start " + containerId);
}
public static DockerResult stop(MySftpAccounts accounts, String containerId) {
return exec(accounts, "docker stop " + containerId);
}
public static DockerResult restart(MySftpAccounts accounts, String containerId) {
return exec(accounts, "docker restart " + containerId);
}
public static DockerResult getLogs(MySftpAccounts accounts, String containerId,
int tail, boolean timestamps) {
String cmd = "docker logs" + (timestamps ? " -t" : "")
+ " --tail " + tail + " " + containerId;
return exec(accounts, cmd);
}
public static DockerResult list(MySftpAccounts accounts, boolean all) {
return exec(accounts, all ? "docker ps -a" : "docker ps");
}
public static DockerResult inspect(MySftpAccounts accounts, String containerId) {
return exec(accounts, "docker inspect " + containerId);
}
public static List<ContainerInfo> listContainers(MySftpAccounts accounts, boolean all) {
List<ContainerInfo> list = new ArrayList<>();
String cmd = (all ? "docker ps -a" : "docker ps")
+ " --format \"{{.ID}}|{{.Image}}|{{.Command}}|{{.CreatedAt}}|{{.Status}}|{{.Ports}}|{{.Names}}\"";
DockerResult r = exec(accounts, cmd);
if (!r.isSuccess()) {
return new ArrayList<>();
}
for (String line : r.getOutput().split("\n")) {
if (line.trim().isEmpty()) continue;
String[] p = line.split("\\|");
if (p.length < 2) continue;
ContainerInfo info = new ContainerInfo();
info.setContainerId(p[0].trim());
info.setImage(p[1].trim());
info.setCommand(p.length > 2 ? p[2].trim() : "");
info.setCreated(p.length > 3 ? p[3].trim() : "");
info.setStatus(p.length > 4 ? p[4].trim() : "");
info.setPorts(p.length > 5 ? p[5].trim() : "");
info.setNames(p.length > 6 ? p[6].trim() : "");
info.setAccountId(accounts.getAccountId());
list.add(info);
}
return list;
}
public static DockerResult exec(MySftpAccounts accounts, String command) {
private static String runCommand(MySftpAccounts account, String cmd) {
JSch jsch = new JSch();
Session session = null;
ChannelExec channel = null;
try {
int port = accounts.getHostPort() != null ? accounts.getHostPort() : 22;
session = jsch.getSession(accounts.getUsername(), accounts.getHostIp(), port);
int port = account.getHostPort() == null ? 22 : account.getHostPort();
session = jsch.getSession(account.getUsername(), account.getHostIp(), port);
session.setTimeout(SSH_TIMEOUT);
if ("key".equalsIgnoreCase(accounts.getAuthType())
&& accounts.getPrivateKey() != null && !accounts.getPrivateKey().isEmpty()) {
jsch.addIdentity("temp",
accounts.getPrivateKey().getBytes(StandardCharsets.UTF_8),
null, null);
} else if (accounts.getPassword() != null && !accounts.getPassword().isEmpty()) {
session.setPassword(accounts.getPassword());
// 认证
if ("key".equalsIgnoreCase(account.getAuthType()) && account.getPrivateKey() != null) {
jsch.addIdentity("temp", account.getPrivateKey().getBytes(StandardCharsets.UTF_8), null, null);
} else {
return DockerResult.fail("SSH 认证信息不完整:缺少密码或私钥");
session.setPassword(account.getPassword());
}
Hashtable<String, String> config = new Hashtable<>();
@@ -99,46 +38,85 @@ public class DockerUtil {
session.setConfig(config);
session.connect(SSH_TIMEOUT);
// 执行命令
channel = (ChannelExec) session.openChannel("exec");
String finalCmd = (accounts.getRootPath() != null && !accounts.getRootPath().isEmpty())
? "cd " + accounts.getRootPath() + " && " + command
: command;
channel.setCommand(finalCmd);
channel.setInputStream(null);
String command = account.getRootPath() != null && !account.getRootPath().isEmpty()
? "cd " + account.getRootPath() + " && " + cmd
: cmd;
channel.setCommand(command);
InputStream in = channel.getInputStream();
ByteArrayOutputStream errOut = new ByteArrayOutputStream();
channel.setExtOutputStream(errOut);
channel.connect();
StringBuilder outBuilder = new StringBuilder();
if (in != null) {
byte[] buf = new byte[4096];
int n;
while ((n = in.read(buf)) != -1) {
outBuilder.append(new String(buf, 0, n, StandardCharsets.UTF_8));
}
// 读取输出
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
int len;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
String stdout = outBuilder.toString().trim();
String stderr = errOut.toString(StandardCharsets.UTF_8).trim();
int exitCode = channel.getExitStatus();
return out.toString(StandardCharsets.UTF_8).trim();
if (exitCode == 0) {
return DockerResult.ok(stdout);
} else {
return DockerResult.fail("命令执行失败,退出码: " + exitCode,
stderr.isEmpty() ? stdout : stderr);
}
} catch (JSchException e) {
return DockerResult.fail("SSH 连接失败: " + e.getMessage());
} catch (IOException e) {
return DockerResult.fail("IO 异常: " + e.getMessage());
} catch (Exception e) {
return null;
} finally {
if (channel != null && channel.isConnected()) channel.disconnect();
if (session != null && session.isConnected()) session.disconnect();
if (channel != null) channel.disconnect();
if (session != null) session.disconnect();
}
}
}
public static List<ContainerInfo> listContainers(MySftpAccounts accounts, boolean all) {
List<ContainerInfo> list = new ArrayList<>();
String cmd = (all ? "docker ps -a" : "docker ps")
+ " --format \"{{.ID}}|{{.Image}}|{{.Command}}|{{.CreatedAt}}|{{.Status}}|{{.Ports}}|{{.Names}}\"";
String output = runCommand(accounts, cmd);
if (output == null || output.isBlank()) return list;
for (String line : output.split("\\R")) {
if (line.isBlank()) continue;
String[] arr = line.split("\\|");
ContainerInfo info = new ContainerInfo();
info.setContainerId(arr.length > 0 ? arr[0].trim() : "");
info.setImage(arr.length > 1 ? arr[1].trim() : "");
info.setCommand(arr.length > 2 ? arr[2].trim() : "");
info.setCreated(arr.length > 3 ? arr[3].trim() : "");
info.setStatus(arr.length > 4 ? arr[4].trim() : "");
info.setPorts(arr.length > 5 ? arr[5].trim() : "");
info.setNames(arr.length > 6 ? arr[6].trim() : "");
info.setAccountId(accounts.getAccountId());
list.add(info);
}
return list;
}
public static DockerResult start(MySftpAccounts accounts, String containerId) {
String res = runCommand(accounts, "docker start " + containerId);
return res != null ? DockerResult.ok(res) : DockerResult.fail("执行失败");
}
public static DockerResult stop(MySftpAccounts accounts, String containerId) {
String res = runCommand(accounts, "docker stop " + containerId);
return res != null ? DockerResult.ok(res) : DockerResult.fail("执行失败");
}
public static DockerResult restart(MySftpAccounts accounts, String containerId) {
String res = runCommand(accounts, "docker restart " + containerId);
return res != null ? DockerResult.ok(res) : DockerResult.fail("执行失败");
}
public static DockerResult getLogs(MySftpAccounts accounts, String containerId, int tail, boolean timestamps) {
String cmd = "docker logs " + (timestamps ? "-t " : "") + "--tail " + tail + " " + containerId;
String res = runCommand(accounts, cmd);
return res != null ? DockerResult.ok(res) : DockerResult.fail("获取日志失败");
}
public static DockerResult list(MySftpAccounts accounts, boolean all) {
String res = runCommand(accounts, all ? "docker ps -a" : "docker ps");
return res != null ? DockerResult.ok(res) : DockerResult.fail("获取列表失败");
}
public static DockerResult inspect(MySftpAccounts accounts, String containerId) {
String res = runCommand(accounts, "docker inspect " + containerId);
return res != null ? DockerResult.ok(res) : DockerResult.fail("查询详情失败");
}
}

View File

@@ -36,12 +36,12 @@ server:
#========= Database settings ==========#
#======================================#
jdbc:
jdbc:
type: mysql
driver: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.31.182:13306/system?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
username: dream
password: info_dream
url: jdbc:mysql://127.0.0.1:13306/my_app?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
username: root
password: root_dream
testSql: SELECT 1
encrypt:
username: false
@@ -156,7 +156,7 @@ web:
addPathPatterns: >
${frontPath}/**
excludePathPatterns: ~
core:
core:
enabled: true
# 在线API文档