Spring boot - MultipartFile 를 이용한 파일 업로드

목차

MultipartFile 인터페이스

multipart/form-data 요청을 처리하기 위해 만들어진 객체

Spring 에서는 멀티파트 요청을 처리 하기 위해 MultipartFile 객체를 제공합니다.

public interface MultipartFile extends InputStreamSource {

// 전달 받은 Parameter Key값을 가져온다.
String getName();

// 파일 명을 가져온다.
@Nullable
String getOriginalFilename();

// 파일의 ContentType을 가져온다.
// pdf 파일의 경우 application/pdf, mp4 파일의 경우 video/mp4, png 파일의 경우 image/png
@Nullable
String getContentType();

// 전달 받은 Parameter Value값이 비어 있는지 확인한다.
boolean isEmpty();

// 전달 받은 파일의 크기를 가져온다.
// 파일은 byte 단위로 표시된다.
long getSize();

byte[] getBytes() throws IOException;

// 전달 받은 파일을 읽기 위한 InputStream을 가져온다.
@Override
InputStream getInputStream() throws IOException;

// MultipartFile 객체를 이용해 Resource(MultipartFileResource) 객체를 반환 받는다.
default Resource getResource() {
return new MultipartFileResource(this);
}

// MultipartFile 내 데이터를 전달받은 File 객체에 저장한다.
// 한번만 호출이 가능한 메소드다.
void transferTo(File dest) throws IOException, IllegalStateException;

// MultipartFile 내 데이터를 전달받은 Path 객체에 저장한다.
default void transferTo(Path dest) throws IOException, IllegalStateException {
FileCopyUtils.copy(getInputStream(), Files.newOutputStream(dest));
}
}

파일 업로드 구현

파일 업로드를 위한 Controller 구현

multipart/form-data 요청은 Form 형식으로 요청이 오기 때문에 RequestBody 어노테이션이 아니라 RequestParam 어노테이션을 이용해 데이터를 받는다.

@RestController
@Slf4j
public class FileController {

String filePath = "/Users/dongwoo-yang/spring-file/";

@PostMapping("/file/upload")
public ResponseEntity upload(@RequestParam("file") MultipartFile multipartFile, HttpServletRequest request) throws IOException, URISyntaxException {

if(multipartFile.isEmpty()){
log.info("File is empty");
}

log.info("multipartFile.getName() : {}", multipartFile.getName());
log.info("multipartFile.getOriginalFilename() : {}", multipartFile.getOriginalFilename());
log.info("multipartFile.getContentType() : {}", multipartFile.getContentType());
log.info("multipartFile.getSize() : {}", multipartFile.getSize());
log.info("multipartFile.getResource() : {}", multipartFile.getResource());

String fullFilename = multipartFile.getOriginalFilename();
int lastIndex = fullFilename.lastIndexOf(".");
String filename = fullFilename.substring(0, lastIndex);
String ext = fullFilename.substring(lastIndex + 1);

// 새로운 파일 이름 생성
String newName = UUID.randomUUID() + "." + ext;
String uploadPath = filePath + newName;

// File 객체를 이용해 저장
// multipartFile.transferTo(new File(uploadPath));

// Path 객체를 이용해 저장
multipartFile.transferTo(Paths.get(uploadPath));

URI uri = new URI(request.getRequestURI());
return ResponseEntity.created(uri).body("File Upload Success");
}
}

File Upload 테스트 코드 작성

파일을 RestTemplate으로 전달할 때는 MultiValueMap 에 담아 전송한다. MultiValueMap 에 들어가는 데이터 형으로는 File 객체가 아니라 Resource 객체를 던져 줘야 mulipart/form-data 형태로 전송이 된다. 이거 때문에 진짜 한참 찾아 다녔다.

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class FileControllerTest {

@Autowired
private TestRestTemplate testRestTemplate;

@LocalServerPort
int randomServerPort;

@Test
public void uploadTest() throws IOException {
ClassPathResource resource = new ClassPathResource("testFile.txt");
File file = resource.getFile();

MultiValueMap multiValueMap = new LinkedMultiValueMap();
multiValueMap.add("file", resource);

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);

HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity(multiValueMap, headers);

String requestURL = "http://localhost:" + randomServerPort + "/file/upload";

ResponseEntity<String> responseEntity = this.testRestTemplate.exchange(requestURL,
HttpMethod.POST,
httpEntity,
new ParameterizedTypeReference<String>() {
});

assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.CREATED);
assertThat(responseEntity.getBody()).isEqualTo("File Upload Success");
}
}

이미지 파일 Upload

PDF 파일 Upload

Mp4 파일 upload

Share