## 📁 스프링 파일 업로드
파일 업로드 기능은 웹 애플리케이션 개발에서 빼놓을 수 없는 중요한 요소 중 하나입니다. 이번 포스팅에서는 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 |