package kr.itn.itnhub.seed; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.io.InputStream; @RestController public class SeedController { private final SeedService seedService; public SeedController(SeedService seedService) { this.seedService = seedService; } @PostMapping("/api/seed") public SeedReport upload(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { throw new SeedParseException("업로드된 파일이 비어 있습니다."); } // 확장자 검사만으로 파일 형식을 완전히 보장하진 못하지만, 엉뚱한 바이트를 // 곧장 Apache POI에 넘기기 전에 흔한 실수(다른 파일을 잘못 올림)를 걸러내고 // 사람이 이해할 수 있는 메시지로 알려준다. String filename = file.getOriginalFilename(); if (filename == null || !hasAllowedExtension(filename)) { throw new SeedParseException("엑셀 파일(.xlsx 또는 .xlsm)만 업로드할 수 있습니다."); } // IOException을 그대로 던지면 바디 없는 500이 되어 다른 업로드 오류와 다르게 // 취급된다. 스트림 읽기 실패도 사용자가 이해할 수 있는 400으로 통일한다. try (InputStream in = file.getInputStream()) { return seedService.seed(in); } catch (IOException e) { throw new SeedParseException("엑셀 파일을 읽지 못했습니다.", e); } } private static boolean hasAllowedExtension(String filename) { String lower = filename.toLowerCase(); return lower.endsWith(".xlsx") || lower.endsWith(".xlsm"); } }