개요
- 비동기 함수 안에서 MultipartFile.getInputStream() 실행 시
임시 파일이 없다는 에러가 난다.
원인
- 컨트롤러에서 multipart/form-data 요청을 받으면
해당 파일이 임시 경로에 저장되는 듯 하다. - 이때 MultipartFile.getInputStream() 실행하면
임시 파일에서 stream 연결을 불러오는 것 같다. - 임시 파일은 해당 요청에 대한 응답을 해버리면 즉시 삭제하는 것 같다.
- 떄문에 응답 후에 비동기 함수에서
MultipartFile.getInputStream()를 실행하면
해당 파일이 없다는 에러가 나는 것이다[참고1][참고2].
해결방법 - 파일 byte로 변환하고 비동기 함수로 전달
- 설명
- 파일을 byte 형태로 변환한 뒤 비동기 함수에 넘겨주면
임시 파일이 삭제되는 것과 상관없이 처리가 가능하다.
- 파일을 byte 형태로 변환한 뒤 비동기 함수에 넘겨주면
- 예시
- image/ImageDto.java
1 2 3 4 5 6
@Getter @Setter public class ImageDto { byte[] imageBytes; String originalFilename; }
- image/ImageController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
@RequiredArgsConstructor @RestController public class ImageController { @PostMapping(value = "/image") public String create(@RequestParam(value = "image") @NotBlank MultipartFile[] imageFiles) throws IOException { List<ImageDto> imageDtoList = new ArrayList<>(); for (MultipartFile imageFile : imageFiles) { ImageDto imageDto = new ImageDto(); imageDto.setImageBytes(imageFile.getBytes()); imageDto.setOriginalFilename(imageFile.getOriginalFilename()); imageDtoList.add(imageDto); } this.saveImage(imageDtoList); return "success"; } public void saveImage(List<ImageDto> imageDtoList) { CompletableFuture.runAsync(() -> { System.out.println("inner async start"); try { // 이미지 저장 로직 ... } catch (Exception e) { throw new RuntimeException(e); } System.out.println("inner async end"); }).exceptionally((e) -> { // 이미지 저장 실패 시 에러 핸들링 return null; }); } }
- image/ImageDto.java
- 단점
- 파일의 byte 형태 변환은 메모리에서 이뤄지므로
엄청 큰 파일을 처리하는 경우에는 사용하기 어렵다. - 이 경우에는 비동기 함수 실행 전에
다른 스토리지에 파일을 저장해서 처리할 것 같다.
- 파일의 byte 형태 변환은 메모리에서 이뤄지므로