일반적으로 웹 프로젝트를 진행해보면 디자인은 디자인팀에서, 프로그램은 프로그램 개발팀에서 별개로 진행하게 되어 별개의 산출물이 만들어진다. 그래서 개발팀의 프로젝트 소스에 디자인 산출물, 예를 들어 이미지나 CSS 파일을 일일이 받아 넣기가 곤란하거나 효율상 넣지 않기로 하는 경우가 대체적인 프로젝트 흐름이다. 이럴 때 개발팀에서 톰캣의 컨텍스트 외부로 경로 매핑하는 방법이 필요해진다.

원칙적으로 소스 버전 관리를 통해서 산출물을 공유하면 좋지만 디자인팀은 아… 그런 거 골치아파요하거나 일단 진행하다가 나중에 넣을께요하며 시간 지연 작전을 쓴다. 또한 개발팀은 개발팀대로 이미지는 파일 크기가 상당히 큰 편이다 보니 프로젝트 폴더에 이미지를 넣고 주고 받는 게 심적으로 부담스러운 면도 있다.

아무튼 이렇게 정적인 자원(디자인 산출물)을 별개로 관리할 경우 개발팀에서 Tomcat으로 개발 중인 웹페이지를 띄울 때 어떻게 하는 게 좋을까? 예를 들어 컨텍스트 경로는 /, 즉 루트고 실제 경로는 d:\project\webapp이라고 하자. 그런데 이미지 경로는 /img이고 실제 경로는 d:\project\design\img일 경우 어떻게 할까? 또는 이미지의 실제 경로가 같은 컴퓨터에 있지 않고 예를 들어 http://123.45.67.89/img에 있다면?

우선 한 컴퓨터 안에 정적인 자원과 자바 컨텍스트가 같이 있되 폴더 위치는 다른 경우를 살펴보자.

아파치 HTTP 서버 + 톰캣

톰캣(Tomcat) 앞에 아파치(Apache) 웹서버를 프록시로 두는 경우는 서버 기계가 여러 대인 운영 서버 환경에서 자주 볼 수 있는 조합이다. 개발 환경에서는 꼭 이렇게 할 필요는 없겠지만 아무튼 이런 경우는 처음부터 아파치 웹서버가 독립적으로 정적인 자원을 서비스하므로 톰캣이 서비스하는 자바 컨텍스트와 아무 상관이 있을 게 없다. 웹서버는 웹서버대로 웹폴더 위치를 지정하고 톰캣은 톰캣대로 웹폴더 위치를 지정하면 된다.

혹시 아파치 웹서버 2.2 이상에서 웹서버와 톰캣을 연동해주는 프록시 설정을 알고 싶다면 여기를 보도록 한다.

톰캣 6 이상(6, 7, 8 공통)

톰캣 6부터는 2단계 이상 디렉터리 구조의 컨텍스트를 지원한다. 무슨 말인가하면 /www와 같은 컨텍스트 뿐 아니라 /www/img와 같은 경로를 별도의 컨텍스트로 독립시킬 수 있다.

방법은 컨텍스트 설정 xml 파일을 "경로1#경로2.xml"과 같은 이름으로 만들어 컨텍스트 설정 파일 경로인 $CATALINA_BASE/conf/[enginename]/[hostname] 폴더에 넣어두는 것이다. 기본 설치 상태인 경우 [enginename]은 "Catalina"고 [hostname]은 "localhost"가 된다. 그리고 파일 내용은 예를 들어 다음과 같이 될 것이다.

<Context path="/img" reloadable="true" docBase="d:\project\design\img">
</Context>

이클립스 같은 개발 환경에서는 위의 설정 파일이 위치하는 경로에 파일을 넣어주기 보다는 Servers 프로젝트에서 톰캣 설정 파일 server.xml 파일을 열어 <Context>를 추가해주는 게 더 편리하다.

톰캣 7

위 방법은 정적인 자원 폴더가 예를 들어 /www/img, /www/css, /www/js 등과 같이 여럿일 경우 설정하는 작업이 귀찮아진다. 또한 설정 파일을 별개로 서버에 작업해 넣어야 하므로 소스 버전 관리가 되지 않는 문제도 있다.

톰캣 7에서는 aliases를 설정할 수 있다.

<Context ...
aliases="/img=d:\project\design\img,/js=d:\project\design\js,/css=d:\project\design\css"/>

</Context>

또한 가상 경로를 설정할 수도 있다. 동작상으로는 위의 aliases와 다를 건 없다. 컨텍스트 설정 파일에 다음과 같이 Resources 태그를 추가하면 된다.

<Context ...>
<Resources className="org.apache.naming.resources.VirtualDirContext"
extraResourcePaths="/img=d:\project\design\img,/js=d:\project\design\js,/css=d:\project\design\css"/>

</Context>

이러한 설정 내용은 META-INF/context.xml에 넣는 것이 프로젝트 소스를 관리하는 면에서 편리하다. 그런데 위에서 aliases의 경우는 경로 설정 문자열의 컴마나 등호 앞뒤로 빈칸이나 줄바꿈 같은 게 있을 수 있으나 가상 경로는 있으면 안된다.

또 한 가지 주의할 점은 (이미 다 알고 하고 있겠지만 확인 차원에서 말하자면) 스프링 같은 프레임웍을 사용할 경우 대개 WEB-INF/web.xml 파일에서

    <servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

와 같이 모든 경로를 스프링의 디스패처 서블릿으로 서비스하도록 설정하는 경우가 일반적인데 이 경우 정적인 자원도 스프링에서 처리하도록 돼 있기 때문에 스프링 설정에서

    <mvc:resources mapping="/img/**" location="/img/" />
<mvc:resources mapping="/css/**" location="/css/" />

와 같이 정적인 자원은 배제하는 게 필수라는 것이다.

톰캣 8

톰캣 7의 혼란스러운 설정들은 톰캣 8에서 과감히 정리됐다. <Context> 태그 안에 PreResources, JarResources, PostResources 등을 설정할 수 있게 바뀌었는데 JAR 파일에 정적인 자원을 넣어 서비스하는 경우가 아니라면 일반적으로 PreResources를 설정하면 된다.

<Context ...>
<PreResources className="org.apache.catalina.webresources.DirResourceSet"
webAppMount="/img" base="d:\project\design\img"/>

</Context>

정적인 자원이 원격지(다른 컴퓨터)에 있는 경우

마지막으로 정적인 자원이 자바 컨텍스트가 위치한 컴퓨터와는 다른 컴퓨터에 있는 경우를 알아보자. 이 경우는 좀 번거롭지만 정적인 자원의 경로 앞에 원격지의 주소를 일일이 붙여주는 수 밖에 없다.

<html>
...
<img src="http://123.45.67.89/img/category/abc123_on.png" >
...
</html>

원격지의 주소는 개발 중 바뀔 수도 있고 운영 서버로 최종 배포할 때도 바뀔 가능성이 많으므로 스프링 같은 프레임웍이나 JSTL을 사용한다면 원격지 주소를 설정 파일 같은 곳에서 변수로 뽑아오는 것이 편리하다.

<img src="${resourcePath}/img/category/abc123_on.png" >

이상으로 글을 마치며 디자인팀과 개발팀의 조화로운 프로젝트 진행을 꿈꿔본다. 😉