JAVA Spring

스프링 파일 업로드

neal89 2025. 4. 20. 10:50
## 📁 스프링 파일 업로드

파일 업로드 기능은 웹 애플리케이션 개발에서 빼놓을 수 없는 중요한 요소 중 하나입니다. 이번 포스팅에서는 HTML 폼을 통한 파일 업로드 방식의 기본적인 이해부터 서블릿에서의 접근 방식, 그리고 스프링 프레임워크가 제공하는 강력한 `MultipartFile` 활용법까지 자세히 알아보겠습니다.

✅ **1. 파일 업로드, 어떤 방식으로 이루어질까? (`application/x-www-form-urlencoded` vs `multipart/form-data`)**

| 구분                         | `application/x-www-form-urlencoded` | `multipart/form-data`             |
| :--------------------------- | :-------------------------------- | :------------------------------ |
| **주요 목적** | 텍스트 데이터 전송                | 텍스트 및 **파일 데이터 전송** |
| **Content-Type** | `application/x-www-form-urlencoded` | `multipart/form-data; boundary=...` |
| **데이터 형태** | URL 인코딩된 텍스트 형식           | 여러 부분(part)으로 구성             |
| **파일 전송** | ❌ 부적합                         | ✅ 적합                         |
| **예시** | 간단한 폼 전송 (로그인, 검색)      | 파일 업로드 폼                  |
| **🔎 핵심!** |                                   | **파일 업로드 시 반드시 `multipart/form-data` 사용!** |

📝 **쉽게 풀어보는 파일 전송 방식:**

웹 페이지에서 폼을 통해 데이터를 서버로 보낼 때, 브라우저는 데이터를 특정한 형식으로 변환하여 HTTP 요청의 본문에 담아 전송합니다. 파일 업로드와 관련된 주요 방식은 두 가지입니다.

* **`application/x-www-form-urlencoded`**: 마치 편지에 내용을 적어 봉투에 담는 것과 같습니다. 폼의 각 필드 이름과 값을 텍스트 형태로 변환하여 `=`으로 연결하고, 여러 필드는 `&`로 이어붙여 하나의 긴 텍스트 문자열로 만듭니다. 이 방식은 간단한 텍스트 데이터 전송에는 효율적이지만, 파일과 같은 바이너리 데이터를 텍스트로 변환하는 과정에서 데이터 손실이 발생하거나 용량이 커져 파일 업로드에는 적합하지 않습니다.

* **`multipart/form-data`**: 택배 상자에 여러 종류의 물건을 각각 포장하여 담는 것에 비유할 수 있습니다. 폼 데이터를 여러 개의 "부분(part)"으로 나누어 전송하며, 각 부분은 데이터의 종류와 이름을 명시하는 헤더와 실제 데이터를 포함합니다. 파일을 그대로 담아서 보낼 수 있기 때문에 파일 업로드에 최적화되어 있으며, 텍스트 데이터와 파일을 동시에 전송하는 것도 가능합니다. 이때, 각 부분을 구분하기 위해 `boundary`라는 특별한 구분자를 사용합니다.

**💻 간단한 텍스트 폼 전송 예시 (`application/x-www-form-urlencoded`)**

