공부하기/Spring

[SpringBoot] 파일 업로드를 위한 MultipartFile의 처리/동작 방식

다섯자두 2025. 4. 9. 15:20

Spring에서는 ``MultipartFile`` 인터페이스를 통해 파일 업로드 기능을 간편하게 구현할 수 있다.

1. Multipart Upload란?

이미지, 영상, 문서 등의 바이너리 데이터를 업로드하기 위한 HTTP 요청 방식이다.

요청의 ``Content-Type``은 ``multipart/form-data``로 지정되며,

데이터는 요청 본문(Body)에 다음과 같이 구성된다.

  • Header : Content-Type, 필드 이름 등 메타데이터
  • Body: 실제 데이터 (파일, 폼 필드 값 등)

Multipart Upload 요청 예시

POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="username"

Alex_Obregon
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="example.txt"
Content-Type: text/plain

This is the content of the file.
------WebKitFormBoundary--

☑️ Spring에서의 Multipart 처리 방식

Spring Boot에서는 ``MultipartResolver``를 통해 multipart/form-data 요청을 자동으로 감지하고 처리한다.

  • multipart/form-data 타입으로 들어오는 HTTP Request들을 감지한다.
  • 요청 본문을 파싱하고 각 파트를 분리한다.
  • 파일은 ``MultipartFile`` 객체로, 텍스트 필드는 ``@RequestParam`` 등을 통해 주입한다.

예시

예를 들어 다음과 같은 요청이 들어오면,

POST /upload HTTP/1.1
Host: yourserver.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="example.txt"
Content-Type: text/plain

This is the content of the file.
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="description"

This is a test description.
------WebKitFormBoundary7MA4YWxkTrZu0gW--

아래 컨트롤러에서 각 파트들을 파싱해서 받아올 수 있게 한다.

@PostMapping("/upload")
public ResponseEntity<String> handleFileUpload(@RequestParam("file") MultipartFile file,
                                               @RequestParam("description") String description) {
    String fileName = file.getOriginalFilename();
    long fileSize = file.getSize();
    return ResponseEntity.ok("Received file: " + fileName + " (" + fileSize + " bytes) with description: " + description);
}

2. 업로드된 파일의 임시 저장 처리

파일 업로드 시 서버는 해당 파일 데이터를 임시로 저장해야 한다.

이 장소는 설정에 따라 메모리 혹은 디스크 중 하나를 사용한다.

Memory (RAM)

  • 말 그대로 RAM에 임시적으로 저장한다.
  • 파일 크기가 작을 때에는 빠르고 효율적이다.
  • 너무 많은 파일이나 큰 파일이 한꺼번에 들어온다면 작고 소중한 메모리가 터질 수 있다 .. 🥶

Disk-backed Buffers

  • 디스크에 임시 저장해놓는 방식이다. (하드디스크, SSD)
  • 처리 속도는 메모리에 비해 느리지만 안정적이다.

☑️ Spring의 파일 임시 저장소

Spring은 기본적으로 서블릿 컨테이너(Tomcat)가 실행 중인 서버의 디스크 공간을 임시 저장소로 사용한다.

``spring.servlet.multipart.file-size-threshold`` 설정을 통해 파일이 특정 크기 미만일 경우 메모리에, 이상일 경우 디스크에 저장되도록 할 수 있다. (default는 0B로, 모두 디스크에 임시 저장된다.)

  • 이 디스크는 서버가 돌아가고 있는 운영체제의 파일 시스템 내 특정 경로를 의미한다.
  • 요청이 들어오면 디스크에 임시 파일을 만들어 저장하고, 요청이 정상 종료된다면 자동으로 삭제한다.
  • 이 때, 배포 중단, 서버 장애 발생 시 삭제 처리가 되지 않는 경우가 발생할 수 있다.
    • 따라서 임시 경로를 명시하고 주기적으로 정리하는 것이 바람직하다.

☑️ MultipartFile의 동작 원리

Spring은 디스크에 저장된 파일을 ``MultipartFile`` 객체에 매핑한다.

  • 전체 파일 데이터를 Heap 메모리에 올리지 않는다.
  • 파일 이름, 크기, 타입 등 메타데이터만 저장한다.
  • 실제 파일 데이터는 InputStream 등을 통해 접근한다.

마무리

MultipartFile에 대해 처리 방식, 동작 원리까지 정리해봤다. 

막연했던 개념이 정리되니까 속이 시원하다.


🔗 Reference