package com.guwan.backend.controller; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.CreateContainerResponse; import com.github.dockerjava.api.command.ExecCreateCmdResponse; import com.github.dockerjava.api.model.*; import com.github.dockerjava.core.DockerClientBuilder; import com.github.dockerjava.core.command.ExecStartResultCallback; import com.github.dockerjava.httpclient5.ApacheDockerHttpClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.github.dockerjava.api.DockerClient; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.concurrent.TimeUnit; @RestController @RequestMapping("/api/common") public class DockerController { private final DockerClient dockerClient; @Autowired public DockerController(DockerClient dockerClient) { this.dockerClient = dockerClient; } @GetMapping("/docker-info") public String getDockerInfo() { Info info = dockerClient.infoCmd().exec(); // 获取 Docker 守护进程的信息 System.out.println("info = " + info); return info.toString(); // 将 Docker 信息返回到 HTTP 响应 } /** * 获取镜像列表 * * @param * @return */ @GetMapping("/imageList") public List imageList() { List imageList = dockerClient.listImagesCmd().withShowAll(true).exec(); System.out.println("imageList = " + imageList); return imageList; } @GetMapping("/listContainers") public List listContainers() { List exec = dockerClient.listContainersCmd().exec(); exec.forEach(container -> System.out.println("name = " + Arrays.toString(container.getNames()))); return exec; } @GetMapping("/create") public void create() throws IOException { String javaFilePath = "D:\\00_桌面\\demo.java"; // 这里填入 Java 文件路径 File javaFile = new File(javaFilePath); Path localDir = Files.createTempDirectory("docker-java"); File localJavaFile = new File(localDir.toFile(), "Main.java"); Files.copy(javaFile.toPath(), localJavaFile.toPath()); String imageName = "openjdk:8"; // 使用官方 OpenJDK 11 镜像 HostConfig hostConfig = HostConfig.newHostConfig() .withBinds(new Bind(localDir.toString(), new com.github.dockerjava.api.model.Volume("/java"))); // 绑定挂载 // 启动容器 String containerId = dockerClient.createContainerCmd(imageName) .withCmd("bash", "-c", "javac /java/Main.java && java -cp /java Main && tail -f /dev/null") .withHostConfig(hostConfig) .withName("java-app-container") .exec().getId(); dockerClient.startContainerCmd(containerId).exec(); System.out.println("Container started. Check the output in Docker."); } private static final String IMAGE_NAME = "gcc:latest"; private static final int TIMEOUT_SECONDS = 10; /* @GetMapping("/testCpp") public void testCpp() throws IOException { System.out.println("dockerClient = " + dockerClient); try { // 创建容器 CreateContainerResponse container = dockerClient.createContainerCmd(IMAGE_NAME) .withTty(true) .withWorkingDir("/app") .exec(); String containerId = container.getId(); dockerClient.startContainerCmd(containerId).exec(); // 写入代码(使用cat和here-doc避免转义问题) String cppCode = "#include \n" + "int main() { std::cout << \"Hello Docker!\\n\"; return 0; }"; execCommand(dockerClient, containerId, "sh -c 'cat > /app/main.cpp < dockerClient.removeContainerCmd(c.getId()).withForce(true).exec());*//* //dockerClient.close(); } } private static String execCommand(DockerClient dockerClient, String containerId, String command) throws Exception { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ExecCreateCmdResponse exec = dockerClient.execCreateCmd(containerId) .withCmd("sh", "-c", command) .withAttachStdout(true) .withAttachStderr(true) .exec(); dockerClient.execStartCmd(exec.getId()) .exec(new ExecStartResultCallback(outputStream, System.err)) .awaitCompletion(TIMEOUT_SECONDS, TimeUnit.SECONDS); return outputStream.toString().trim(); }*/ @GetMapping("/judge") public ResponseEntity> judgeCode() { Map result = new HashMap<>(); List testCases = new ArrayList<>(); // 真实用户提交的C++代码(示例:A+B问题) String cppCode = "#include \n" + "using namespace std;\n" + "int main() {\n" + " int a, b;\n" + " cin >> a >> b;\n" + " cout << a + b << endl;\n" + " return 0;\n" + "}"; // 定义测试用例 testCases.add(new TestCase("1 2", "3")); // 基础测试 testCases.add(new TestCase("-5 8", "3")); // 负数测试 testCases.add(new TestCase("1000000 2000000", "3000000")); // 大数测试 testCases.add(new TestCase("", "")); // 错误输入测试 testCases.add(new TestCase("3", "")); // 不完整输入测试 String containerId = null; try { // 创建容器(使用官方GCC镜像) CreateContainerResponse container = dockerClient.createContainerCmd("gcc:latest") .withTty(true) .withWorkingDir("/app") .withHostConfig(HostConfig.newHostConfig() .withMemory(100 * 1024 * 1024L) // 限制内存100MB .withCpuCount(1L)) // 限制1核CPU .exec(); containerId = container.getId(); dockerClient.startContainerCmd(containerId).exec(); // 1. 写入代码文件 execCommand(containerId, "mkdir -p /app", 10); execCommand(containerId, "bash -c 'cat > /app/main.cpp <> caseResults = new ArrayList<>(); for (int i = 0; i < testCases.size(); i++) { TestCase testCase = testCases.get(i); Map caseResult = new HashMap<>(); caseResult.put("case_id", i + 1); caseResult.put("input", testCase.input); caseResult.put("expected", testCase.expectedOutput); try { // 写入输入文件 execCommand(containerId, "bash -c 'cat > /app/input.txt <&1", // 捕获标准错误 3 // 超时3秒 ); // 标准化输出处理 actualOutput = actualOutput.trim() .replaceAll("\r\n", "\n") .replaceAll("[ \\t]+", " "); // 结果对比 boolean isPassed = actualOutput.equals(testCase.expectedOutput); caseResult.put("status", isPassed ? "passed" : "failed"); caseResult.put("actual", actualOutput); // 特殊错误类型检测 if (actualOutput.contains("Timeout")) { caseResult.put("status", "time_limit_exceeded"); } else if (actualOutput.contains("runtime error")) { caseResult.put("status", "runtime_error"); } else if (actualOutput.isEmpty()) { caseResult.put("status", "no_output"); } } catch (Exception e) { caseResult.put("status", "system_error"); caseResult.put("message", e.getMessage()); } caseResults.add(caseResult); } result.put("status", "completed"); result.put("cases", caseResults); result.put("pass_count", caseResults.stream() .filter(c -> "passed".equals(c.get("status"))) .count()); } catch (Exception e) { result.put("status", "system_error"); result.put("message", e.getMessage()); } finally { if (containerId != null) { dockerClient.removeContainerCmd(containerId) .withForce(true) .exec(); } } return ResponseEntity.ok(result); } // 辅助方法:执行容器命令 private String execCommand(String containerId, String command, int timeoutSeconds) throws Exception { ByteArrayOutputStream output = new ByteArrayOutputStream(); ExecCreateCmdResponse exec = dockerClient.execCreateCmd(containerId) .withCmd("bash", "-c", command) .withAttachStdout(true) .withAttachStderr(true) .exec(); dockerClient.execStartCmd(exec.getId()) .exec(new ExecStartResultCallback(output, output)) .awaitCompletion(timeoutSeconds, TimeUnit.SECONDS); return output.toString().trim(); } // 测试用例类 static class TestCase { String input; String expectedOutput; public TestCase(String input, String expectedOutput) { this.input = input; this.expectedOutput = expectedOutput; } } }