본문 바로가기
카테고리 없음

Springboot Matipart/form-data 파일 업로드 구현 예제

by Hello_World_! 2025. 8. 8.
반응형

파일 업로드는 웹 애플리케이션에서 굉장히 자주 사용되는 기능입니다. 이번 글에서는 스프링 MVC에서 파일 업로드를 구현하는 전 과정을 코드와 함께 자세히 설명합니다. 특히 초보자도 이해할 수 있도록 **"왜 이 코드가 필요한가?"**를 중심으로 설명합니다.


✅ HTML 폼의 전송 방식 이해

파일 업로드를 하기 전에 먼저 HTML <form> 태그가 데이터를 전송하는 방식을 알아야 합니다.

text
복사편집
1. application/x-www-form-urlencoded ← 기본값 (텍스트 데이터만 전송 가능) 2. multipart/form-data ← 파일 포함한 데이터 전송 가능 (우리가 쓸 방식!)
  • application/x-www-form-urlencoded는 텍스트만 전송 가능.
  • multipart/form-data는 텍스트 + 파일(바이너리) 함께 전송 가능.

🔥 왜 multipart/form-data를 써야 할까?

폼에서 이름, 나이 같은 텍스트 + 파일을 동시에 보내야 하기 때문입니다. 그래서 form 태그에 반드시 다음 속성을 추가합니다:

html
복사편집
<form method="post" enctype="multipart/form-data">

🏗 프로젝트 초기 설정 (Spring Boot)

groovy
복사편집
// build.gradle dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' }
  • Web, Thymeleaf, Lombok 사용
  • Java 11 기준으로 진행

📄 HTML 업로드 폼 작성 (upload-form.html)

html
복사편집
<form th:action method="post" enctype="multipart/form-data"> <ul> <li>상품명 <input type="text" name="itemName"></li> <li>파일<input type="file" name="file"></li> </ul> <input type="submit"/> </form>
  • enctype="multipart/form-data" 꼭 필요!
  • 파일 input은 <input type="file" name="file">

① 서블릿 기반 파일 업로드 (ServletUploadControllerV1)

java
복사편집
@PostMapping("/upload") public String saveFileV1(HttpServletRequest request) throws ServletException, IOException { String itemName = request.getParameter("itemName"); Collection<Part> parts = request.getParts(); // ★ 핵심! multipart 파싱 ... }

🧠 왜 이 코드를 쓰는가?

  • request.getParts() → 전송된 각 파트를 분리해 Part 객체로 제공
  • Part → 파일, 텍스트 구분 없이 다 들어있음

application.properties 추가

properties
복사편집
logging.level.org.apache.coyote.http11=trace
  • HTTP 전송 내용을 콘솔에서 확인 가능

② 파일을 실제로 서버에 저장하기 (ServletUploadControllerV2)

java
복사편집
@Value("${file.dir}") private String fileDir; // application.properties에서 업로드 경로 주입 @PostMapping("/upload") public String saveFileV1(HttpServletRequest request) throws ServletException, IOException { Collection<Part> parts = request.getParts(); for (Part part : parts) { if (StringUtils.hasText(part.getSubmittedFileName())) { String fullPath = fileDir + part.getSubmittedFileName(); part.write(fullPath); // ★ 서버에 저장 } } ... }

📌 주의할 점

  • file.dir은 실제 폴더 경로여야 하며, 미리 만들어져 있어야 합니다.
  • 저장할 때 part.write() 메서드를 사용.

③ 스프링 방식으로 업로드 처리 (SpringUploadController)

java
복사편집
@PostMapping("/upload") public String saveFile(@RequestParam String itemName, @RequestParam MultipartFile file) throws IOException { if (!file.isEmpty()) { String fullPath = fileDir + file.getOriginalFilename(); file.transferTo(new File(fullPath)); // ★ 스프링식 파일 저장 } ... }

✅ 스프링은 MultipartFile을 자동 주입해줍니다

  • @RequestParam MultipartFile file로 선언만 하면 파일이 들어옴
  • file.getOriginalFilename() → 업로드한 원본 파일명
  • file.transferTo(...) → 저장

④ 실전 예제 - 첨부파일 + 이미지 여러 개 업로드 (ItemController)

📌 핵심 기능

  1. 첨부파일 1개 업로드
  2. 이미지 여러 개 업로드
  3. 업로드 파일 정보 저장
  4. 업로드 파일 다운로드 + 이미지 출력

📦 관련 클래스 요약

클래스설명
Item 상품 엔티티, 첨부파일과 이미지 목록 포함
UploadFile 업로드된 파일 정보 (원본명, 저장명)
FileStore 파일 저장 로직 처리 (UUID 생성 포함)
ItemRepository 메모리 저장소 (Map 사용)
ItemForm 폼 객체 (파일 정보 포함)
ItemController 업로드 처리 컨트롤러
 

📁 FileStore.java – 파일 저장 처리

java
복사편집
public UploadFile storeFile(MultipartFile multipartFile) throws IOException { String originalFilename = multipartFile.getOriginalFilename(); String storeFileName = createStoreFileName(originalFilename); multipartFile.transferTo(new File(getFullPath(storeFileName))); return new UploadFile(originalFilename, storeFileName); } private String createStoreFileName(String originalFilename) { String ext = extractExt(originalFilename); return UUID.randomUUID().toString() + "." + ext; }

🔐 왜 UUID를 붙여서 저장할까?

  • 사용자가 같은 파일명을 여러 번 업로드하면 덮어쓰기 발생
  • 서버에서 고유한 이름으로 관리해야 함

🌅 이미지 출력 및 파일 다운로드

이미지 출력

java
복사편집
@GetMapping("/images/{filename}") @ResponseBody public Resource downloadImage(@PathVariable String filename) { return new UrlResource("file:" + fileStore.getFullPath(filename)); }
  • <img> 태그에서 호출되며, 서버에서 파일 바이너리를 직접 반환

첨부파일 다운로드

java
복사편집
@GetMapping("/attach/{itemId}") public ResponseEntity<Resource> downloadAttach(@PathVariable Long itemId) { Item item = itemRepository.findById(itemId); String storeFileName = item.getAttachFile().getStoreFileName(); String uploadFileName = item.getAttachFile().getUploadFileName(); UrlResource resource = new UrlResource("file:" + fileStore.getFullPath(storeFileName)); String encodedUploadFileName = UriUtils.encode(uploadFileName, StandardCharsets.UTF_8); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedUploadFileName + "\"") .body(resource); }
  • 파일 다운로드 시 Content-Disposition 헤더로 다운로드 파일명 설정 가능

📌 마무리 요약

구분방식설명
서블릿 방식 HttpServletRequest, Part 직접 파싱
스프링 방식 MultipartFile 자동 처리 (권장)
저장 방식 file.transferTo() or part.write() 서버 저장
주의사항 파일명 중복 방지 UUID 사용
응답 처리 @ResponseBody, Resource 이미지, 첨부파일 반환
 

📍 실습 주소 예시

주소설명
/spring/upload 스프링 파일 업로드
/items/new 상품 업로드 폼
/items/{id} 상품 상세 보기
/images/{filename} 이미지 조회
/attach/{itemId} 첨부파일 다운로드
 

💡 이 포스트는 스프링 파일 업로드의 전 과정을 실습 + 설명한 가이드입니다. 초보자라면 꼭 직접 실습해보세요!