오늘의 삽질 일기.
어제 쓴 내용과 비슷한 일을 하고 있었다.
작업 내용은 내가 만든 프로젝트를 jar파일로 묶어서 실행하는 것이다.
어제 글을 쓴거 처럼 생성된 jar는 pom.xml의 모든 dependency library를 포함하였으며, manifest도 만들어서 실행가능한 jar 상태이다.
문제는.. 리소스를 읽을 때 파일을 찾지 못한다는 것이다.
project 내부에 있는 src/main/resources/font 폴더를 읽어야하는데, jar가 묶이기 전인 이클립스 프로젝트에서는 잘 실행이 되지만, jar파일이 패키징한 뒤 실행하면 font폴더를 찾지 못하는 것이다. (이것 또한 옛날에 겪은 내용인데, 적어놓지 않아서 까먹음..)
내용은 아래와 같다.
getClass().getResource("font").getPath() 를 이용하여 자원의 경로를 설정하여 그 안에 자원들을 사용한다.
이클립스(eclipse)
=> 정상 동작
Jar로 묶었을 때
=> file:/C:/main/workspace/aspose/target/aspose-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/font
=> 찾지 못함.. 어떻게 해결할까
일단 리소스와 관련되서 많이 보게되는 getResource() 함수에 대해 조사했다.
검색해보니 나와같은 사람이 많다...
getClass().getResource() 와 getClass().getClassLoader().getResource() 의 차이점이다.
많은 자료가 있었으나 가장 이해가 쉽게 되었던 포스팅을 참고해서 말하자면,
일단 밑에 2가지를 알아야 한다고 한다.
1. .jar 파일로 빌드시 최상위인 루트 디렉토리에 위치하게 되는데 런타임시 해당 파일들이 ROOT CLASSPATH에 위치한다는 것을 의미
2. CLASSPATH의 ROOT에 위치하므로 절대 경로인 /를 앞에 명시함으로 리스소 파을 로드할 수 있음 (상대 경로로 명시할 경우 호출한 클래스의 위치에 따라 경로가 달라짐)
따라서 코드로 표현해보면
getClass().getResource("D2Coding.ttf"); // 현재 클래스 위치에서 리소스를 찾는다. (같은 곳에 존재해야함)
getClass().getResource("/font/D2Coding.ttf"); // 패키지와 동일 루트에서 검색
getClass().getClassLoader().getResource("D2Coding.ttf"); // 패키지와 동일 루트에서의 상대 위치를 나타낸다. (항상 절대경로만 인식하여 사용된다.)
이렇다.
그래 이제 대충 무슨 얘긴줄 알겠다. 그래서 jar안에 있는 resource는 어떻게 읽을까?
저 위의 차이점을 알아도 문제가 있다.. 무슨 문제냐면 이클립스(개발환경)에서 리소스를 찾게 설정하면 jar파일로 패키징했을 때 리소스에서 못 찾고, jar파일에서 리소스를 찾게하면 이클립스(개발환경)에서 리소스를 못찾게 되는...
그래서 두곳에서 작성할 수 있게
if(new File(this.getClas().getRsource("/font").toPath()).exist()){
// 이클립스에서 동작
}else if(new File("font")){
// jar패키징했을때 동작
}
해서 꼼수를 부릴려고 했으나, 뭔가 코드가 아름답지 않아서..
해결을 못하고 회사 대리님한테 물어봤는데.. 대리님께서 친절하게 메일로 답장을 주셨다.
spring-core lib를 사용하면 될것 같다고하셔서 간단하게 한번 찾아봤다.
리소스 => src/main/resources (*.java 처럼 컴파일 대상이 되는 소스파일이 아닌 파일들)
스프링 프레임워크에는 이러한 CLASS_PATH에 저장된 리소스 파일들을 쉽게 가져올 수 있도록 ClassPathResource 클래스 제공한다고 한다.. (git을 뒤져보니 예전에도 이녀석을 썼었다..)
내일 출근하면 ClassPathResource를 사용해서 문제를 해결해봐야겠다.
포스팅은 곧 ... 주말에 할수있겠지?
시간이 늦었으니 이만 자야겠다.