설명SpringBoot 에서 getResource 사용 시, 생기는 문제 → getResource를 사용할 때는 prefix를 확실하게 붙여줘라resource 폴더에서 파일 읽기Jar 파일 안에서 위의 코드로 FileNotFoundException 발생resource 폴더에 파일 쓰기
설명
- 리소스는 파일 시스템에서 읽을 수도 있고 classpath 에서 읽을 수도 있고 url을 통해 웹에서 다운 받아서 얻어 올 수도 있음
- java에서는 이러한 모든 IO를
Resource
와ResourceLoader
클래스를 통하여 하나의 API로 제공함
- 모든 ApplicationContext interface 는 ResourceLoader interface를 상속함


AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); var resource = context.getResource("application.yaml"); var resource2 = context.getResource("file:sample.txt"); System.out.println(resource2.getClass().getCanonicalName()); var strings = Files.readAllLines(resource2.getFile().toPath()); System.out.println(strings.stream().reduce("", (a, b) -> a + "\n" + b));
- 위와 같이 getResource안에 그냥 파일 이름 쓰면 default로 classpath에서 찾음 →
ClassPathContextResource
반환(classpath:
라고 붙여주어도 됨 →ClassPathResource
반환)
file:
을 붙여주면 Workingdir 기준으로 찾게 됨

var resource3 = context.getResource("https://stackoverflow.com/"); var readdableByteChannel = Channels.newChannel(resource3.getURL().openStream()); var bufferedReader = new BufferedReader(Channels.newReader( readdableByteChannel, StandardCharsets.UTF_8)); var contents = bufferedReader.lines().collect(Collectors.joining("\n")); System.out.println(contents);
SpringBoot 에서 getResource 사용 시, 생기는 문제 → getResource를 사용할 때는 prefix를 확실하게 붙여줘라
- context.getResource()는 context의 종류에 따라 반환하는 default Resource 구현체가 달라짐
- SpringBoot에서 사용하는 ApplicationContext는 AnnotationConfigServletWebServerApplicationContext인데 얘의 getResource() 에서 반환하는 Resource는 ServletContextResource임.
- 근데 ServletContextResource는 관련된 웹 어플리케이션의 root 디렉토리에서 상대경로로 파일을 찾게 됨.
resource 폴더에서 파일 읽기
[ Spring Docs ] PathMatchingReousrcePatternResolver
public static String readFileFromResourceFolder(String fileName) throws IOException { ResourcePatternResolver resourcePathResolver = new PathMatchingResourcePatternResolver(); Resource resource = resourcePathResolver.getResource("classpath:%s".formatted(fileName)); return FileUtils.readFileToString(resource.getFile(), Charset.defaultCharset()); }
ResourcePatternResolver
인터페이스를 통해 location pattern(eg- Ant-style path pattern)으로Resource
를 찾아올 수 있음
PathMatchingResourcePatternResolver
가 ApplicationContext의 바깥에서 사용할 수 있는ResourcePatternResolver
의 유일한 standalone 구현체
classpath*:
Prefix해당 Prefix를 붙임으로 해서 같은 이름의 여러 경로에 존재하는 리소스를 불러올 수 있음
예를 들어, "
classpath*:META-INF/beans.xml
" 는 클래스 패스에 존재하는 모든 "META-INF/beans.xml" 파일들을 찾음 (classes 폴더나 JAR 파일 안에서)This is particularly useful for autodetecting config files of the same name at the same location within each jar file.
Jar 파일 안에서 위의 코드로 FileNotFoundException 발생
[ Stackoverflow ] Classpath resource not found when running as jar
public static String readFileFromResourceFolder(String fileName) { Resource resource = resourcePatternResolver.getResource("classpath:%s".formatted(fileName)); try { System.out.println(resource.getURL()); return IOUtils.toString(resource.getInputStream(), Charset.defaultCharset()); } catch (IOException e) { throw new IllegalArgumentException(e); } }
- Local에서 실행했을 시 Resource 파일의 경로
file:/Users/gilgeun-o/Desktop/Projects/VirtualOffice_WebServer/backend/core/build/resources/main/ec2_user_data.txt
- Jar 파일에서 실행했을 시 Resource 파일 경로
jar:file:/Users/gilgeun-o/Desktop/Projects/VirtualOffice_WebServer/backend/core/build/libs/core-0.0.1.jar!/BOOT-INF/classes!/ec2_user_data.txt
jar -tf [JAR 파일명]
명령어로 jar 파일 내부에 리스트를 볼 수 있음- resource.getFile() 로 jar 안의 클래스패스 내부의 파일에 접근시 발생하는 오류
java.io.FileNotFoundException: class path resource [static/docs/index.html] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/Users/gilgeun-o/Desktop/Projects/VirtualOffice_WebServer/ backend/core/build/libs/core-0.0.1.jar!/static/docs/index.html]
요약
- classpath 자체에는 문제가 없음
- getFile() api 이용 시 파일시스템을 통해 읽어오려 함. getInputStream()을 이용하여 데이터 읽어오기
resource 폴더에 파일 쓰기
File buildClassesFolder = resourcePatternResolver.getResource("classpath:.") .getFile(); File file = new File(buildClassesFolder + "/%s".formatted(fileName)); file.createNewFile();
- 여기서 buildClassesFolder는 사실 resources 폴더가 아닌 컴파일된 build/classes/java/main 경로를 가리킴. 즉 파일 생성시 build/classes/java/main/filename.txt 로 생성되게 됨