본문 바로가기

Backend/Spring

Spring Boot 파일 업로드 MultipartFile

Spring의 MultipartFile 인터페이스를 이용하여 파일 업로드하는 방법에 대해서 알아볼게요.

파일을 리스트로 여러 개 업로드하면 컨트롤러에서 받을 수 있도록 할거에요.

간단하게 말해서 다중 업로드죠.

예제 구현은 Spring Boot 2.1.8, OpenJDK 11 버전으로 했어요.

 

FileController

기본적으로 @RequestPart 어노테이션을 이용해서 multipart/form-data 요청을 메소드 인수와 연관시킬 수 있어요.

@RequestParam를 사용해도 동일하게 잘 받아집니다.

 

@PostMapping("")
@ResponseStatus(HttpStatus.CREATED)
public List<String> upload(@RequestPart List<MultipartFile> files) throws Exception {
	List<String> list = new ArrayList<>();
	for (MultipartFile file : files) {
		String originalfileName = file.getOriginalFilename();
		File dest = new File("C:/Image/" + originalfileName);
		file.transferTo(dest);
		// TODO
	}
	return list;
}

 

application.yml

spring.servlet.multipart.enabled: 멀티파트 업로드 지원여부 (default: true)

spring.servlet.multipart.file-size-threshold: 파일이 메모리에 기록되는 임계값 (default: 0B)

spring.servlet.multipart.location: 업로드된 파일의 임시 저장 공간

spring.servlet.multipart.max-file-size: 파일의 최대 사이즈 (default: 1MB)

spring.servlet.multipart.max-request-size: 요청의 최대 사이즈 (default: 10MB)

 

spring:
  servlet:
    multipart:
      file-size-threshold: 1MB
      location: C:/Temp
      max-file-size: 100MB
      max-request-size: 100MB

 

파일의 크기가 fize-size-threshold 값 이하라면 임시파일을 생성하지 않고 메모리에서 즉시 파일을 읽어서 생성할 수 있어요. 속도는 더 빠르겠지만, 쓰레드가 작업을 수행하는 동안 부담이 되는 부분이기 때문에 충분한 검토가 필요한 설정이에요.

파일의 크기가 fize-size-threshold 값을 초과한다면 파일은 spring.servlet.multipart.location 경로에 저장되어 해당 파일을 읽어서 작업을 하도록 되어있어요.

 

참고로 location을 설정하지 않으면 System.getProperty("java.io.tmpdir"); 경로에 저장이 되요.

아래 이미지의 path와 같이 눈으로 보기에도 굉장히 지저분한 경로가 생성될 수 있어요.

요청 처리 후에는 파일이 삭제되도록 되어있지만, 운영하다보면 결국 남아있는 것은 어떤 이유로든 남게 되있어요.

그럴 경우에는 삭제 처리를 별도로 해야하기 때문에 작업과 관리가 용이하도록 경로를 직접 설정해주는 것이 좋아요.

 

 

업로드 클라이언트를 구현하지 않고 간단하게 Postman으로 업로드 테스트를 했어요.

Postman에서는 동일한 key에 값을 넣어 리스트로 전송할 수 있어요.

 

 

 

기본적인 구현은 여기까지가 끝이에요.

 

마지막으로 파일 뿐만 아닌 일반 필드도 같이 보내야할 경우에 어떻게 하면 되는지까지 이야기해보고 마칠게요.

간단해요. 클라이언트에선 form 형태로 요청하고 서버에선 @RequestParam 어노테이션을 사용하여 매핑하면 됩니다.

FileController

@PostMapping("")
@ResponseStatus(HttpStatus.CREATED)
public List<String> upload(@RequestPart List<MultipartFile> files,
		@RequestParam String field1,
		@RequestParam String field2,
		@RequestParam String field3,
		@RequestParam String field4) throws Exception {
	// TODO
}

 

 

 

위와 같은 방법이 조금 지저분하다고 느껴진다면, VO를 활용하시면 되요.

개인적으로는 VO로 설계하는 편입니다.

FileController

@PostMapping("")
@ResponseStatus(HttpStatus.CREATED)
public List<String> upload(FileVo form) throws Exception {
	// TODO
}

FileVo

@Getter
@Setter
public class FileVo {
	
	private List<MultipartFile> files;
	private String field1;
	private String field2;
	private String field3;
	private String field4;

}