지난 시간에 소스코드를 만들어보았다.
MVC 패턴에 대해서는 따로 언급을 하지 않을 예정이니 처음 듣는다면 인터넷에서 검색해서 공부하자.
(위키백과 - 한글 / 영문)
브라우저 관점
철처하게 스프링프레임워크를 떠나서 브라우저 관점에서 보자.
지난 시간에 봤던 아래 페이지는 웹브라우저의 주소로 부터 시작한다.
HTTP GET ( 호스트 - localhost / 포트 - 8080 / 경로 - /HelloWorld/ )
- 클라이언트(브라우저) 요청
GET /HelloWorld/ HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: ko
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0)
Accept-Encoding: gzip, deflate
Host: 10.17.29.20:8080
Connection: Keep-Alive
- 서버 응답
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=UTF-8
Content-Language: ko
Content-Length: 183
Date: Thu, 13 Sep 2012 02:46:54 GMT
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>
Hello world!
</h1>
<P> The time on the server is 2012년 9월 13일 (목) 오후 3시 52분 28초. </P>
</body>
</html>
서버관점
브라우저 관점에서는 서버란 HTML 페이지를 반환해주는 웹서버(TCP 서버)일 뿐이다.
이제 서버, 스프링 프레임워크에서 어떻게 요청을 처리하는지 따라가보자.
기본적으로 자바의 서블릿에 대해서는 알고 있는 것이 이해하기 편할 것이다.
웹 설정 파일(Web Configuration file)
서블릿은 기본적으로 web.xml 이라는 설정파일을 가지고 있다.
참고로 src/main/webapp/WEB-INF/web.xml 에 위치한다.
열어보면 아래와 같은 부분이 있을 것이다.
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
서블릿 이름은 appServlet이고, 서블릿 클래스가 'org.springframework.web.servlet.DispatcherServlet'로 지정이 되어 있다.
디스패처 서블릿(Dispatcher Servlet)
디스패처 서블릿은 클라이언트 요청을 핸들링하기 위해 앞단에서 컨트롤 하기 위해 존재한다.
클라이언트로 부터 오는 URL이 무엇이되던, 이 서블릿은 컨트롤러에 요청 객체로 넘겨주기 전에 클라이언트의 요청을 가로챌 것이다. 참고로 DispatcherServlet은 스프링라이브러리인 spring-webmvc-3.1.0.RELEASE.jar 안에 있다.
이 클래스는 아래와 같은 시그너처로 되어 있다.
public class DispatcherServlet extends FrameworkServlet
* FrameworkServlet - org.springframework.web.servlet.FrameworkServlet : 스프링의 웹 프레임워크를 위한 기본 서블릿이다. 전 솔루션에 걸쳐 자바빈 기반의 스프링 애플리케이션 컨텍스트를 이용하여 통합을 제공한다.
초기화 파라메터(init-param; initial parameter)
init-param은 초기화 파라메터를 설정하는 부분인데, 컨텍스트 설정 위치가 '/WEB-INF/spring/appServlet/servlet-context.xml'로 되어 있음을 알 수 있다.
servlet-context.xml
<annotation-driven />
<resources mapping="/resources/**" location="/resources/" />
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
맨위의 annotation-driven은 어노테이션 기반을 사용하겠다고 설정하는 것이다. 컨트롤러 작성을 xml 상에 일일이 <bean> 태그를 이용해서 스프링 빈으로 등록할 수 있으나 클래스에 @Controller 어노테이션을 붙이면 해당 클래스를 웹 요청을 처리하는 컨트롤러로 사용할 수 있다. (스프링 2.5부터 지원)
resources 태그는 HTTP GET으로 들어온 /resources/~ 형태의 요청(보통 정적 파일)을 웹어플리케이션루트/resources 디렉토리로 지정을 하겠다는 것이다.
웹 페이지에서 최종형태는 HTML 같은(PDF나 엑셀파일이 될 수 도 있다)형태의 뷰이다. 기본적으로 템플릿에는 jsp 페이지로 되어 있다. 컨트롤러는 ViewResolver를 통해 View 객체를 리턴하게 되는데 위에서는 'InternalResourceViewResolver'가 지정되어 있다.
/HelloWorld/ 요청은 어디로?
localhost의 8080포트로 GET /HelloWorld/ HTTP/1.1 요청을 한다고 봤다.
코드는 아래와 같다. (로거부분은 제외 시켰다.)
@Controller
public class HomeController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(
DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "home";
}
}
servlet-context.xml에서 annotation-driven에서 언급되었듯이 HomeController 클래스에 @Controller라는 어노테이션이 붙어있다. 어노테이션이 붙어있으면 서버가 시작할 때 RequestMappingHandlerMapping에 의해서 자동으로 등록이 된다.
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String com.tistory.namocom.HomeController.home(java.util.Locale,org.springframework.ui.Model)
HomeController에는 home이라는 메소드가 있는데 @RequestMapping이라는 어노테이션이 붙어있다. 요청처리를 매핑하기 위한 어노테이션인데, HTTP GET으로 "/"에 대한 처리를 담당한다고 보면 된다.
브라우저에서 요청한 http://localhost:8080/HelloWorld/는 결국 HomeController.home 이라는 메소드로 들어오게 되는 것이다.
이 home 메소드에서 해주는 일은 단순하다.
- java.text.DateFormat 클래스에서 현재 날짜와 시간을 해당 로케일에 맞게 가져온 후에
- 문자열로 만들어서
- serverTime라는 속성에 넣은 후
- home 이라는 뷰에 넘기게 되어 있다.
그럼 home은 어디로 넘어가는가?
아까 servlet-context.xml에서 InternalResourceViewResolver 가 지정되어 있음을 기억해보자.
prefix(접두사)가 /WEB-INF/views/ 였고, suffix(접미사)가 .jsp 였다.
결국 home이라는 뷰 이름은 /WEB-INF/views/home.jsp 으로 바뀌게 된다.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>
Hello world!
</h1>
<P> The time on the server is ${serverTime}. </P>
</body>
</html>
JSP는 HTML을 만들기 위한 템플릿일 뿐이다.
결국은 아래와 같은 HTML이 동적으로 만들어진다. 어디가 차이인지 알겠는가?
바로 ${serverTime} 부분이 2012년 9월 13일 (목) 오후 3시 52분 28초 와 같은 문자열로 대체가 된 것이다.
컨트롤러에서 model.addAttribute("serverTime", formattedDate ); 에서 모델의 애트리뷰트 이름이 serverTime이었다.
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>
Hello world!
</h1>
<P> The time on the server is 2012년 9월 13일 (목) 오후 3시 52분 28초. </P>
</body>
</html>
전체적인 그림
웹브라우저에서 시작된 요청부터, 결과까지 개념적으로 그림으로 만들어보았다.
지난번에 깨졌던 한글은?
이번에 보면 한글이 다 잘 나오고 있는데 어떻게 해결을 한 것일까?
결론은 간단하다. jsp에서 페이지 인코딩을 UTF-8로 하도록 조정을 해주었다.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" pageEncoding="UTF-8"%>
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>
Hello world!
</h1>
<P> The time on the server is ${serverTime}. </P>
</body>
</html>
참고로 본인은 개인적으로 프로젝트의 인코딩 형식을 UTF-8로 하고 있다. 다국어 지원을 위해서 말이다.
스프링에서도 기본적으로 다국어 지원을 위한 로케일을 지원하고 있지 않은가?
- 위에서 home 메소드에 첫 번째 인자가 Locale locale 이다!
이상으로 HelloWorld 예제 분석을 마쳐본다.
스프링에 대해 더 자세히 알고 싶으면 스프링 홈페이지에서 Document를 읽거나 Introduction to Spring MVC Framework를 읽어보면 도움이 될 것 같다.
'Programing > JVM(Java, Kotlin)' 카테고리의 다른 글
[Spring] 의존성관리(dependency management) (0) | 2012.11.12 |
---|---|
숫자로 된 문자열 0으로 패딩하기... (0) | 2012.11.06 |
스트림(Stream) (0) | 2012.10.19 |
자바 가상 머신(JVM) (0) | 2012.09.27 |
[Spring] Spring 3.0 시작 - Hello World 만들기 (0) | 2012.09.06 |