View Resolver와 그 처리과정에 대한 단상
스프링에서의 View Resolver는 요청을 해석한 뒤, 어떤 내용을(파일 포함) 요청자에게 돌려줘야하는지를 결정해 주는 객체이다.
즉, 특정 URL에 대해 요청이 들어오면 어떤 View가 되도록 어떻게 일해야 하는지 스스로 알고있다는 것이다.
클라이언트가 어떤 View를 보고싶다는 요청을 했다고 가정하자. 그 View는 이미지 파일을 http://fureweb.com/image/a.jpg 이와같은 형태로 http 프로토콜을 이용하여 서버에 자원을 요청한다고 가정한다.
1. 요청을 보낸 클라이언트는 웹 브라우저였다. 웹 브라우저에서 이미지를 해석하려면, Response Header에서 Content-Type이 image/jpeg 등의 브라우저가 해석할 수 있는 헤더가 박혀있어야 이미지 파일로 랜더링 해 줄 것이다. 바이너리를 뒤져서 헤더 어디까지 찾아보고 알아서 맞춰주는 형태의 라이브러리 같은것이 분명히 있겠지만, 현재는 찾아본적이 없어 일단.. –; 어쨌든 이러한 요청을 톰캣 컨테이너에서 감지한 이후 웹브라우저에 응답하는 전체 과정을 정리겸 한번 살펴보겠다.
2. 컨트롤러에서 /image/{fileName}.{ext} 형태와 같은 요청이 들어온 이후 서버에서 response처리 하기까지의 전체 흐름은 아래와 같다.
- @PathVariable 애노테이션을 이용하여 두개의 String 값을 저장하고, map에 key-value형태로 넘겨줄 object를 put한다.
- AbstractView를 extends한 View Resolver가 사용할 map에 받아온 String을 필요한 형태로 담아 View Resolver가 이해할 수 있는 형태로 return시켜준다. (xml 또는 configuration을 통해 bean container에 등록되어있는 bean의 이름-name 또는 id-을 사용해야 할 것이다.)
- return을 통해 View Resolver가 파일에 대한 요청임을 이해한 뒤, 클라이언트가 원하는 파일을 서버에서 찾아 다음과 같은 과정을 수행한다. 해당 View Resolver는 org.springframework.web.servlet.view.AbstractView 클래스를 extends하고 있어야 한다. 또한 해당 리졸버는 abstract method인 renderMergedOutputModel 메소드를 반드시 구현해야한다.
- response의 OutputStream에 flush하기 전, response객체에 header를 설정한다.
- 만약 download 해야하는 컨텐츠인 경우, Content-Disposition의 filename 에는 java.net.URLEncoder .encode 메소드를 사용하여 파일명을 utf-8로 인코딩한 값을 넣어준 뒤 attachment와 filename 설정을 처리한다.
- Content-type을 받아온 확장자명에 따라 알맞은 형태로 작성해준다. jpg가 들어온 경우, response.setHeader(“Content-Type”, “image/jpeg”); 이러한 형태가 될 것이다.
- 헤더를 모두 작성한 뒤 response 객체로부터 getOutputStream() 한 결과를 OutputStream 객체에 담는다.
- FileInputStream 객체를 하나 생성하면서, 해당 파일의 절대경로를 String Type으로 넣어준다.(파일명 포함)
- org.springframework.util.FileCopyUtils 클래스의 copy 메소드를 이용하여, FileInputStream 객체와, OutputStream 객체를 차례대로 1번, 2번 인자로 넣어준다.
- OutputStream객체를 flush한다.
3. 위 흐름을 통해 클라이언트의 웹브라우저에서 서버에 존재하는 a.jpg파일 (혹은 그 요청에 응답하는 다른 경로의 어떤 jpeg 이미지 헤더를 가진 바이너리)을 응답받아 눈으로 확인할 수 있게 되는 것이다.
잡담을 마치며
Customized된 View Resolver를 사용하기 위해서는 스프링 빈 컨테이너에 org.springframework.web.servlet.view.BeanNameViewResolver가 이미 인스턴스화 되어있어야한다. 또한 모든 View Resolver보다 우선순위가 가장 높아야 한다. beans 선언부에 xmlns:p=”http://www.springframework.org/schema/p” 값을 설정해 놓았다면, p:order=”0″ 형태로 우선순위를 정할 수 있고, 그렇지 않았다면 property name을 해당 빈을 인스턴스화 하기 전, 프로퍼티를 가질 수 있도록 값을 설정해 줘야 할 것이다. <property name=”order” value=”0″/>과 같은 형태로.
어서 빨리 xml 설정이 없는 세상으로 넘어가고싶다. 스프링 캠프에서 대충 맛만 보고, 여기저기 웹사이트에서 눈팅하며 얻은 내용들이 고작. 아직 Configuration 같은 애노테이션을 제대로 써본적이 없는데, 빨리 배워 적용해보고싶다!
최근 댓글