Configuration

Spring MVC를 이용하여 웹 애플리케이션을 개발하기 위해서는 다음과 같은 기본 설정이 필요하다.

web.xml 설정

먼저 web.xml파일에 다음과 같이 contextLoaderListner를 등록해 준다.
<listener>
	<listener-class>
		org.springframework.web.context.ContextLoaderListener
	</listener-class>
</listener>
다음은 DispatcherServlet을 등록하고 서블릿 명, 처리할 URL패턴명, Spring 설정 파일의 위치를 지정해줘야 하는데 DispatcherServlet에 관련된 내용과 설정 방법은 아래와 같다.

    DispatcherServlet

    Spring MVC DispatcherServlet의 URL 요청에 따른 workflow는 아래와 같은 다이어그램으로 그려질 수 있다.
    위 workflow에서 볼 수 있듯이 DispatcherServlet은 Front Controller 패턴을 사용하여 모든 요청을 하나의 servlet에서 받은 뒤 Handler Mapping을 통해 각각의 요청을 처리할 컨트롤러에 넘긴다. 컨트롤러에서 요청을 처리한 뒤 ModelAndView 객체를 다시 Dispatcher에게 넘기면 Dispatcher는 받은 객체의 view 이름과 ViewResolver를 사용하여 해당 응답을 보여줄 view에게 Model객체들을 넘기고 출력할 view를 만들게 된다. 그 후 다시 Dispatcher에게 제어권을 넘기면 Reponse에 방금 만들어낸 view을 실어 보낸다.
    이러한 DispatcherServlet은 web.xml에 다음과 같이 설정한다.
    <servlet>
    	<servlet-name>action</servlet-name>
    	<servlet-class>
    		org.springframework.web.servlet.DispatcherServlet</servlet-class>
    	<load-on-startup>1</load-on-startup>
    </servlet>
    DispatchserServlet은 servlet의 이름에 따른 XML 파일로부터 Spring applicationContext를 로드한다. <servlet-name>에 servlet 이름을 지정해 주는데 여기서 지정해 준 이름은 bean 설정파일인 "서블릿명-servlet.xml"의 servlet명과 같아야 한다. 즉, <servlet-name>을 action으로 지정해 주었다면 action-servlet.xml이라는 파일로부터 applicationContext를 로드하게 되는것이다. 그 다음엔 DispatchserServlet에 의해 처리될 요청을 URL을 지정해야 한다. web.xml에 다음과 같이 설정한다.
    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    위와 같이 설정할 경우 URL의 확장자가 ".do"인 모든 URL에 대한 요청은 DispatcherServlet이 처리하게 된다.
    context loader를 사용할 때는 로드해야 할 Spring 설정 파일의 위치를 지정해야 하는데 지정하지 않을 경우 디폴트 값으로 /WEB-INF/applicationContext.xml 이라는 Spring 설정 파일을 찾게 된다. 하지만 이 파일만 사용할 경우 모든 빈 설정은 이 한 파일에 등록 되어야 한다. 그러므로 contextConfigLocation 이라는 파라미터를 설정함으로써, context loader가 로드할 수 있는 하나 이상의 Spring 설정 파일을 지정해주는 것이 좋다.
    <context-param>
    	<param-name>contextConfigLocation</param-name>
    	<param-value>/conf/applicationContext-*.xml</param-value>
    </context-param>
    위와 같이 정의할 경우 /conf/applicationContext-*.xml값의 설정파일을 로드하게 된다. 또한 DispatcherServlet은 WebApplicationContext를 가지고있고 context Hierarchy는 다음 그림과 같다.
    WebApplicationContext에 설정할 수 있는 특별한 bean들은 다음과 같다.
    Bean type
    설명
    Controllers 각종 컨트롤러들
    Handler mappings 요청된 URL을 처리할 컨트롤러와 매칭
    View resolvers View를 결정
    Locale resolver 국제화 지원하기 위해 사용자의 locale 알아냄
    Theme resolver 테마 사용할 때 사용
    multipart file resolver 폼에서 파일 업로드 할 때 사용
    Handler exception resolver(s) 특정 예외가 발생할 때의 보여줄 view 등록

