TroubleShooting

java jar 배포 시 파일을 찾을 수 없습니다. [해결방법]

에디개발자 2020. 11. 9. 17:47
반응형

 

Spring boot는 내장 톰캣이 있기 때문에 jar배포를 하면 내부적으로 톰캣을 띄울 수 있습니다.  그런데 배포하자마자 resource에서 excel file 읽어올 때 에러가 났습니다. fileNotfound!!!

문제되는 소스는 아래와 같습니다.

File file = ResourceUtils.getFile("classpath:" + filePath);

Local에서는 정상작동하는데 왜 안되는가 하고 여러가지 시도를 했습니다.

 

 

URL은 잘 가져오나?

URL url = ResourceUtils.getURL("classpath:"+filePath);

결과는

url=jar:file:/home/yongtae/server/test-project-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/excel/

잘 가져온다! 근데 경로가 이상하다. 

 

경로때문에 문제가 있는건가? "jar: file: !" 지워보자

소스 수정하고 다시 도전해보자

String url = url.replace("jar:", "").replace.("file:", "").replace("!");
File file = ResourceUtils.getFile("classpath:" + filePath);

결과는 똑같이 fileNotFound..

 

더 구글링을 해보니 jar로 배포하면 jar 내부에 있는 file에 접근하려면 getFile으로는 불가능하다고 합니다.

결국 직장동료의 도움을 받아 ClassPathResource클래스를 쓰면 된다고 합니다.

 

해결

아래 소스로 하면 에러없이 작동합니다!

ClassPathResource classPathResource = new ClassPathResource(filePath);

if(classPathResource.exists() == false){
    log.error("Invalid filePath : {}", filePath);
    throw new IllegalArgumentException();
}
log.info("file path exists = {}", classPathResource.exists());

try (InputStream is = new BufferedInputStream(classPathResource.getInputStream())) {
	// logic...
}

 

ClassPathResource 내부 소스를 보니 클래스 생성 시 path와 classLoader를 생성합니다.

	public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
		Assert.notNull(path, "Path must not be null");
		String pathToUse = StringUtils.cleanPath(path);
		if (pathToUse.startsWith("/")) {
			pathToUse = pathToUse.substring(1);
		}
		this.path = pathToUse;
		this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
	}

 

file을 stream 형식으로 읽어옵니다.

	@Override
	public InputStream getInputStream() throws IOException {
		InputStream is;
		if (this.clazz != null) {
			is = this.clazz.getResourceAsStream(this.path);
		}
		else if (this.classLoader != null) {
			is = this.classLoader.getResourceAsStream(this.path);
		}
		else {
			is = ClassLoader.getSystemResourceAsStream(this.path);
		}
		if (is == null) {
			throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
		}
		return is;
	}

 

결론

결론적으로 jar 배포를 하면 jar 안의 file에 접근하려면 Stream을 사용해야합니다

반응형