[Spring MVC] [2] 11. 파일 업로드

윤경·2021년 10월 2일
0

Spring MVC

목록 보기
26/26
post-thumbnail


드디어 마지막 챕터다,,


[1] 파일 업로드 소개

HTML 폼 전송 방식

1. application/x-www-form-urlencoded
2. multipart/form-data

1. application/x-www-form-urlencoded 방식

HTML 폼 데이터를 서버로 전송하는 가장 기본적인 방법으로 Form 태그에 별도의 enctype 옵션이 없으면 웹 브라우저는 요청 HTTP 메시지의 헤더에 Content-Type: application/x-www-form-urlencoded 내용을 추가한다.

하지만 파일 업로드는 문자가 아닌 바이너리 데이터를 전송해야 한다.
또한, 보통 폼을 전송할 때 파일만 전송하지 않는다는 점을 해결해야 한다.
➡️ 문자와 바이너리를 동시에 전송

그래서 다음과 같은 방식을 사용한다.

2. multipart/form-data

이 방식은 Form 태그에 별도로 enctype="multipart/form-data"를 지정해야 한다.
이는 다른 종류의 여러 파일과 폼 내용을 함께 전달할 수 있다. (multipart)

content-Disposition: 항목별 헤더. 여기에 부가 정보 포함
이렇게 항목을 구분해 한 번에 전송 가능


[2] 프로젝트 생성

기본 설정


[3] 서블릿과 파일 업로드1

request.getParts(): multipart/form-data 전송 방식에서 각각 나누어진 부분을 받아 확인할 수 있음

logging.level.org.apache.coyote.http11=debug: application.properties에서 이 옵션을 넣어주면 아래처럼 HTTP 요청 메시지를 확인할 수 있다.

이미지 바이너리 파일이기 때문에 이렇게 깨져 보이는 것일뿐!! ㄱㅊㄱㅊ

📌 업로드 사이즈 제한
사이즈를 초과하면 SizeLimitExceededException 발생
max-file-size: 파일 하나의 최대 사이즈, 기본 1MB
max-request-size: 멀티파트 요청 하나에 여러 파일 업로드할 수 있는데 그 전체 합을 말함. 기본 10MB

ex) spring.servlet.multipart.max-file-size=1MB

📌 멀티파트 관련 처리
spring.servlet.multipart.enabled=false
이렇게 옵션을 꺼버리면 서블릿 컨테이너가 멀티파트와 관련된 처리를 하지 않음

request.getParameter("itemName"), request.getParts()의 결과가 비게된다.

서기본 값은 true로 스프링 부트가 서블릿 컨테이너에게 데이터를 처리하라고 설정한다.

✔️ 로그에서 HttpServletRequest 객체가 RequestFacadeStandardMultipartHttpServletRequest로 변한 것을 확인해보자.

📌 참고만 하기

spring.servlet.multipart.enabled 옵션을 켜면 스프링의 DispatcherServlet에서 MultipartResolver를 실행한다.

MultipartResolver는 멀티파트 요청인 경우 서블릿 컨테이너가 전달하는 일반적인 HttpServletRequest를 MultipartHttpServletRequest로 변환해 반환한다.

MultipartHttpServletRequest는 HttpServletRequest의 자식 인터페이스이고, 멀티파트와 관련된 추가 기능을 제공한다.

스프링이 제공하는 기본 MultipartResolver는 MultipartHttpServletRequest 인터페이스를 구현한 StandardMultipartHttpServletRequest를 반환한다.

이제 컨트롤러에서 HttpServletRequest 대신에 MultipartHttpServletRequest를 주입받을 수 있는데, 이걸 사용하면 멀티파트와 관련된 여러가지 처리를 편리하게 할 수 있다.
그러나 참고만 하라는 이유는 MultipartFile이라는 좋은 기능이 있기 때문이다. MultipartHttpServletRequest는 사실 잘 사용하지 않는다.


[4] 서블릿과 파일 업로드2

파일 업로드를 위해 파일이 저장될 실제 폴더를 만들어두기

멀티파트 형식은 전송 데이터를 하나씩 part로 나누어 전송. parts에는 니누어진 데이터가 각각 담김.

part.getSubmittedFileName(): 클라이언트가 전달할 파일명
part.getInputStream(): Part의 전송 데이터를 읽을 수 있음
part.write(): Part를 통해 전송된 데이터를 저장할 수 있음

📌
큰 용량 파일을 업로드해 테스트할 때는 로그가 많이 남으므로 logging.level.org.apache.coyote.http11=debug 옵션을 끄는 것이 좋다.

log.info("body={}", body); 또한 바이너리 데이터를 모두 출력하므로 용량이 크다면 꺼주기.


[5] 스프링과 파일 업로드

@RequestParam MultipartFile file
: 업로드하는 HTML Form의 name에 맞춰 @RequestParam을 적용하면 된다.
추가로 @ModelAttribute에서도 MultipartFile을 동일하게 사용할 수 있다.

MultipartFile 주요 메소드
file.getOriginalFilename(): 업로드 파일명
file.transferTo(): 파일 저장


[6] 예제로 구현하는 파일 업로드, 다운로드

📍 요구사항

  • 상품을 관리 (상품 이름 / 첨부파일 하나 / 이미지파일 여러개)
  • 첨부파일 업로드, 다운로드 가능
  • 업로드한 이미지 웹 브라우저에서 확인

uploadFileName: 고객이 업로드한 파일명
storeFileName: 서버 내부에서 관리하는 파일명

파일명을 따로 두는 이유?

고객이 업로드한 파일명으로 서버 내부에 파일을 저장하면 안되기 때문.
다른 고객이 같은 파일 이름을 업로드 할 경우 내부에서 충돌이 발생한다. 서버에서 저장할 파일명이 겹치지 않도록 내부에서 관리하는 별도의 파일명이 필요하다.

createStoreFileName(): 서버 내부에서 관리하는 파일명은 유일한 이름을 생성하는 UUID를 사용해 충돌하지 않도록 한다.

extractExt(): 확장자를 별도로 추출해 서버 내부에서 관리하는 파일명에도 붙여준다.
ex) 51041c62-86e4-4274-801d-614a7d994edb.png


드디어 로드맵 하나가 끝장났습니다. 이제 로드맵2를 시작해보도록 하겠습니다. (-o-)(_o_)

profile
개발 바보 이사 중

0개의 댓글