```html
<form action="/save" method="post">
    <input type="text" name="username" value="티스토리">
    <input type="text" name="article" value="오늘의 포스팅 내용">
    <button type="submit">저장</button>
</form>

➡️ 서버로 전송되는 데이터 형태: username=%ED%8B%B0%EC%8A%A4%ED%86%A0%EB%A6%AC&article=%EC%98%A4%EB%8A%98%EC%9D%98+%ED%8F%AC%EC%8A%A4%ED%8C%85+%EB%82%B4%EC%9A%A9 (URL 인코딩됨)

🔑 핵심: 파일 업로드 시에는 반드시 <form> 태그에 enctype="multipart/form-data" 속성을 추가해야 한다는 점을 잊지 마세요!

☕️ 2. 서블릿으로 multipart 데이터 다루기 (기초)

서블릿 환경에서는 HttpServletRequest 객체의 getParts() 메서드를 통해 multipart/form-data로 전송된 데이터를 개별 Part 객체로 접근할 수 있습니다. 각 Part 객체를 통해 파일명, 파일 크기, 입력 스트림을 얻어와 직접 파일 저장 로직을 구현해야 합니다.

Collection<Part> parts = request.getParts();
for (Part part : parts) {
    String fileName = part.getSubmittedFileName(); // 업로드된 파일명 추출
    if (fileName != null && !fileName.isEmpty()) {
        part.write(fileDir + fileName); // 서버에 파일 저장
    } else {
        String formFieldName = part.getName(); // 텍스트 필드 이름 추출
        String formFieldValue = request.getParameter(formFieldName); // 텍스트 필드 값 추출
        System.out.println(formFieldName + ": " + formFieldValue);
    }
}

⚠️ 주의: 서블릿에서 직접 multipart 데이터를 처리하는 것은 번거롭고, 보안 및 예외 처리 등 고려해야 할 사항이 많아 실제 서비스 환경에서는 스프링의 MultipartFile 활용을 권장합니다.

🍃 3. 스프링 MultipartFile로 쉽고 강력하게 파일 업로드하기

스프링 프레임워크는 파일 업로드를 위한 MultipartFile이라는 편리한 인터페이스를 제공합니다. 컨트롤러에서 @RequestParam 어노테이션을 사용하여 폼에서 전송된 파일을 MultipartFile 객체로 간단하게 받을 수 있습니다.

✅ 3.1. 단일 파일 업로드 예제

🖼 HTML 폼

<form action="/upload" method="post" enctype="multipart/form-data">
    <label for="itemName">상품명:</label>
    <input type="text" name="itemName" id="itemName"><br><br>
    <label for="file">업로드 파일:</label>
    <input type="file" name="file" id="file"><br><br>
    <button type="submit">파일 업로드</button>
</form>

💻 스프링 컨트롤러

@Controller
@PostMapping("/upload")
public String upload(@RequestParam String itemName,
                     @RequestParam MultipartFile file) throws IOException {
    if (!file.isEmpty()) {
        String uploadDir = "/path/to/upload/directory/"; // 실제 업로드 경로 설정
        String originalFilename = file.getOriginalFilename(); // 원본 파일명
        String filePath = uploadDir + originalFilename;

        file.transferTo(new File(filePath)); // 파일 저장

        System.out.println("상품명: " + itemName);
        System.out.println("업로드된 파일명: " + originalFilename);
        System.out.println("저장 경로: " + filePath);
    }
    return "upload_result"; // 업로드 완료 페이지
}

📦 3.2. 여러 파일 한 번에 업로드하기

🖼 HTML 폼

<form action="/uploadFiles" method="post" enctype="multipart/form-data">
    <label for="itemName">상품명:</label>
    <input type="text" name="itemName" id="itemName"><br><br>
    <label for="files">업로드 파일 (여러 개 선택 가능):</label>
    <input type="file" name="files" id="files" multiple><br><br>
    <button type="submit">여러 파일 업로드</button>
</form>

💻 스프링 컨트롤러

@Controller
@PostMapping("/uploadFiles")
public String uploadFiles(@RequestParam String itemName,
                          @RequestParam List<MultipartFile> files) throws IOException {
    String uploadDir = "/path/to/upload/directory/"; // 실제 업로드 경로 설정

    System.out.println("상품명: " + itemName);

    for (MultipartFile file : files) {
        if (!file.isEmpty()) {
            String originalFilename = file.getOriginalFilename();
            String filePath = uploadDir + originalFilename;
            file.transferTo(new File(filePath));
            System.out.println("업로드된 파일명: " + originalFilename + ", 저장 경로: " + filePath);
        }
    }
    return "upload_result"; // 업로드 완료 페이지
}

⚙️ 스프링 부트 설정 (application.properties 또는 application.yml)

spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=50MB
  • spring.servlet.multipart.max-file-size: 개별 파일의 최대 업로드 크기를 설정합니다.
  • spring.servlet.multipart.max-request-size: 한번의 요청으로 업로드할 수 있는 총 파일 크기의 합을 설정합니다.
    ```

'JAVA Spring' 카테고리의 다른 글

Spring Type Conversion & Formatter  (0) 2025.04.11
API Exception Handling  (0) 2025.04.11
Error Handling & Error Pages  (0) 2025.04.11
Servlet Filter vs Spring Interceptor  (0) 2025.04.11
Cookie and Session  (0) 2025.04.11