Spring으로 방명록 애플리케이션을 구현하는 시리즈입니다.
- [Spring] 방명록 애플리케이션 (1) - 환경 설정
- [Spring] 방명록 애플리케이션 (2) - 준비 단계 ( 스프링 활용하기 )
- [Spring] 방명록 애플리케이션 (3) - 구현
- [Spring] 방명록 애플리케이션 (4) - 정적 파일 처리 ( DefaultServletHandler )
- [Spring] 방명록 애플리케이션 (5) - 뷰 객체 생성 ( ViewResolver )
- [Spring] 방명록 애플리케이션 (6) - 예외 처리 ( ExceptionHandler )
- [Spring] 방명록 애플리케이션 (7) - 3 Layer Architecture와 Service 계층
- [Spring] 방명록 애플리케이션 (8) - 커넥션 풀 ( Connection Pool ) DBCP
- [Spring] 방명록 애플리케이션 (9) - Mybatis 환경 설정
- [Spring] 방명록 애플리케이션 (10) - Mybatis 적용
Default Servlet Handler
톰캣은 클라이언트의 요청 URL을 보고 Servlet Mapping에 따라 URL에 매핑된 Servlet이 처리를 하는 구조입니다.
그리고 URL에 매핑되는 Servlet이 없다면, 예를들어 CSS, image 파일 같은 정적자원들은 defaultSevlet이 처리하도록 되어 있습니다.
즉 CSS , image 파일들은 서버 외부에서 직접 접근 할 수 없는 /WEB-INF/assets 폴더 아래에 위치하는 것이 일반적인데,
CSS , image 파일에 접근하기 위한 Servlet Mapping을 하지 않았으면 톰캣이 defaultServlet으로 처리하여 정적 파일에 접근을 합니다.
일반적으로 정적 파일에 대해 Servlet Mapping을 하지 않죠.
스프링에서는 DispatcherServlet이 모든 요청을 받아 들인 후 Handler mapping table에 따라 컨트롤러로 분기 한다고 했었습니다.
그렇기 때문에 DispatcherServlet은 정적 파일에 대해 톰캣이 defaultServlet으로 실행할 수 있는 기회를 뺏어갑니다.
모든 요청은 일단 DispatcherServlet에서 처리해버리기 때문이죠.
정적 자원에 접근하기 위한 경로 설정을 JSP/Servlet과 똑같이 해도 스프링에서는 경로를 읽지 못합니다.
정말 그런지 테스트를 해보도록 하겠습니다.
방명록 애플리케이션의 디렉토리 구조에서 webapp/assets/images 폴더를 생성하고 이미지 파일을 아무거나 저장해주세요.
그리고 index.jsp 파일에 아래의 태그를 추가해주세요.
<img src="/guestbook/assets/images/1.jpg">
그리고 http://localhost:8080/guestbook/main/index 을 요청하면 1.jpg를 불러오지 못하는 것을 확인할 수 있습니다.
그런데 Spring 프로젝트가 아닌 JSP/Servlet 프로젝트를 만들어서 똑같은 디렉터리 구조로 같은 코드로 <img> 태그를 추가하면 정상적으로 응답이 됩니다.
JSP/Servlet에서는 톰캣이 default Servlet이 있기 때문에 처리가 가능하지만,
스프링에서는 Dispatcher Servlet이 모든 요청을 받아들이기 때문에 톰캣의 default Servlet이 정적 파일을 처리할 수 있는 기회를 잃게 됩니다.
환경 설정
이제 스프링에서 CSS, image파일 등이 정상적으로 응답 될 수 있도록 환경 설정을 하도록 하겠습니다.
spring-servlet.xml 에 아래의 코드를 추가하면 끝납니다.
<!-- 서블릿 컨테이너의 디폴트 서블릿 위임 핸들러 -->
<mvc:annotation-driven />
<mvc:default-servlet-handler />
이 코드는 만약 Handler Mapping에 해당하는 URL이 없으면 default-servlet으로 처리하겠다는 의미입니다.
즉 매핑이 되지 않은 URL은 webapp폴더를 시작으로 경로를 찾아가게 되고, 여기에서도 해당 경로의 자원이 존재하지 않으면 404 Not found가 발생합니다.
* 의문점
<mvc:default-servlet-handler />만 있으면 되는 줄 알았는데 <mvc:annotation-driven /> 코드도 있어야 정상적으로 동작이 되더라구요.
이 부분은 조금 더 알아봐야 할 것 같습니다.
컨텍스트 경로
정적 파일의 경로를 작성할 때 자신의 애플리케이션 경로를 프로젝트 폴더 이름으로 작성하는 것 말고, JSTL 표기법으로 작성할 수도 있습니다.
두 번째와 같이 JSTL로 컨텍스트 경로를 설정하는 방법의 이점은 프로젝트 폴더의 이름을 URL 주소로 사용하고 싶지 않을 때입니다.
( 프로젝트 폴더의 이름이 guestbook 이라면, localhost:8080/guestbook/ 의 경로로 요청을 보내야 합니다. )
실제로 톰캣을 등록했을 때 생성되는 Server 폴더의 server.xml 파일 ( 127 line )에서 경로 수정이 가능합니다.
JSTL 표기법으로 컨텍스트 경로를 설정하면, 컨텍스트 경로를 변경했을 때 일일이 /guestbook 을 새로운 경로로 바꿔주는 수고를 덜 수 있습니다.
이상으로 스프링에서 정적 자원에 접근하기 위해 필요한 DefaultServletHandler에 대해 알아보았습니다.