Spring Boot 동영상/파일 업로드

Rookedsysc·2024년 3월 3일
0
post-thumbnail

🤔 이 게시물을 작성하게 된 계기

새로 시작한 프로젝트에서 동영상 업로드를 구현할 일이 생겨서 구현하는 중에 에러 메시지를 뱉어내지 않고 Unkown Exception이 자꾸 떨어지는 것을 확인했다. 그리고 게시물을 4~5개 정도 서칭하고 지피팅을 30분째 하고 있을 때 로그 레벨을 Debug 까지 낮추고 나서야

Resolved [org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size exceeded]

라는 에러가 발생하고 있는 것을 알게 되었다.
그리고 그 에러 검색을 해보고 나서야 이걸 해결하는 방법에 대해서 알게 되었다.
해결 방법은 application.yaml 파일에 max file size를 설정해주는 것이다.

spring:
  servlet:
    multipart:
      enabled: true
      max-file-size: 10000MB #10GB
      max-request-size: 10000MB # 10GB
      file-size-threshold:

구현

VideoService

@Service
@Slf4j
public class VideoService {
    private static final long MAX_FILE_SIZE = 1024L * 1024L * 1024L * 10L; // 10GBpublic String upload(MultipartFile file) {checkFileTypeOrThrow(file);
        checkFileSizeOrThrow(file);String fileName = UUID.randomUUID() + ".mp4";
        //
        String directoryPath = getDirectoryPath();
        Path filePath = Paths.get(directoryPath, fileName);
        try (OutputStream os = Files.newOutputStream(filePath)) {
            os.write(file.getBytes());
            return fileName;
        } catch (IOException e) {
            log.error("file upload failed", e);
            throw new ApiException(VideoStatus.FILE_UPLOAD_FAILED);
        }
    }/**
     * 파일을 저장할 디렉토리 경로를 가져오고 없다면 생성한다.
     */
    private String getDirectoryPath() {
        String dierctory = "src/main/resources/static/video";
        Path directtoryPath = Paths.get(dierctory);
        if (!Files.exists(directtoryPath)) {
            try {
                Files.createDirectories(directtoryPath);
            } catch (IOException e) {
                log.error("file upload failed", e);
                throw new ApiException(VideoStatus.FILE_UPLOAD_FAILED);
            }
        }
        return directtoryPath.toString();
    }
​
​
    /**
     * 파일 타입이 MP4인지 확인
     */
    private void checkFileTypeOrThrow(MultipartFile file) {
        String contentType = file.getContentType();
        if (!contentType.equals("video/mp4")) {
            throw new ApiException(VideoStatus.INVALID_FILETYPE);
        }
    }
​
​
    /**
     * 파일 사이즈가 10GB 이상인지 확인
     */
    private void checkFileSizeOrThrow(MultipartFile file) {
        long fileSize = file.getSize();
        if (fileSize >= MAX_FILE_SIZE) {
            throw new ApiException(VideoStatus.FILE_SIZE_EXCEEDED);
        }
    }
}

VideoApiController

@RestControllerWithEnvelopPattern
@RequestMapping("/open-api/video")
@RequiredArgsConstructor
public class VideoApiController {
    private final VideoService videoService;@PostMapping("/upload")
    public String saveFile(@RequestParam("file") MultipartFile file) {
        String fileName = videoService.upload(file);
        return fileName;
    }
}

VideoStatus

@Getter
@AllArgsConstructor
public enum VideoStatus implements ApiStatusIfs {
    INVALID_FILETYPE(4400, "지원하지 않는 파일 형식입니다."),
    FILE_SIZE_EXCEEDED(4401, "파일 크기가 최대 크기를 초과하였습니다."),
    FILE_UPLOAD_FAILED(4502, "파일 업로드에 실패하였습니다."),
    EMPTY_FILE(4403, "파일이 비어있습니다."),
    ;
    private final Integer statusCode;
  private final String message;}

코드 설명

VideoController 👉 VideoService로 이어지는 코드이다. VideoService에서는 해당하는 파일이 .mp4 파일인지 확인하고 용량을 확인해서 10GB를 넘는지 확인한다.
그리고 이 검증 구간을 통과하고 나면 getDirectoryPath() 메서드를 통해서 project root를 기준으로 src/main/resources/static/video 폴더가 있는지 확인하고 없다면 생성한 후 그 폴더에 random한 UUID로 파일이름을 지정해서 저장한다.

0개의 댓글