Spring

[Spring] 서버에 파일 저장하고 경로 가져오기: ServletContext resource [/src/main/xxx.pdf] cannot be resolved to URL because it does not exist

깃짱 2024. 2. 24. 01:30
반응형
반응형

 

💋 문제상황

 

 

private String saveFile(final MultipartFile file) {
	String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
	final Path path = Paths.get("src", "main", "pdf", fileName);

	try {
		Files.copy(file.getInputStream(), path);
		final Resource resource = resourceLoader.getResource("file:" + path); // TODO: なんで「ファイル」だって
		return resource.getURI().toString();
	} catch (IOException e) {
		throw new RuntimeException(e);
	}
}

 

사용자로부터 받은 pdf 파일을 내 서버의 특정 경로인 path에 복사하고, 그 뒤에 path의 uri를 반환하는 메서드다. form으로 받은 파일을 저장하기 위해서 사용하고 있다.

 

사실 저건 gpt한테 물어봐서 짰던 코드인데, 문제가 발생함..

 

이후에 저기로부터 반환받은 값을 그대로 저장해 버린다.

 

@Transactional
public Long register(final MultipartFile file) {
	final String pdfURI = saveFile(file);
	log.info("Saved pdf File in Server. File URI: {}", pdfURI);

		// 'file:'이 붙은 코드 그대로 저장해버림!!! 
	final Translations translations = translationsRepository.save(Translations.of(pdfURI, file.getOriginalFilename()));

		// 이제부터 알아서 할일 함...
	eventPublisher.publishEvent(new OcrRegisterEvent(this, translations));
	return translations.getId();
}

 

이후에 데이터베이스에서 경로를 데려왔을 때, 내가 원하는 모양이 아니다,,,! 관련 이슈

 

 

저 못생긴 file: 이게 대체 왜 붙는 것인지, 모르겠어서 그냥 없애봤다.

 

final Resource resource = resourceLoader.getResource(String.valueOf(path));

 

근데 에러가 난다.

 

java.lang.RuntimeException: java.io.FileNotFoundException: ServletContext resource [/src/main/pdf/baa5bc59-c095-4bf7-a724-92c922d34b14_28번.pdf] cannot be resolved to URL because it does not exist

 

💋 문제원인

 

대체 이 둘의 차이가 뭐지?

 

final Resource resource = resourceLoader.getResource("file:" + path);

 

final Resource resource = resourceLoader.getResource(String.valueOf(path));

 

 

첫 번째 코드에서는 "file:" 프로토콜을 명시적으로 써줘서 경로(path)가 파일 시스템 경로일 것으로 가정하고, resourceLoader는 파일 시스템에서 저 경로로 가서 리소스를 반환한다.

그러나 두 번째 코드에서는 "file:" 프로토콜을 사용하지 않고 path만을 사용하여 리소스를 로드하기 때문에 path가 파일 시스템 경로인지, 또는 다른 유형의 리소스 경로인지 확실히 알지 못한다. 만약 path가 파일 시스템 경로가 아니라면 이렇게 작성된 코드는 오류를 발생시킬 수 있다고는 하는데,,,

 

 

사실 저 파일이 제대로 저장은 되어 있거덩? 근데 명시적으로 어떤 유형의 리소스인지를 알려주는게 더 좋을 것 같다.

 

💋 해결방법

Resource라는 인터페이스가 너무 여러 리소스에 대해 범용적이어서 발생하는 문제다.

 

Spring Framework의 Resource 인터페이스는 다양한 유형의 리소스를 추상화하기 위해 설계된거니깐, 난 굳이 파일을 쓰는게 명백한데 여기서 저 젤 꼭대기 인터페이스를 쓸 필요는 없을 것 같다.

 

실제로도 리소스 종류는 저래 다양하니 아마도 내가 썼던 두번째 코드는 1, 2 중에 구분을 못하는 것 같다.

 

 

나는 그래서 FileSystemResource를 사용하도록 코드를 수정했다.

 

private String saveFile(final MultipartFile file) {
	String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
	final Path path = Paths.get("src", "main", "pdf", fileName);

	try {
		Files.copy(file.getInputStream(), path);
		Resource resource = new FileSystemResource(path.toFile());
		return resource.getFile().getPath();
	} catch (IOException e) {
		throw new RuntimeException(e);
	}
}

 

"file:" 프로토콜을 명시할 필요도 없어져서 코드가 더 명확하고 간결해졌다. 파일 시스템에서 리소스를 로드하는 데 특화된 클래스를 사용하는 것이 더 바람직하다!

 

 

도움이 되었다면, 공감/댓글을 달아주면 깃짱에게 큰 힘이 됩니다!🌟
비밀댓글과 메일을 통해 오는 개인적인 질문은 받지 않고 있습니다. 꼭 공개댓글로 남겨주세요!

 

반응형