IT/자바, 스프링

서블릿으로 받은 MultipartFile에 대한 NoSuchFileException

thesse 2022. 9. 19. 10:09
300x250
반응형

MultipartFile의 임시적인 속성

멀티파트파일은 임시 파일로 생성되었다가 해당 메소드가 종료되면 사라진다고 한다!

(이걸 몰라서 얼마나 삽질을 한 건지...)

 

때문에 @Async 메소드로 달아서 처리하거나

다른 pubic 메서드로 넘겨서 처리하려고 하면 파일을 찾지 못하는 경우가 발생하는 것.

 

1) async로 넘겨야 할 경우 물리적으로 복사해둔 후 메소드가 끝날때 지워주는 방식을 통해 영속적으로 사용할 수 있고

2) 같은 클래스 내에서 호출하여 파일을 가공하는 경우 private 메소드로 사용하면 된다.

 

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/multipart/MultipartFile.html

 

MultipartFile (Spring Framework 5.3.23 API)

Transfer the received file to the given destination file. This may either move the file in the filesystem, copy the file in the filesystem, or save memory-held contents to the destination file. If the destination file already exists, it will be deleted fir

docs.spring.io

 

 

 

기존 방식

Controller   Service → AsyncService CloudService (여기에서 변환)

 

위와 같이 멀티파트파일을 넘겨 넘겨 받아서

클라우드 스토리지에 올리기 직전 MultipartFile -> File로 변환하려 했다.

 

그러나 CloudService에서 멀티파트파일은 메타정보만 가지고 있고

/tmp/tomcat....../work/Tomcat/localhost/ROOT 아래에 있는 .tmp 파일은

Service 클래스에서 async 메서드를 호출하고 리턴됐을 때 이미 사라지고 없는 상태인 것이다. (NoSuchFile)

 

 

 

해결

Controller   Service  (여기에서 변환) → AsyncService  CloudService

이렇게 async 메서드를 호출할 때 애초에 변환된 File 객체를 넘겨줘서 처리하자

더 이상 익셉션이 발생하지 않고 잘 돌아갔다.

 

모든 처리가 끝난 뒤 생성한 파일을 삭제해주는것까지 잊지 말자!

 

private File convert(MultipartFile file) {
        File convFile = null;
        boolean result = true;
        try {
            // 혹시나 파일 이름이 중복될 수 있으니 파일 이름 앞에 랜덤한 숫자값을 덧붙여줌
            convFile = new File(tmpLocation + "/" + Math.abs(LocalDateTime.now().hashCode()) + "_" + URLDecoder.decode(file.getOriginalFilename(), "UTF-8"));
            convFile.createNewFile();
            FileOutputStream fos = new FileOutputStream(convFile);
            fos.write(file.getBytes());
            fos.close();
            return convFile;
            
        } catch (Exception e){
            result = false;
            e.printStackTrace();
            
        } finally {
            if(result=false && convFile.exists()){
                convFile.delete();
            }
        }
        return null;
    }

 

 

300x250
반응형