action-servlet.xml 설정

web.xml에 위와같이 패턴명 "*.do"로 지정해 주었기 때문에 확장자가 ".do"에 해당하는 모든 URL은 DispatcherServlet이 처리하게 될 것이다. 이러한 web.xml 설정이 끝나면 개발한 Controller를 URL과 매핑해주는 부분인 handlerMapping과 view를 찾아주는 viewResolver를 action-servlet.xml에 추가해 줘야한다.

    Handler Mapping

    Cotroller와 URL을 매핑하기 위해서 Spring MVC에서는 여러가지의 Handler Mapping을 지원한다. 또한 Handler Mapping에 요청된 URL경로를 입력할 때 /**/*.do 와 같이 "*" 기호를 사용하여 경로를 지정하는것이 가능하다.
    • BeanNameUrlHandlerMapping
    • BeanNameUrlHandlerMapping은 빈 이름과 URL을 Mapping한다. 이러한 BeanNameUrlHandlerMapping의 정의는 다음과 같다.
      <bean name="/test.do"
      	class="sample.web.controller.HelloworldController">
      	<property name="helloworldService" ref="helloworldService" />
      </bean>
      test.do로 들어온 요청을 받아 HelloworldController와 매핑한다. 이 HelloworldController는 helloworldService를 사용하고 있으며 이 역시 bean으로 정의되어 있어 web.xml의 context-param에서 정의한 경로에 따라 applicationContext-helloworldService.xml을 읽어 들일수 있다. 또한 빈 설정 파일에 HandlerMapping이 설정되어 있지 않을 경우 Spring MVC는 BeanNameUrlHandlerMapping을 default HandlerMapping으로 설정한다.
    • SimpleUrlHandlerMapping
    • SimpleUrlHandleMapping은 매핑에 대한 정보를 각각의 Controller에서 설정하는 것이 아니라 하나의 저장소에서 관리하는 것이다. 사용자는 컨트롤러를 빈으로 정의해 주고 mappings 프로퍼티의 value값에 각각의 요청에 대한 컨트롤러 매핑만 지정해 주면 된다. 다음은 위의 BeanNameUrlHandlerMapping 예시를 SimpleUrlHandlerMapping을 이용해 나타낸 것이다.
      <bean id="urlMapping"
      	class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
      	<property name="mappings">
      		<value>
      			/test.do = helloworldController
      		</value>
      	</property>
      </bean>
      
      <bean id="helloworldController"
      	class="sample.web.controller.HelloworldController">
      </bean>
      또한 SimplerUrlHandlerMapping을 사용할 경우 매핑 정보를 빈 설정 파일이 아닌 별도의 파일에서 관리하는 것이 가능하다. 예는 다음과같다.
      <bean id="urlMapping" 
           class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
          <property name="mappings">
              <bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
                  <property name="location">
                      <value>/mapping.properties</value>
                  </property>
              </bean>
          </property>
      </bean>
      다음은 위에서 정의된 mapping.properties파일의 내용이다.
      test.do = helloworldController
    • Intercepting requests
    • handler mapping은 interceptor를 만들어 요청이 들어오기 전(preHandle), 들어온 후(postHandle), 완료된 후(afterCompletion)에 특정 작업을 추가할 수 있다. 예를 들어 로그인한 사용자에게만 보여주고 싶은 페이지가 있다면 매번 exception을 발생시켜 페이지를 이동시켜 주지 않아도 페이지 요청 처리 전에 interceptor를 preHandler정의 하면 mappings의 value로 지정되어있는 모든 요청에 대해 interceptor를 적용시킬 수 있다. 이러한 interceptor를 처리하기 위해서는 먼저 interceptor를 만들어 줘야 하는데 이는 HandlerInterceptorAdapter를 extends하여 interceptor를 발생시킬 시점에 따른 메소드를 오버라이딩 한다.

      interceptor의 생성예는 다음과 같다.
      public class UserLoginInterceptor extends HandlerInterceptorAdapter{
      
      	@Override
      	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
      		                Object hadler) throws Exception {
      		// TODO Auto-generated method stub
      		  if(request.getSession().getAttribute("userId") != null)
      	            return true;
      	        else {
      	            response.sendRedirect("login.jsp");
      	            return false;
      	        }
      	}
      }
      위의 예는 preHandle메소드를 오버라이딩 하여 요청이 들어오기 전에 위와같은 작업을 수행 하게되는것이다. session에 userId값이 존재할 경우 true를 리턴하고 요청을 처리하게 될 것이고, userId값이 존재 하지 않는다면 login.jsp페이지를 출력하게 될것이다. 다음은 빈 설정파일에 interceptor를 설정한 예시이다.
      <bean id="urlMapping1"
      	class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
      	<property name="interceptors">
      		<list>
      			<ref bean="userLoginInterceptor"/>
      		</list>
      	</property>
      	
      	<!-- 여러개의 핸들러 매핑을 정의할 경우 같은 요청에 대한 우선순위를 "order" 프로퍼티를 사용해
      	정해줄 수 있다. 숫자가 작을수록 우선순위는 높다. -->
      	<property name="order"><value>2</value></property>
      	
      	<property name="mappings">
      		<value>
      			/list.do=getUserListController
      		</value>
      	</property>
      </bean>
      
      <bean id="userLoginInterceptor" class="sample.services.UserLoginInterceptor" />
      위와같은 설정으로 interceptor를 사용해 요청에 따른 interceptor를 정의해줄 수 있다.

    View Resolver

    핸들러(controller)는 요청을 처리 한 뒤 ModelAndView 객체를 넘겨준다. 이 때 이 객체에 view의 이름을 같이 넘겨 주는데 이 이름으로 실제 view를 찾아 주는 역할을 하는 것이 View Resolver이다.
    Spring이 제공하는 View Resolver들은 다음과 같다.
    ViewResolver
    설명
    AbstractCachingViewResolver View 들을 cashing하는 기능 제공
    XmlViewResolver ViewResolver 의 구현체로 XML파일 사용(/WEB-INF/views.xml 을 기본 설정파일로 사용)
    ResourceBundleViewResolver ViewResolver 의 구현체로 리소스 파일 사용(views.properties 를 기본 리소스 파일로 사용)
    UrlBasedViewResolver ViewResolver 의 구현체로 특별한 맵핑 정보 없이 의미상 view 이름을 URL로 사용(View 이름과 실제 view 자원과의 이름이 같을 때 사용)
    InternalResourceViewResolver UrlBasedViewResolver 를 상속 받았으며 InternalResourceView(Servlet, JSP)를 사용
    VelocityViewResolver/FreeMarkerViewResolver UrlBasedViewResolver 를 상속 받았으며 VelocityView 와 FreeMarkerView를 사용
    사용하려는 기술에 따라 위와같은 View Resolver를 적절히 선택하여야한다.

    • JSP 사용
    • <bean id="viewResolver"
            class="org.springframework.web.servlet.view.UrlBasedViewResolver">
          <property name="prefix" value="/WEB-INF/jsp/"/>
          <property name="suffix" value=".jsp"/>
      </bean>
      

      viewResolver는 action 요청 처리 후 사용자에게 보여줄 view를 찾는 역할을 하고 prefix와 suffix를 지정해 줄수 있다. 만약 controller에서 넘겨준 modelAndView 값이 index이고 prefix를 "/jsp/", suffix를 ".jsp"라고 정의 했다면 이 viewResolver는 "/jsp/index.jsp"를 찾게 된다. 이러한 viewResolver 정보를 변경함으로써 Velocity, Excel, PDF등을 View로 이용하는 것이 가능하다.

    • JSTL 사용
    • <bean id="jspViewResolver" 
         class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
      </bean>
      만약 JSTL 태그를 사용한다면 viewClass 특성을 설정함으로써 InternalResourceView를 JstlView로 대체해야 한다. JstlView도 요청을 JSP에 전달한다.

Resources