 |
|
난이도 : 고급 Sunil Patil, 선임 컨설턴트, Ascendant Technology LLC
2008 년 3 월 04 일 이 글은 스프링 포틀릿 MVC 프레임워크(Spring Portlet MVC Framework)를 사용하여 IBM WebSphere Portal에 배치할 간단한 HelloWorld 포틀릿 애플리케이션을 만드는 방법을 다룹니다. 포틀릿 개발에 오픈소스 MVC 프레임워크를 사용하고자 하는 포틀릿 개발자와 아키텍트를 위해 작성한 글입니다.
이 글은 세 개의 글로 이뤄진 "IBM WebSphere 포털 내에서 사용할 스프링 포틀릿 MVC 프레임워크 애플리케이션 개발하기" 연재의 첫 번째 글로 난이도는 고급이다. 본 글을 이해하기 위해 JSR-168 포틀릿 개발의 기초를 알아야 하고 스프링 프레임워크에 대해 적어도 기본 이해는 하고 있어야 한다.
지난 몇 년 동안 스프링 프레임워크는 J2EE 개발자들 사이에서 인기를 얻어왔다. 스프링 프레임워크는 인프라스트럭처 코드를 제공함으로써 J2EE를 쉽게 개발할 수 있게 해줬고, 그에 따라 MVC 프레임워크나 객체 관계형 매핑 프레임워크 등에 쏟던 노력을 애플리케이션의 비즈니스 로직을 구현하는 데 집중할 수 있게 됐다.
스프링 프레임워크 1.0 버전은 서블릿 기반 애플리케이션을 개발할 때 사용할 수 있는 웹 MVC 프레임워크를 가지고 있다. 스프링 프레임워크 2.0 버전부터는 웹 MVC 프레임워크의 복제품인 포틀릿 MVC 프레임워크를 가진다. 이는 JSR-168과 호환되는 포틀릿 애플리케이션을 개발하는 데 쓸 수 있다.
다음은 스프링 포틀릿 MVC 프레임워크의 장점이다.
- 특별한 변경없이 포틀릿 MVC 프레임워크를 사용하여 개발된 포틀릿을 JSR-168과 호환되는 어느 포틀릿 컨테이너에나 배치할 수 있다. 반면 IBM 스트럿츠 포틀릿 프레임워크(Struts Portlet Framework)나 IBM JSF 프레임워크를 사용하여 개발된 포틀릿은 IBM WebSphere Portal 런타임에 영향을 받는다.
- 대다수의 다른 포틀릿 MVC 프레임워크는 포틀릿 작동을 캡슐화하고 요청 프로세싱의 단계로 렌더하려고 한다. 하지만 스프링 포틀릿 MVC 프레임워크는 다르다. 포틀릿의 두 단계 요청 프로세싱이 서블릿의 한 단계 요청 프로세싱보다 낫다는 것을 이해하고 이를 이용하려 한다. 포틀릿 MVC 프레임워크(스트럿츠 프레임워크의 동작과 같은)에서 요청을 처리하는 기본 인터페이스를 정의하는 Controller.java 클래스는 handleActionRequest()와 handleRenderRequest() 메서드를 정의한다. 이 접근법을 통해 더 유연하게 애플리케이션을 만들 수 있다.
- 스프링 포틀릿 MVC 프레임워크는 JSTL, 아파치 타일즈(Apache Tiles), 아파치 벨로시티(Apache Velocity), 프리메이커(FreeMaker) 같은 인기있는 뷰-렌더링 기술과 쉽게 통합된다.
- 포틀릿 MVC 프레임워크는 포틀릿의 테스트 주도 개발에 사용할 수 있는 모조(mock) 테스팅 프레임워크를 제공한다.
이 글은 스프링 포틀릿 MVC 프레임워크를 단계별로 설명한 글이다. 기본 스프링 프레임워크와 JSR-168 호환의 포틀릿 개발에 대한 고급 지식은 필요치 않다 하더라도 기본 개념을 가지고 있어야 한다.
또한 일단 스프링 포틀릿 MVC 프레임워크를 위한 개발 환경을 설정하는 방법에 대해 다루고 스프링 포틀릿 MVC 프레임워크에서 간단한 HelloWorld 애플리케이션을 개발하는 방법을 이어 다룬다. 또한 렌더 요청이 어떻게 처리되는지 본다. 마지막으로 포틀릿에서 Help와 Edit 모드 지원을 추가하는 방법을 보여준다.
개발 환경 설정하기
먼저 WebSphere 소프트웨어를 위한 IBM IBM Rational Application Developer를 사용하여 개발 환경을 설정해야 한다. 본 글의 샘플 코드는 메이븐(Maven) 빌드 스크립트에 있으므로 원하는 개발 환경을 사용하거나 마이크로소프트 메모장 같은 텍스트 편집기를 사용해 코딩할 수 있다.
샘플 코드는 스프링 웹 MVC(Spring Web MVC), 스프링 코어(Spring Core), 아파치 커먼즈 로깅(Apache Commons Logging), 아파치 Log4j, 아파치 커먼즈 파일 업로드(Apache Commons File Upload), 아파치 타일즈 등과 많은 의존관계를 갖는다. 이들 JAR 파일을 개별적으로 다운로드해 클래스 경로에 추가하는 것이 문제가 될 수 있으므로 본 글에서는 아파치 메이븐 2.0을 빌드 도구로 사용하여 필요한 의존 관계를 모두 다운로드한다. 다음 단계를 따라 개발 환경을 설정하자.
- Rational Application Developer에 HelloSpringPortletMVC라는 이름의 동적 웹 프로젝트를 만든다.
- 메이븐 2.0은 프로젝트에 표준 디렉터리 구조를 사용하라고 권유하므로 Configre 웹 모듈 설정 페이지에 HelloSpringPortletMVC 프로젝트를 만든다. 그리고 다음을 넣는다.
- /src/main/webapp와 같은 Content Directory
- 자바 소스 디렉터리로 /src/main/java
- 본 글에 필요한 샘플 코드를 다운로드 절의 링크에서 다운받자. 샘플 코드 ZIP 파일을 c:/temp 디렉터리에 풀어 넣는다.
- SpringHelloPortletMVC 샘플 코드에서 빌드 스크립트(pom.xml)를 복사하여 프로젝트 디렉터리의 루트 폴더에 넣는다.
- 메이븐 2.0을 아직 가지고 있지 않다면 아파치 메이븐 웹 사이트에 가서 메이븐 바이너리 2.x 버전을 다운로드한다. 설치 방법은 아파치 메이븐 다운로드 페이지를 참조하라.
- 명령행을 열어 HelloSpringPortletMVC 프로젝트의 루트로 이동한다. mvn 패키지 명령을 작동하여 코드를 만들 수 있다. 이 명령으로 프로젝트에 필요한 모든 의존 관계를 다운로드할 수 있다. 메이븐 빌드 스크립트를 처음으로 실행하는 거라면 모든 의존 관계를 다운로드하는 데 몇 분 걸릴 수 있다.
- mvn eclipse:eclipse 명령을 실행하여 마우스 오른쪽 버튼으로 클릭하고 Refresh를 선택한다. 프로젝트의 클래스 경로에 몇 가지 JAR 파일이 추가됐음을 볼 수 있다.
- 이 때 M2_REPO 변수가 없다는 오류가 뜨면 Windows-Preferences-Java-Build Path를 선택하고 M2_REPO 클래스 경로 변수를 메이븐 2.0 저장소에 넣는다. 마이크로소프트 윈도우에서는
c:\Documents and Settings\<loginname>\.m2\repository.
리눅스에서는
~/.m2/repository
다.
이 단계를 따라하면 HelloSpringPortletMVC 프로젝트는 그림 1의 개발 환경처럼 보인다.
그림 1. Rational Application Developer 설정
이것으로 개발 환경이 완성됐다. 이제 HelloWorld 스프링 포틀릿 MVC 애플리케이션을 개발해보자.
HelloWorld 스프링 포틀릿 MVC 프레임워크 애플리케이션 개발하기
새 프레임워크를 배우는 가장 좋은 방법은 이를 사용하여 HelloWorld 애플리케이션을 개발하는 것이다. 본 절에서는 스프링 포틀릿 MVC 프레임워크를 사용하여 HelloWorld 포틀릿을 개발한다. 여기서는 HelloWorld 포틀릿이 뷰(View) 모드만 지원한다. 사용자가 HelloWorld 포틀릿에 접근하려고 할 때마다 View.jsp에서 생성되는 마크업을 사용자에게 보여준다.
portlet.xml 개발하기
Listing 1처럼 /src/main/webapp/WEB-INF/ 폴더에 portlet.xml 파일을 만들어 HelloWorld 샘플 개발을 시작해보자.
Listing 1. portlet.xml을 위한 코드 목록
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app
xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" >
<portlet>
<description>HelloWorld Portlet using Spring MVC</description>
<portlet-name>HelloSpringPortletMVC</portlet-name>
<display-name>Hello World Spring Portlet MVC Framework Portlet</display-name>
<portlet-class> org.springframework.web.portlet.DispatcherPortlet
</portlet-class>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<portlet-info>
<title>
Hello World Spring Portlet MVC Framework Portlet
</title>
<short-title>
HelloWorldSpringPortletMVC
</short-title>
<keywords>
spring portlet
</keywords>
</portlet-info>
</portlet>
</portlet-app>
|
DispatcherPortlet은 모든 클라이언트 요청을 처리해야 한다. 요청을 받으면 이 요청을 처리하는 데 쓸 컨트롤러(Controller) 경로를 찾아야 하고 요청 처리 단계를 기반으로 handleActionRequest()나 handleRenderRequest() 메서드를 호출한다. 컨트롤러 클래스는 비즈니스 로직을 실행하고 마크업을 렌더링하는 데 사용하는 뷰 이름을 사용자에게 반환한다. 그리고 나서 DispatcherPortlet은 실제 마크업 생성을 위해 이 뷰에 제어를 보낸다.
여기서 볼 수 있듯 DispatcherPortlet은 스프링 포틀릿 MVC 프레임워크 내에서 사용하는 주요 디스패처(dispatcher)다. 포틀릿 애플리케이션이 하나 이상의 DispatcherPortlet을 정의할 수 있음을 기억하자. 이럴 경우 이 포틀릿 각각은 애플리케이션 컨텍스트와 핸들러 매핑을 전달하여 자신의 이름공간을 움직인다.
DispatcherPortlet은 또한 포틀릿에 애플리케이션 컨텍스트(스프링 구성 파일)를 전달해야 한다. 먼저 configLocation 포틀릿 개시 매개변수 값을 확인하고자 한다. 매개변수가 지정되지 않았으면 포틀릿 이름(<portlet-name> 요소 값)에 appends-portlet.xml을 갖고 /WEB-INF 폴더에서 이 파일을 로드하고자 한다. portlet.xml 파일에서 configLocation 개시 매개변수를 지정하지 않았으므로 다음 절에서 HelloWorldPortletMVC-portlet.xml 파일을 만들자.
HelloSpring PortletMVC-portlet.xml 개발하기
Listing 2처럼 애플리케이션의 /src/main/webapp/WEB-INF 폴더에 HelloSpringPortletMVC-portlet.xml 파일을 만들자.
Listing 2. HelloSpringPortletMVC-portlet.xml을 위한 코드 목록
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
\"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="viewController"
class="com.ibm.developerworks.springmvc.ViewController"></bean>
<bean id="portletModeHandlerMapping" class=
"org.springframework.web.portlet.handler.PortletModeHandlerMapping">
<property name="portletModeMap">
<map>
<entry key="view">
<ref bean="viewController"/>
</entry>
</map>
</property>
</bean>
</beans>
|
HelloSpringPortletMVC-portlet.xml 파일은 HelloSpringPortletMVC 포틀릿의 애플리케이션 컨텍스트 파일이다. 여기에는 몇 가지 빈(bean)에 대한 정의가 있다.
-
viewController: 여기서는 viewController 빈(bean) 정의가 com.ibm.developerworks.springmvc.ViewController.java 클래스를 가리킴을 기억하자.
-
portletModeHandlerMapping: 지난 절에서 언급했듯 DispatcherPortlet이 클라이언트 요청을 가질 때 이 요청을 처리하기 위해 적절한 컨트롤러 클래스를 찾으려 한다. 이 때 portletModeHandlerMapping이 필요하다. portletModeHandlerMapping 클래스는 HandlerMapping 인터페이스의 간단한 구현이고 요청시마다 적절한 컨트롤러를 찾는데 DispatcherPortlet을 사용한다. PortletModeHandlerMapping은 현 요청의 포틀릿 모드를 사용하여 적절한 컨트롤러 클래스를 찾아 요청을 처리하는 데 사용한다. portletModeHandlerMapping 빈의 portletModeMap 속성은 컨트롤러 클래스에 반해 포틀릿 모드 이름을 매핑하는 공간이다. 샘플 코드에서 viewController은 뷰 모드 요청을 처리해야 함을 보여준다.
ViewController.java 개발하기
전 절에서 viewController 빈이 모든 뷰 모드 요청을 처리한다고 배웠다. 이제 Listing 3처럼 ViewController.java 클래스를 만들어 볼 차례다.
다음 단계를 따라 com.ibm.developerworks.springmvc.ViewController.java를 만들자.
- /src/main/java를 마우스 오른쪽 버튼으로 클릭하고 New - Java Class를 선택한다.
- 패키지에 com.ibm.developerworks.springmvc를 넣는다.
- 이름에 ViewController를 넣는다.
- Finish를 클릭한다.
- 클래스 내용을 Listing 3의 코드로 바꾼다.
Listing 3. ViewController.java를 위한 코드 목록
package com.ibm.developerworks.springmvc;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import org.springframework.web.portlet.ModelAndView;
import org.springframework.web.portlet.mvc.AbstractController;
public class ViewController extends AbstractController{
protected ModelAndView handleRenderRequestInternal(RenderRequest request,
RenderResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView("View");
return modelAndView;
}
}
|
주의: 아파치 스트러츠 프레임워크(Apache Struts Framework)에 익숙하다면 컨트롤러 클래스를 아파치 스트럿츠 프레임워크의 액션(Action) 클래스와 같다고 생각하면 된다.
스프링 포틀릿 MVC 프레임워크의 모든 컨트롤러 클래스는 org.springframework.web portlet.mvc.Controller 인터페이스를 직접 또는 간접적으로 구현해야 한다. 더 쉽게 하기 위해 스프링 프레임워크는 컨트롤러 인터페이스의 기본 구현인 AbstractController 클래스를 제공한다. 개발자는 늘 AbstractController나 다른 더 특정한 하위 클래스에서 컨트롤러를 확장해야 한다. 컨트롤러 클래스의 어떤 구현이든 재사용 가능해야 하고 쓰레드에 안전해야 하고 포틀릿 생명주기 내내 다중 요청을 처리할 수 있어야 한다.
샘플 코드에서 AbstractController로부터 확장한 ViewController 클래스를 만든다. HelloSpringPortletMVC 포틀릿에서 어떤 작동 프로세싱도 원하지 않으므로 AbstractController의 handleRenderRequest() 메서드만 사용한다. 이제 HelloWorldPortletMVC가 사용자 요청에 따라 View.jsp 마크업을 사용자에게 렌더하는 일만 남았다. 이를 위해 View와 같은 뷰 값과 ModelAndView 객체를 반환한다.
Web.xml 개발하기
포틀릿 명세 1.0(Portlet Specification 1.0)에 따르면 모든 포틀릿 애플리케이션은 또한 서블릿 명세 2.3과 호환되는 웹 애플리케이션이며 웹 애플리케이션 배치 서술자(여기서는 web.xml)가 있어야 한다. Listing 4처럼 다음 단계로 /WEB-INF/ 폴더에 web.xml 파일을 만들자.
-
/src/main/webapp/web.xml.
에 위치한 기존 web.xml 파일을 연다
- 이 파일의 내용을 Listing 4의 코드로 바꾼다.
Listing 4. Web.xml의 코드 목록
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>
Hello Spring Portlet MVC Framework Application
</display-name>
<servlet>
<servlet-name>ViewRendererServlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.ViewRendererServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ViewRendererServlet</servlet-name>
<url-pattern>/WEB-INF/servlet/view</url-pattern>
</servlet-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
</web-app>
|
샘플 포틀릿의 web.xml 파일은 두 가지를 선언한다.
-
ViewRendererServlet: ViewRendererServlet은 포틀릿 지원을 위한 브릿지 서블릿이다. 렌더 단계 중 DispatcherPortlet은 PortletRequest를 ServletRequest로 감싸고 실제 렌더링을 위해 제어를 ViewRendererServlet에 전달한다. 이 프로세스를 통해 스프링 포틀릿 MVC 프레임워크는 서블릿 버전인 스프링 포틀릿 MVC 프레임워크와 같은 뷰 인프라스트럭처를 사용한다.
-
ContextLoaderListener: ContextLoaderListener 클래스는 웹 애플리케이션을 시작할 때 웹 애플리케이션 컨텍스트를 로딩하는 일을 관장한다. 웹 애플리케이션 컨텍스트는 포틀릿 애플리케이션의 모든 포틀릿으로 공유된다. 복사된 빈 정의의 경우 포틀릿 애플리케이션 컨텍스트 안의 빈 정의는 웹 애플리케이션 컨텍스트에 우선한다.
ContextLoader 클래스는 contextConfigLocation 웹 컨텍스트 매개변수 값을 읽어 컨텍스트 파일의 위치를 찾고자 한다. contextConfigLocation 매개변수가 설정되지 않았으면 기본 값인 /WEB-INF/applicationContext.xml을 사용하여 컨텍스트 파일을 로드한다.
applicationContext.xml 개발하기
지난 절에서 언급했듯 contextConfigLocation 컨텍스트 매개변수 값이 설정되지 않았으면 ViewRendererServlet은 /WEB-INF/applicationContext.xml 파일에서 웹 애플리케이션 컨텍스트를 읽으려고 한다. Listing 5처럼 /WEB-INF/ 폴더에 applicationContext.xml을 만들자.
Listing 5. applicationContext.xml의 코드 목록
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="viewResolver" class=
"org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass">
<value>
org.springframework.web.servlet.view.JstlView
</value>
</property>
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
|
샘플 코드에서 applicationContext.xml 파일은 viewResolver 빈 하나만을 정의한다. viewResolver 빈은 주어진 뷰 이름의 실제 JSP 파일의 위치를 찾는 데 사용된다. 샘플 코드에서 마지막 뷰 렌더링을 위해 JSP 파일을 원하므로 JSP와 타일즈 뷰를 지원하는 InternalResourceViewResolver를 사용한다.
viewResolver 빈에 몇 가지 속성을 설정했음을 볼 수 있을 것이다.
- Prefix와 /WEB-INF/jsp/와 같은 값
- Suffix와 JSP와 같은 값
이는 viewResolver에 뷰 해결을 위한 뷰 이름을 가질 때마다 /WEB-INF/jsp를 접두사로, JSP를 접미사로 추가함을 말한다. 그 결과 ViewController.handleRenderRequestInternal()의 뷰와 같은 값과 ModelAndView를 반환할 때 /WEB-INF/jsp/View.jsp 내용을 사용자에게 렌더한다.
마지막으로 다음 단계를 따라 /WEB-INF/jsp 폴더에 "Hello from Spring Portlet MVC Framework"라는 메시지를 가진 간단한 View.jsp 페이지를 만들자.
- WEB-INF 폴더를 마우스 오른쪽 버튼으로 클릭하고 New - Folder를 선택한다.
- 폴더 이름을 jsp라 한다.
- 새 jsp 파일을 마우스 오른쪽 버튼으로 클릭하고 New - File을 선택한다.
- 이 파일 이름을 View.jsp라 한다.
- JSP 파일을 위한 편집기에 "Hello from Spring Portlet MVC Framework"라 입력한다.
이제 샘플 애플리케이션이 완성됐다. mvn 패키지 명령을 실행하여 포틀릿을 만들어 HelloSpringPortletMVC-1.0.war를 만들 수 있다. 다 만든 후 WebSphere Portal에 있는 타겟 폴더에 만든 HelloSpringPortletMVC-1.0 war을 배치한다. HelloWorldPortletMVCPortlet에 접근할 때 뷰 모드에서 "Hello From Spring Portlet MVC Framework" 메시지가 보여야 한다.
렌더링이 작동하는 방법
사용자가 HelloSpringPortletMVC 포틀릿에 접근하려고 할 때 어떤 일이 발생하는지 살펴보자.
그림 2. DispatcherPortlet이 렌더 요청을 받았을 때 발생하는 연속 이벤트
알고 있듯 사용자가 HelloWorldPortletMVC 포틀릿이 있는 페이지에 접근하려고 할 때나 페이지의 포틀릿에 사용자가 동작을 수행하려 할 때, 또는 그 페이지를 새로 고치고자 할 때 HelloWorldPortletMVC 포틀릿에 렌더 요청이 전송된다. 샘플 코드에서 DispatcherPortlet은 주 포틀릿 클래스이므로 WebSphere Portal은 이의 render() 메서드를 호출하면 다음의 연속 이벤트가 발생한다.
- DispatcherPortlet의 render() 메서드는 doRender() 메서드를 호출하는 doDispatch() 메서드를 호출한다.
- doRenderService() 메서드가 제어를 갖게 되면 우선 PortletRequest.getLocale() 메서드를 호출하여 요청의 로케일(locale)을 찾고자 한다. 이 로케일은 선택을 위해 로케일과 관련된 모든 결정(어떤 리소스 번들이 로드돼야 하는지 또는 어떤 JSP가 장소에 기반을 두고 사용자에게 보여야 하는지 등)을 하는 동안 사용된다.
- 다음 doRenderService() 메서드는 이 포틀릿으로 구현되는 모든 HandlerMapping 클래스를 통해 반복 및 getHandler() 메서드를 호출하여 요청을 처리할 적절한 컨트롤러를 식별하기 시작한다.
- 샘플 코드에서 PortletModeHandlerMapping만 HandlerMapping 클래스로 구성했다. PortletModeHandlerMapping 클래스는 현재 포틀릿 모드 값을 읽고 이를 기반으로 요청을 처리하는 데 사용되는 컨트롤러 클래스를 찾는다. 샘플 코드에서 ViewController은 뷰 모드를 처리하도록 구성되므로 PortletModeHandlerMapping 클래스는 ViewController의 객체를 반환한다.
- ViewController의 객체가 반환된 후 doRenderService() 메서드는 이의 handlerRenderRequestInternal() 메서드를 호출한다.
- ViewController.java에 있는 handlerRenderRequestInternal() 메서드 구현은 매우 간단하다. 제어를 갖게 된 메시지를 기록하고 ModelAndView 인스턴스와 뷰와 같은 값을 만들고 이를 DispatcherPortlet에 반환한다.
- 제어가 doRenderService()로 반환되면 뷰를 렌더할 방법을 찾아야 한다. 이를 위해 DispatcherPortlet은 resolveViewName() 메서드를 호출하여 포틀릿 애플리케이션에 구성된 모든 ViewResolvers를 반복하기 시작한다.
- 샘플 코드에서 InternalResourceViewResolver라는 하나의 ViewResolver만 구성했다. 이의 resolveViewName() 메서드가 viewName과 함께 호출될 때 뷰 이름에 접두사로 /WEB-INF/jsp를, 접미사로 JSP를 추가하고자 한다. 그리고 /WEB-INF/jsp/View.jsp가 존재하는지 확인한다. 존재한다면 view.jsp를 감싸는 JstlView 객체를 반환한다.
- 제어가 doRenderService() 메서드에 반환된 후 /WEB-INF/servlet/view, 즉 ViewRendererServlet을 가리키는 객체 PortletRequestDispatcher을 만든다. 그리고 나서 요청에 JstlView 객체를 설정하고 요청을 ViewRendererServlet으로 보낸다.
- ViewRendererServlet가 제어를 갖게 되면 요청 속성에서 JstlView 객체를 읽고 /WEB-INF/jsp/View.jsp URL을 가리키는 다른 RequestDispatcher을 만들어 실제 마크업 생성을 위해 제어를 전달한다. View.jsp로 생성되는 마크업은 사용자에게 반환된다.
아마도 ViewRendererServlet이 왜 필요한지 의아할 것이다. DispatcherPortlet가 View.jsp에 직접 제어를 보내면 어떨까? 중간에 ViewRendererServlet을 추가하면 스프링 포틀릿 MVC 프레임워크는 기존의 뷰 인프라스트럭처를 재사용할 수 있다. 이는 스프링 포틀릿 MVC 프레임워크와 아파치 타일즈 프레임워크를 통합하는 것이 얼마나 쉬운지 알 수 있을 것이다.
Help와 Edit 모드를 위한 지원 추가하기
본 절에서는 HelloSpringPorteltMVC 포틀릿을 변경하여 Help와 Edit 모드 지원을 추가하겠다. 간단하게 하기 위해 각기 다른 세 가지 JSP 파일을 만든다. 이들 JSP 파일 각각은 사용자에게 현재 포틀릿 모드 이름을 보여주고 다음에 나오는 단계를 따라 HelloWorldPortletMVC 프레임워크를 변경하여 포틀릿의 현재 모드를 기반으로 이들 JSP 중 하나에 제어를 보낼 것이다.
/WEB-INF/jsp 파일에 Help.jsp와 Edit.jsp라는 두 개의 파일을 만든다. Help.jsp 파일은 Listing 6처럼 생겼다.
Listing 6. Help 파일을 위한 HelpController.java의 코드 목록
<%@page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" session="false"%>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%>
<portlet:defineObjects />
<p>Hello from Spring Portlet MVC Framework - Help Mode</p>
|
같은 방법으로 Edit.jsp를 만든다. 이제 Listing 7처럼 com.ibm.developerworks.springmvc 패키지에 HelpController.java를 만든다.
Listing 7. Edit 파일을 위한 HelpController.java의 코드 목록
public class HelpController extends AbstractController{
private static Log log = LogFactory.getLog(HelpController.class);
protected ModelAndView handleRenderRequestInternal(RenderRequest request,
RenderResponse response) throws Exception {
log.debug("Entering HelpController.handleRenderRequestInternal()");
ModelAndView modelAndView = new ModelAndView("Help");
log.debug("Exiting HelpController.handleRenderRequestInternal() " + modelAndView);
return modelAndView;
}
}
|
여기서 볼 수 있듯이 HelpController.java는 AbstractController의 handleRenderRequestInternal() 메서드와만 겹친다. handleRenderRequestInternal() 메서드 구현은 ViewController.java의 그것과 비슷하다. 즉, "Entering HelpController.handleRenderRequest Internal()"라는 메시지를 기록하고 난 후 ModelAndView 객체와 Help와 같은 뷰 값을 반환한다. JSP 파일 이름을 Edit으로 바꿔 Edit 모드에도 같은 방법으로 EditController 클래스를 만든다.
다음 스프링 포틀릿 MVC 프레임워크에 HelpController를 사용하여 Help 모드 요청을 처리하고 EditController를 사용하여 Edit 모드 요청을 처리하라고 말한다. 이는 Listing 8처럼 HelloSpringPortletMVC-portlet.xml 파일을 변경하여 할 수 있다.
Listing 8. HelloSpringPortletMVC-portlet.xml의 코드 목록
<bean id="viewController" class="com.ibm.developerworks.springmvc.ViewController"/>
<bean id="editController" class="com.ibm.developerworks.springmvc.EditController"/>
<bean id="helpController" class="com.ibm.developerworks.springmvc.HelpController"/>
<bean id="portletModeHandlerMapping"
class = "org.springframework.web.portlet.handler.PortletModeHandlerMapping">
<property name="portletModeMap">
<map>
<entry key="view">
<ref bean="viewController"/>
</entry>
<entry key="edit">
<ref bean="editController"/>
</entry>
<entry key="help">
<ref bean="helpController"/>
</entry>
</map>
</property>
</bean>
|
HelloSpringPortletMVC-portlet.xml에 몇 가지 변경을 해야 한다. 먼저 EditController와 HelpController 빈을 정의해야 한다. 그리고 나서 portletModeHandlerMappingbean의 portletModeMap 속성 값을 수정하여 Edit 모드와 editController 빈을, Help 모드와 helpController 빈을 매핑한다. 이렇게 변경하면 스프링 포틀릿 MVC 프레임워크는 Edit 모드에 요청이 들어올 때 editController 빈에 제어를, Help 모드에 요청이 들어올 때 helpController 빈에 제어를 전달한다.
portlet.xml 파일을 변경하여 HELP와 VIEW <portlet-mode> 요소를 추가하는 것을 잊지 말자. WebSphere Portal은 HelloSpringPortletMVC 포틀릿에 Help와 Edit 버튼을 생성하지 않는다. 그리고 나중에 요청을 변경할 수 없다.
결론
본 글에서 도구를 만드는 데 아파치 메이븐 2.0을 사용하여 개발 환경을 설정하는 방법을 설명했다. 스프링 포틀릿 MVC 프레임워크를 사용하여 간단한 HelloWorld 포틀릿을 개발하는 방법과 렌더 요청이 처리되는 방법을 다뤘다. 이제 스프링 포틀릿 MVC 프레임워크를 이해해야 한다. 간단한 HelloWorld 포틀릿을 만들고자 해도 네 가지 다른 XML 구성 파일을 만들어야 한다는 스프링 포틀릿 MVC 프레임워크의 단점도 알아야 한다. 하지만 구성을 나눠 다중 파일로 만드는 능력은 복잡한 애플리케이션을 개발하는 데 큰 도움이 될 것이다.
다음 part 2에서는 간단한 폼 제출과 사용자 요청을 기반으로 동적 내용을 생성하는 방법을 다루겠다.
다운로드 하십시오 | 이름 | 크기 | 다운로드 방식 |
|---|
| part-1.zip | 8KB | HTTP |
참고자료 교육
제품 및 기술 얻기
토론
필자소개  | |  | Sunil Patil은 Ascendant Technology, LLC에서 수석 컨설턴트로 일하고 있다. IBM developerWorks에 몇 가지 글과 Java Portlets 101이라는 책을 썼다. |
기사에 대한 평가
|