Backend/spring (Boot)

[Spring] (프로젝트 외부) 정적 리소스 처리

dddzr 2025. 7. 26. 16:27

📌0. 서블릿 컨테이너 기본 동작

자원이 프로젝트 내부 /resources 또는 /static 밑에 있을 때

 0-1. Spring MVC (레거시 설정, xml 기반)

  • DispatcherServlet을 /에 매핑하면 모든 요청이 DispatcherServlet으로 감.
  • 정적 리소스도 DispatcherServlet을 거치게 됨 → 그래서 Spring이 ResourceHttpRequestHandler를 통해 다시 정적 리소스 처리를 해줘야 함.

 0-2. Spring Boot 동작 원리

스프링부트는 자동으로 ResourceHandlerRegistry를 등록해서, 별도 mvc:resources를 안 써도 정적 리소스 핸들러가 붙음.

  • 기본 매핑 경로:
    • classpath:/static/
    • classpath:/public/
    • classpath:/resources/
    • classpath:/META-INF/resources/
  • 그래서 static/images/test.png 같은 파일을 두면 http://localhost:8080/images/test.png 로 바로 접근 가능.

 

📌 1. 자원이 프로젝트 외부에 있을 때

  1. 톰캣 같은 컨테이너는 기본적으로 / 요청을 DefaultServlet이 처리 → 정적 파일(css, js, 이미지 등)을 찾아서 반환.
  2. 그런데 내 프로젝트에서는 썸네일(/thumb-images/**)이 웹앱 내부의 정적 리소스가 아니라, 외부 경로(file:/appl/upfiles/thumbnails/) 에 있음.
  3. DefaultServlet은 webapp/ 경로밖의 파일은 몰라서 못 서빙함 → 그대로 404.

 

📌 1-1. Spring MVC 설정

정적 리소스를 사용하려면 반드시 설정해야 할 파일

✅ 1-1-1. web.xml 설정 (DispatcherServlet 매핑)

이 설정으로 인해 /thumb-images/** 같은 정적 요청도 DispatcherServlet을 거치게 됨

<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern> <!-- 모든 요청을 Spring으로 전달 -->
</servlet-mapping>

 

✅ 1-1-2. servlet-context.xml (또는 dispatcher-servlet.xml) 설정

DispatcherServlet이 들어온 요청을 HandlerMapping → mvc:resources 설정에 따라 ResourceHttpRequestHandler로 연결.

DispatcherServlet이 요청을 받고, ResourceHttpRequestHandler가 외부 경로를 찾아 반환

<!-- (1) DispatcherServlet이 못 찾는 정적 리소스를 서블릿 컨테이너에게 위임 -->
<mvc:default-servlet-handler />

<!-- (2) 정적 리소스 매핑 -->
<mvc:resources mapping="/thumb-images/**" location="file:/appl/upfiles/thumbnails/" />

<!-- 로컬 개발 시 -->
<!-- <mvc:resources mapping="/thumb-images/**" location="file:/D:/appl/upfiles/thumbnails/" /> -->

<!-- (3) 기타 static 리소스 -->
<mvc:resources mapping="/resources/**" location="/resources/" />
  • file: 접두사는 절대경로 기반을 의미
  • classpath:는 WAR 내부 리소스를 가리킴 (자주 쓰는 /static/, /public/ 등 포함)

📌 1-2. Spring Boot 설정

/resource 경로에 있는 건 설정 x, 외부 경로는 설정 필요

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/thumb-images/**")
                .addResourceLocations("file:/appl/upfiles/thumbnails/");
    }
}

 

📌 2. 리소스 경로 설정 (Window / Linux)

환경 설정 예시 (servlet-context.xml)
로컬(윈도우) file:/D:/appl/upfiles/thumbnails/
운영(리눅스) file:/appl/upfiles/thumbnails/
  •  D:/ 드라이브는 리눅스에서는 인식되지 않음
  • 반드시 슬래시 / 로 끝나는 경로로 지정해야 정상 동작

 

📌 3. 테스트 방법 및 확인 포인트

1️⃣ 브라우저에서 정적 파일 요청

GET /thumb-images/thumb_20250714131822380.jpg

 

2️⃣ 로그 확인: DispatcherServlet → ResourceHttpRequestHandler

Mapped to ResourceHttpRequestHandler [URL [file:/appl/upfiles/thumbnails/]]

 

3️⃣ 정상 응답이면 200 OK
❌ 404 에러면 아래 항목들 확인

 

📌 4. 404에러 (에러 로그 → 원인 추적 → 해결)

사실 이게 글 쓴 이유다.

🔍 현상: 이미지 404, 정적 리소스 응답 안됨

 

🔹 로그 분석

Mapped to ResourceHttpRequestHandler [URL [file:/D:/appl/upfiles/thumbnails/]]

Resource not found

 

-- 전체 로그

15:56:50.455 [DEBUG] --- [https-jsse-nio-443-exec-1] o.s.w.s.h.SimpleUrlHandlerMapping.getHandler:523: Mapped to ResourceHttpRequestHandler [URL [file:/D:/appl/upfiles/thumbnails/]] 15:56:50.455 [DEBUG] --- [https-jsse-nio-443-exec-1] o.s.w.s.r.ResourceHttpRequestHandler.handleRequest:560: Resource not found

 

🔹  원인 확인 명령어 (리눅스 서버)

# 경로 존재 여부 확인
ls -l /appl/upfiles/thumbnails/thumb_20250626145206541.079.jpg

# 경로 권한 확인
ls -ld /appl/upfiles/thumbnails
ls -l /appl/upfiles/thumbnails

# SELinux context 확인
ls -Z /appl/upfiles/thumbnails

 

🔹  확인된 문제

나의 경우에는 파일 업로드 시 사용하는 경로 변수가 아래와 같게 설정되어 있어서 D디렉토리 경로를 포함시킨게 문제였다. (로컬은 윈도우, 서버는 로키서버 였음)

<entry key="file.thumbnail.path">D:/appl/upfiles/thumbnails</entry>

 

[root@ebiz logs]# ls -l D:/appl/upfiles/thumbnails/thumb_20250626145206541.079.jpg

ls: cannot access 'D:/appl/upfiles/thumbnails/thumb_20250626145206541.079.jpg': No such file or directory

[root@ebiz logs]# ls -l /appl/upfiles/thumbnails/thumb_20250626145206541.079.jpg

-rw-r--r--. 1 root root 151195  6월 26 14:52 /appl/upfiles/thumbnails/thumb_20250626145206541.079.jpg

 

항목 결과
요청 URL /thumb-images/thumb_20250626145206541.079.jpg
로그상 매핑 file:/D:/appl/upfiles/thumbnails/ (리눅스에서 X)
리눅스 실제 경로 /appl/upfiles/thumbnails
파일 권한 -rw-r--r-- (정상)
디렉토리 권한 drwxr-xr-x (정상)
SELinux context default_t (비정상)

 

🔧 해결 방법

나는 1번만으로 해결 됐는데 404에러 발생시 아래 2, 3 방법도 체크 할 것!!

1️⃣ 경로 수정 

<!-- 잘못된 경로 -->
<mvc:resources mapping="/thumb-images/**" location="file:/D:/appl/upfiles/thumbnails/" />

<!-- 리눅스에서의 정상 설정 -->
<mvc:resources mapping="/thumb-images/**" location="file:/appl/upfiles/thumbnails/" />

 

2️⃣ SELinux context 수정

sudo semanage fcontext -a -t httpd_sys_content_t "/appl/upfiles/thumbnails(/.*)?"
sudo restorecon -Rv /appl/upfiles/thumbnails

 

3️⃣ 접근권한 설정

chmod 644 /appl/upfiles/thumbnails/*
chmod 755 /appl/upfiles/thumbnails

 

🚀 마무리 체크리스트

항목 확인
DispatcherServlet이 모든 요청을 수신하는지 ✅ web.xml 확인
<mvc:resources> 설정이 올바른지 ✅ file:/경로/
리눅스의 경로 사용이 맞는지 ✅ D:/ ❌
디렉토리와 파일 권한 설정 ✅ chmod, ls -l
SELinux가 차단하고 있지 않은지 ✅ ls -Z, semanage