- src
- main
- java
- com
- example
- judge
- JudgeApplication.java
- controller
- JudgeController.java
- service
- JudgeService.java
- model
- Submission.java
- util
- CodeExecutor.java
- resources/static
- input.txt
- output.txt

{ user : "파송송", answer : "some awesome code" }
answer => Soultion.java 형태로 저장
정답 여부 판별과 채점 모듈 구현
시간을 초과한 경우에는 작업을 중단
상황에 맞는 상태 코드 리턴 (컴파일 에러 등..)
정답 데이터를 제출하고 원하는 리턴이 나오는지 검증
package com.example.judge;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CodingtestGradeApplication {
public static void main(String[] args) {
SpringApplication.run(CodingtestGradeApplication.class, args);
}
}
package com.example.judge.controller;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.judge.model.Submission;
import com.example.judge.service.JudgeService;
@RestController
public class JudgeController {
@Autowired
private JudgeService judgeService;
@PostMapping("/submit")
public ResponseEntity<?> submitCode(@RequestBody Submission submission) throws IOException{
System.out.println(submission.getAnswer());
String result = judgeService.judge(submission);
return ResponseEntity.ok(result);
}
}
package com.example.judge.model;
public class Submission {
private String user;
private String answer;
// getters and setters
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
}
package com.example.judge.service;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.springframework.stereotype.Service;
import com.example.judge.model.Submission;
import com.example.judge.util.CodeExecutor;
@Service
public class JudgeService {
public String judge(Submission submission) throws IOException {
String code = submission.getAnswer();
File file = new File("Solution.java");
String expectedOutputPath = "src/main/resources/static/output.txt";
try(FileWriter writer = new FileWriter(file)){
writer.write(code);
}catch(IOException e ) {
e.printStackTrace();
return "파일 쓰기 오류";
}
String result = CodeExecutor.compileAndRun(file);
// 예상 출력과 실제 출력을 비교
String expectedOutput = new String(java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(expectedOutputPath))).trim();
if (result.equals(expectedOutput)) {
return "정답입니다.";
} else {
return "틀렸습니다. 예상 출력: " + expectedOutput + " 실제 출력: " + result;
}
}
}
package com.example.judge.util;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.concurrent.*;
public class CodeExecutor {
public static String compileAndRun(File file) {
try {
// 외부 프로세스 실행
// - Runtime.getRuntime().exec(command) 메서드는 주어진 명령어 command를 실행시키기 위한 외부 프로세스를
// 생성.
// command는 실행하려는 외부 프로그램의 명령어와 옵션을 포함한 문자열. 예를 들어, "javac Solution.java"와 같이 자바
// 컴파일러를 실행하는 명령어.
// - 여기서는 javac 명령어를 실행시키기 위해 사용.
// - file.getName()은 file 객체에서 파일의 이름을 가져오는 메서드.
// - 따라서 위 코드에서는 Solution.java 파일을 컴파일하는 명령어가 실행.
Process compileProcess = Runtime.getRuntime().exec("javac " + file.getName());
String inputPath = "src/main/resources/static/input.txt";
// 외부 프로세스가 종료될 때까지 현재 스레드를 차단하고 기다린다
compileProcess.waitFor();
// compileProcess.exitValue() 메서드는 외부 프로세스의 종료 코드(exit code)를 반환
// 일반적으로 0은 성공을 나타내고, 그 외의 값은 실패를 나타냄
if (compileProcess.exitValue() != 0) {
return "컴파일 오류";
}
// 비동기 실행
Callable<String> task = () -> {
try {
Process runProcess = Runtime.getRuntime().exec("java " + file.getName().replace(".java", ""));
// input.txt의 내용을 실행 프로세스에 전달
BufferedWriter stdInput = new BufferedWriter(new OutputStreamWriter(runProcess.getOutputStream()));
BufferedReader inputFile = new BufferedReader(new FileReader(inputPath));
String inputLine;
while ((inputLine = inputFile.readLine()) != null) {
stdInput.write(inputLine);
stdInput.newLine();
}
stdInput.close();
BufferedReader stdOutput = new BufferedReader(new InputStreamReader(runProcess.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(runProcess.getErrorStream()));
String s;
StringBuilder output = new StringBuilder();
while ((s = stdOutput.readLine()) != null) {
output.append(s).append("\n");
}
while ((s = stdError.readLine()) != null) {
output.append(s).append("\n");
}
runProcess.waitFor();
if (runProcess.exitValue() != 0) {
return "런타임 오류: " + output.toString();
}
return output.toString().trim();
} catch (Exception e) {
e.printStackTrace();
return "예외 발생: " + e.getMessage();
}
};
// Executors 클래스를 사용하여 ExecutorService 인스턴스 생성
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(task);
String result;
try {
result = future.get(5, TimeUnit.SECONDS); // 5초로 제한 시간 설정
} catch (TimeoutException e) {
future.cancel(true);
result = "시간 초과";
} finally {
executor.shutdown();
}
return result;
} catch (Exception e) {
e.printStackTrace();
return "예외 발생: " + e.getMessage();
}
}
}
테스트를 위해 단순한 answer를 넣었다

