2025. 4. 28. 14:00ㆍ코딩 도구/백엔드 개발 (Backend Development)
스프링 MVC 2 - 파일 업로드 정리
이 글은 인프런 김영한님의 "스프링 MVC 2편 - 백엔드 웹 개발 활용 기술" 강의의 '파일 업로드' 파트를 수강하고 정리한 내용이다.
이 강의에서는 웹 애플리케이션에서 파일 업로드를 처리하는 다양한 방식을 다루며, multipart/form-data의 구조부터 서블릿 API, 그리고 실무에서 널리 사용하는 MultipartFile 기반의 스프링 방식까지 점진적으로 발전시켜 나간다. 특히 마지막 실무 예제를 통해 실제 파일 업로드, 다운로드 구현 시 고려할 부분들을 세세히 배울 수 있다.
정리 및 흐름 요약
- 폼 전송 방식 이해: application/x-www-form-urlencoded vs multipart/form-data
- 서블릿 기반 파일 업로드 처리 (Part API)
- 스프링의 MultipartFile 활용 방식
- 실제 파일 저장 로직과 다운로드 처리 구현
1. HTML Form 전송 방식
기본적으로 HTML Form은 두 가지 방식으로 서버에 데이터를 전송할 수 있다:
- application/x-www-form-urlencoded: 기본 문자 기반 전송 방식
- multipart/form-data: 파일 업로드를 위한 바이너리 기반 전송 방식
multipart/form-data는 문자열과 파일을 동시에 전송할 수 있어야 할 때 사용하며, 각각의 데이터는 Part 단위로 분리되어 전송되고, 각 Part에는 파일 이름, 타입, 콘텐츠 등의 정보가 포함된다.
2. 서블릿과 파일 업로드 (기초)
HttpServletRequest + Part API 사용
서블릿 3.0 이상부터는 파일 업로드를 위해 request.getParts()를 사용해 multipart 데이터를 직접 다룰 수 있다.
하지만 이 방식은 다음과 같은 한계가 있다:
- HttpServletRequest 기반으로 작성되어 코드가 복잡하고 직관적이지 않다.
- 파일 저장 경로 처리, 예외 처리, MIME 타입 처리 등을 개발자가 모두 직접 구현해야 한다.
결론적으로, 기본 개념 학습 목적 외에는 실무에서 잘 사용하지 않는다.
3. 스프링과 파일 업로드 (실무 핵심)
MultipartFile 인터페이스 활용
스프링은 파일 업로드를 보다 쉽게 처리하기 위해 MultipartFile 인터페이스를 제공한다. 이 방식은 컨트롤러에서 다음과 같이 간단히 선언하여 사용할 수 있다:
@PostMapping("/upload")
public String saveFile(@RequestParam String itemName,
@RequestParam MultipartFile file) throws IOException {
log.info("itemName={}", itemName);
log.info("multipartFile={}", file);
if (!file.isEmpty()) {
String fullPath = fileDir + file.getOriginalFilename();
file.transferTo(new File(fullPath));
}
return "upload-form";
}
장점
- multipart 요청을 자동으로 분석하여 MultipartFile로 주입해준다.
- 코드가 간결하고 생산성이 높다.
- 파일 이름, 확장자, 크기, Content-Type 등에 쉽게 접근할 수 있다.
- transferTo(...) 메서드를 통해 서버 파일로 간단히 저장할 수 있다.
주요 메서드
- getOriginalFilename(): 클라이언트가 업로드한 파일명 반환
- getSize(): 파일 크기 반환
- getContentType(): MIME 타입 반환
- transferTo(...): 파일 저장 처리
이 방식은 실무에서 가장 많이 사용되는 파일 업로드 처리 방식이다.
4. 실무 예제로 구현한 파일 업로드/다운로드
요구사항
- 상품 등록 시 첨부파일 1개, 이미지 여러 개 업로드 가능해야 한다.
- 업로드한 첨부파일은 다운로드 가능해야 한다.
- 업로드한 이미지들은 브라우저에서 바로 확인 가능해야 한다.
핵심 클래스 설계
1) UploadFile
@Data
public class UploadFile {
private String uploadFileName; // 사용자가 업로드한 파일명
private String storeFileName; // 서버에서 관리하는 유니크 파일명
public UploadFile(String uploadFileName, String storeFileName) { ... }
}
2) FileStore
public class FileStore {
public UploadFile storeFile(MultipartFile multipartFile) {...}
public List<UploadFile> storeFiles(List<MultipartFile> multipartFiles) {...}
private String createStoreFileName(String originalFilename) { ... }
private String extractExt(String originalFilename) { ... }
}
- UUID를 사용하여 서버 저장 파일명을 유일하게 생성한다.
- 원래 확장자를 유지하여 MIME 타입 처리를 일관되게 할 수 있다.
3) Item, ItemForm, ItemRepository
- 상품 등록 폼에서 MultipartFile, List<MultipartFile>을 입력받도록 구성한다.
- 업로드된 파일은 서버에 저장하고, 해당 정보는 메모리 기반 저장소에 저장한다.
4) ItemController
@PostMapping("/items/new")
public String saveItem(@ModelAttribute ItemForm form, ...) throws IOException {
UploadFile attachFile = fileStore.storeFile(form.getAttachFile());
List<UploadFile> storeImageFiles = fileStore.storeFiles(form.getImageFiles());
Item item = new Item(...);
itemRepository.save(item);
return "redirect:/items/{itemId}";
}
- 이미지 조회는 <img src="/images/{storeFileName}"> 방식으로 처리한다.
- 첨부파일 다운로드는 <a href="/attach/{itemId}"> 링크를 제공한다.
마무리 정리
- 파일 업로드는 단순히 파일만 서버에 저장하는 것이 아니라, 파일 이름 관리, 확장자 처리, MIME 타입 처리, 보안 이슈 등 다양한 요소를 고려해야 한다.
- 서블릿 기반보다는 MultipartFile을 활용하는 스프링 방식이 실무에서 더 효율적이고 관리하기 쉽다.
- UUID 기반의 내부 저장 파일명과 사용자가 업로드한 파일명을 분리함으로써 파일명 충돌 및 보안 문제를 예방할 수 있다.
'코딩 도구 > 백엔드 개발 (Backend Development)' 카테고리의 다른 글
[Spring DB] 커넥션 풀과 DataSource (0) | 2025.05.12 |
---|---|
[Spring DB] JDBC 이해 (0) | 2025.05.05 |
[Spring] API 예외 처리 정리 (0) | 2025.04.21 |
[Spring] 예외 처리와 오류 페이지 정리 (0) | 2025.04.14 |
[Spring] 로그인 처리2 (필터, 인터셉터) 정리 (1) | 2025.04.07 |