Spring ‐ 파일 업로드 - thought-corner/Backend-PlayGround GitHub Wiki
서블릿을 활용한 파일 업로드
- 큰 파일을 무제한 업로드하게 둘 수는 없으므로 업로드 사이즈를 제한할 수 있다.
- 사이즈를 넘으면
SizeLimitExceededException예외가 발생한다.
spring.servlet.multipart.max-file-size=1MB # 파일 하나의 최대 사이즈
spring.servlet.multipart.max-request-size=10MB # 멀티파트 요청 하나에 여러 파일을 업로드 할 수 있는데 그 전체 합
- 파일 데이터는
multipart/form-data방식으로 전송되기 때문에@RequestBody를 사용할 수 없다. @RequestPart,@RequestParam,@ModelAttribute어노테이션으로는 받을 수 있다.
📚multipart/form-data
1. 핵심 개념
- 일반적인 폼 데이터(application/x-www-form-urlencoded)는
key=value&key=value형태의 단순 문자열로 전송된다.- 하지만 바이너리 데이터는 이런 방식으로 전송하기 어렵기 때문에, HTTP는 multipart/form-data라는 방식을 제공한다.
2. HTTP 요청 메시지 구조
POST /save HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary...
------WebKitFormBoundary...
Content-Disposition: form-data; name="itemName"
Spring Book
------WebKitFormBoundary...
Content-Disposition: form-data; name="imageFile"; filename="logo.png"
Content-Type: image/png
(바이너리 데이터...)
------WebKitFormBoundary...--
public ResponseEntity<> file(@RequestPart MultipartFile files){}
public ResponseEntity<> file(@RequestParam MultipartFile file){}
public ResponseEntity<> file(@ModelAttribute MultipartFile file){}
// 생략시 modelAttribute 적용
public ResponseEntity<> file(MultipartFile file){}
Content-Disposition: 각 파트의 이름과 실제 파일명 정보를 담고 있다.- 개별
Content-Type: 파일 파트의 경우 해당 파일이 어떤 형식인지 별도의 헤더를 가질 수 있다.3. 스프링 MVC의 처리 방식
- Spring은 복잡한 멀티파트 요청을 쉽게 처리할 수 있도록
MultipartResolver를 제공한다.- DispatcherServlet의 개입 : 요청을 받으면
MultipartResolver를 실행하고 해당 요청이multipart/form-data인지 확인하고, 맞다면 일반적인HttpServletRequest를MultipartHttpServletRequest로 변환한다.- 컨트롤러에서의 활용 : 스프링에서 파일을 받는 방법으로
MultipartFile인터페이스를 사용한다.
@PostMapping("/upload")
public String saveFile(@RequestParam String itemName,
@RequestParam MultipartFile imageFile) throws IOException {
if (!imageFile.isEmpty()) {
String fullPath = "/upload/" + imageFile.getOriginalFilename();
imageFile.transferTo(new File(fullPath)); // 파일 저장
}
return "upload-success";
}
4. 스프링 부트 설정(Configuration)
- 스프링 부트는 별도의 설정 없이도
StandardServletMultipartResolver를 기본으로 등록한다.
# 파일 하나당 최대 용량 (기본 1MB)
spring.servlet.multipart.max-file-size=10MB
# 한 번의 요청에 포함된 모든 파일의 총 합계 용량 (기본 10MB)
spring.servlet.multipart.max-request-size=50MB
# 멀티파트 처리 여부 (기본 true)
spring.servlet.multipart.enabled=true
스프링과 파일 업로드
- 스프링은
MultipartFile이라는 인터페이스로 멀티파트 파일을 매우 편리하게 지원한다.
public interface MultipartFile extends InputStreamSource {
/**
* 멀티파트 폼 데이터에서 파라미터의 이름을 반환합니다. (HTML input 태그의 name 속성값)
*/
String getName();
/**
* 클라이언트가 업로드한 파일의 실제 이름을 반환합니다.
* 주의: 보안상의 이유로(경로 조작 등) 이 이름을 그대로 서버 저장 경로에 사용하는 것은 위험합니다.
*/
@Nullable String getOriginalFilename();
/**
* 파일의 콘텐츠 타입(MIME type)을 반환합니다. (예: image/png)
*/
@Nullable String getContentType();
/**
* 파일이 비어있는지 여부를 확인합니다. (선택된 파일이 없거나 내용이 없는 경우 true)
*/
boolean isEmpty();
/**
* 파일의 크기를 바이트(byte) 단위로 반환합니다.
*/
long getSize();
/**
* 파일의 내용을 바이트 배열로 반환합니다.
*/
byte[] getBytes() throws IOException;
/**
* 파일의 내용을 읽기 위한 InputStream을 반환합니다.
*/
@Override
InputStream getInputStream() throws IOException;
/**
* MultipartFile을 추상화된 Resource 객체로 변환합니다. (Spring 5.1+)
*/
default Resource getResource() {
return new MultipartFileResource(this);
}
/**
* 업로드된 파일을 지정된 목적지(File)로 저장합니다.
* 내부적으로 임시 저장소에 있는 파일을 이동하거나 복사합니다.
*/
void transferTo(File dest) throws IOException, IllegalStateException;
/**
* 업로드된 파일을 지정된 경로(Path)로 저장합니다. (Spring 5.1+)
*/
default void transferTo(Path dest) throws IOException, IllegalStateException {
FileCopyUtils.copy(getInputStream(), Files.newOutputStream(dest));
}
}
관련 예제 코드는 여기에서 볼 수 있습니다.