HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🤩
개발
/
Spring
Spring
/
🎧
Spring Framework 핵심개념(Core)
/
💻
Resource
💻

Resource

[참고] Spring Framework Documentation
 
설명SpringBoot 에서 getResource 사용 시, 생기는 문제 → getResource를 사용할 때는 prefix를 확실하게 붙여줘라resource 폴더에서 파일 읽기Jar 파일 안에서 위의 코드로 FileNotFoundException 발생resource 폴더에 파일 쓰기
 

설명

  • 리소스는 파일 시스템에서 읽을 수도 있고 classpath 에서 읽을 수도 있고 url을 통해 웹에서 다운 받아서 얻어 올 수도 있음
  • java에서는 이러한 모든 IO를 Resource와 ResourceLoader 클래스를 통하여 하나의 API로 제공함
  • 모든 ApplicationContext interface 는 ResourceLoader interface를 상속함
notion image
notion image
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 기준으로 찾게 됨
notion image
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]
      • getFile() api를 이용하면 파일시스템에서 찾으려고 함. 그러나 jar 파일 내부에서는 파일 시스템을 통한 접근이 불가능하기에 getInputStream 메서드를 이용해서 읽어와야 함
💡
요약 - 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 로 생성되게 됨