18
- Spring MVC - Spring Framework - Confluence 3 6 워크북 프레임워크 Spring Spring 프레임워크 워크북 63- Spring MVC Dashboard > Spring Framework > ... > Spring 프레임워크 워크북 62- Spring MVC > Spring 프레임워크 워크북 63- Spring MVC Community Spring Framework Log In | Sign Up Browse Space Add News View Attachments (5) Info Added by 박재성, last edited by 박재성 on 602, 2007 ( view change) Labels: (None) 6. Spring MVC 3. 샘플 애플리케이션에 Spring MVC 적용 지금까지 Spring MVC 기반으로 클라이언트의 요청을 처리하는 기본적인 과정에 대하여 살펴보았다. 절에서는 샘플 애플리케이션을 Spring MVC 기반하에서 구현해보면서 Spring MVC기능에 대하여 구체적으로 살펴보도록 하겠다. 3.1 메인 페이지 구현하기 Spring MVC가장 기본적인 기능을 구현하는 과정에 대하여 살펴보기 위하여 샘플 애플리케이션 페이지에서 비즈니스 계층과의 통신이 메인페이지를 구현하는 과정에 대하여 제일 먼저 살펴보도록 하자. 애플리케이션을 개발하다보면 샘플 애플리케이션의 메인 페이지처럼 정적인 페이지에 접근해야 되는 경우가 종종 발생한다. 정적인 페이지 직접 접근할 수도 있겠지만 애플리케이션의 모든 URL대하여 공통적인 작업을 처리할 필요가 있을 경우에는 정적인 페이지 DispatcherServlet통하여 접근하도록 개발할 경우 쉽게 해결할 있다. 모델 2 개발 방식으로 애플리케이션을 개발할 항상 논란의 여지가 되는 부분이 정적인 페이지, 입력화면에 직접 접근하는 것을 허용할지에 대한 여부이다. 물론 같은 페이지에 DispatcherServlet거치지 않고 직접 접근하는 것도 좋은 방법이다. 하지만 이와 같이 개발할 경우 애플 리케이션 전체에 걸쳐서 영향을 미치게 인증이나 공통적인 기능을 구현할 경우 문제가 발생할 있다. 따라서 가능한 페이지에 직접 접근하는 것을 막는 것이 좋은 방법이다. 책에서는 개발자 뿐만 아니라 일반 사용자들이 JSP파일에 직접적으로 접근하는 것을 막기 위하여 모든 JSP파일을 WEB-INF 디렉토리내에 관리하고 있다. WEB-INF 디렉토리는 일반 사용자들이 직접 접근할 없는 디렉토리 이므로 모델 2 개발 방식으로 개발할 JSP파일을 관리 하기 위하여 좋은 곳이다. 10:02:54] 오후 http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (1 / 18) [2008-02-19

Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

  • Upload
    others

  • View
    6

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

Spring 프레임워크 워크북 6장 3강 - Spring MVC Dashboard > Spring Framework > ... > Spring 프레임워크 워크북 6장 2강 - Spring MVC > Spring 프레임워크 워크북 6장 3강

- Spring MVC

Community Spring

Framework

Log In | Sign Up

Browse Space Add News View Attachments (5) Info

Added by 박재성, last edited by 박재성 on 6월 02, 2007 (view change)

Labels: (None)

6장. Spring MVC Ⅰ

3. 샘플 애플리케이션에 Spring MVC 적용

지금까지 Spring MVC 기반으로 클라이언트의 요청을 처리하는 기본적인 과정에 대하여 살펴보았다. 이 절에서는 샘플 애플리케이션을

Spring MVC 기반하에서 구현해보면서 Spring MVC의 기능에 대하여 구체적으로 살펴보도록 하겠다.

3.1 메인 페이지 구현하기

Spring MVC의 가장 기본적인 기능을 구현하는 과정에 대하여 살펴보기 위하여 샘플 애플리케이션 페이지에서 비즈니스 계층과의 통신이 없

는 메인페이지를 구현하는 과정에 대하여 제일 먼저 살펴보도록 하자.

웹 애플리케이션을 개발하다보면 샘플 애플리케이션의 메인 페이지처럼 정적인 페이지에 접근해야 되는 경우가 종종 발생한다. 정적인 페이지

에 직접 접근할 수도 있겠지만 웹 애플리케이션의 모든 URL에 대하여 공통적인 작업을 처리할 필요가 있을 경우에는 정적인 페이지 또

한 DispatcherServlet을 통하여 접근하도록 개발할 경우 쉽게 해결할 수 있다.

모델 2 개발 방식으로 애플리케이션을 개발할 때 항상 논란의 여지가 되는 부분이 정적인 페이지, 입력화면에 직접 접근하는 것을 허용할지에

대한 여부이다. 물론 이 같은 페이지에 DispatcherServlet을 거치지 않고 직접 접근하는 것도 좋은 방법이다. 하지만 이와 같이 개발할 경우 애플

리케이션 전체에 걸쳐서 영향을 미치게 될 인증이나 공통적인 기능을 구현할 경우 문제가 발생할 수 있다. 따라서 가능한 페이지에 직접 접근하는

것을 막는 것이 좋은 방법이다.

이 책에서는 개발자 뿐만 아니라 일반 사용자들이 JSP파일에 직접적으로 접근하는 것을 막기 위하여 모든 JSP파일을 WEB-INF 디렉토리내에

서 관리하고 있다. WEB-INF 디렉토리는 일반 사용자들이 직접 접근할 수 없는 디렉토리 이므로 모델 2 개발 방식으로 개발할 때 JSP파일을 관리

하기 위하여 좋은 곳이다.

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (1 / 18) [2008-02-19

Page 2: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

정적인 페이지의 경우 비즈니스 계층과 통신하는 부분도 없을 뿐 아니라 단지 HTML이나 JSP화면을 출력하는 역할만을 담당하고 있다. 그런데

정적인 페이지에 접근하기 위하여 매번 새로운 Controller를 추가하는 것은 불필요한 작업이 아닐 수 없다. Spring MVC는 이 같은 단점을 보

완하기 위하여 UrlFilenameViewController를 지원하고 있다.

UrlFilenameViewController는 샘플 애플리케이션의 메인 페이지를 구현하기에는 충분하다. 그런데 이 Controller의 단점은 모든 URL을 다

음과 같이 처리한다는 것이다.

http://localhost:8080/chapter6/index.html => /chapter6/index.jsp

http://localhost:8080/chapter6/user/index.html => /chapter6/index.jsp

http://localhost:8080/chapter6/board/index.html => /chapter6/index.jsp

이와 같이 모든 서브 디렉토리에 대한 URL을 하나로 인식하여 처리한다는 것이다. 정적인 페이지는 특정 디렉토리에만 존재하는 것이 아니라

JSP를 관리하는 모든 디렉토리에 존재할 수 있기 때문에 필자는 UrlFilenameViewController를 모든 서브 디렉토리에 대해서도 처리하는 것

이 가능하도록 다음과 같이 구현하였다.

예제 6-2 MyUrlFilenameViewController.java

package net.javajigi.common.web;

.... 중간 생략 ....

public class MyUrlFilenameViewController implements Controller { protected final Log logger = LogFactory.getLog(getClass());

public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { String contextPath = request.getContextPath(); String uri = request.getRequestURI();

if( logger.isDebugEnabled() ) { logger.debug("URI : " + uri); logger.debug("ContextPath : " + contextPath); }

int begin = 0; if ((contextPath == null) || (contextPath.equals(""))) { begin = 1; } else { begin = contextPath.length() + 1; }

if( logger.isDebugEnabled() ) { logger.debug("Begin : " + begin); }

int end;

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (2 / 18) [2008-02-19

Page 3: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

if (uri.indexOf(";") != -1) { end = uri.indexOf(";"); } else if (uri.indexOf("?") != -1) { end = uri.indexOf("?"); } else { end = uri.length(); } String fileName = uri.substring(begin, end); if (fileName.indexOf(".") != -1) { fileName = fileName.substring(0, fileName.lastIndexOf(".")); }

for (Enumeration en = request.getParameterNames(); en.hasMoreElements();) { String attribute = (String) en.nextElement(); Object attributeValue = request.getParameter(attribute);

if( logger.isDebugEnabled() ) { logger.debug("set Attribute in Request : " + attribute + "=" + attributeValue); }

request.setAttribute(attribute, attributeValue); }

return new ModelAndView(fileName); }}

다음은 정적인 페이지에 접근할 때 사용할 확장자를 web.xml에 다음과 같이 추가해주었다.

예제 6-3 web.xml - 정적인 페이지를 담당하게 될 확장자를 추가하는 부분

<servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.html</url-pattern></servlet-mapping>

예제 6-1 에 이어 예제 6-3 을 web.xml에 추가했으므로 확장자가 ".do", ".html"에 해당하는 모든 URL은 DispatcherServlet이 처리하게 되

었다.

다음은 예제 6-2 에서 개발한 Controller를 URL과 매핑해주어야 한다. 예제 6-2 를 샘플애플리케이션에서 사용가능하도록 action-servlet.

xml에서 설정한 정보는 다음과 같다.

예제 6-4 action-servlet.xml - 메인 페이지를 위한 빈 설정 부분

<beans> <bean name="/**/*.html" class="net.javajigi.common.web.MyUrlFilenameViewController"/>

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (3 / 18) [2008-02-19

Page 4: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass"> <value>org.springframework.web.servlet.view.JstlView</value> </property> <property name="cache" value="false" /> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean></beans> >

예제 6-4 에서 메인 페이지를 위한 부분은 예제 6-2 의 MyUrlFilenameViewController을 정의한 부분이다. MyUrlFilenameViewController

에서 사용한 빈 이름을 보면 별표(asterisk, *)를 사용하여 확장자가 ".html"에 해당하는 모든 URL에 대하여 MyUrlFilenameViewController

을 매핑(Mapping)하도록 설정하고있다. Spring MVC에서는 URL과 Controller를 매핑할 때 별표를 사용하는 것이 가능하다.

나머지 HandlerMapping과 ViewResolver는 샘플 애플리케이션의 다른 Controller에서도 공통적으로 사용하는 빈 설정정보이

다. HandlerMapping과 ViewResolver에 대한 자세한 내용은 추후에 설명하도록 하겠다.

예제 6-4 까지의 구현을 완료한 다음 http://localhost:8080/chapter6/index.html 로 접근하면 샘플 애플리케이션의 메인 페이지에 접근

할 수 있다.

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (4 / 18) [2008-02-19

Page 5: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

그림 6-4 Spring MVC 기반으로 구현한 샘플 애플리케이션의 메인 화면

만약 사용자 관리 프로젝트와 자료실 게시판에서도 메인 페이지와 같은 정적인 페이지(일반적으로 입력화면에서도 사용가능하다.)가 존재한다

면 확장자가 ".html"을 이용하여 접근하는 것이 가능하다. 예를 들어 사용자 관리 프로젝트의 입력화면이 "/user/write.jsp"라면

http://localhost:8080/chapter6/user/write.html 로 접근하는 것이 가능하다.

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (5 / 18) [2008-02-19

Page 6: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

메인페이지의 접근 URL은 index.html이다. 그런데 메인 페이지 화면을 담당하고 있는 JSP파일의 위치는 "/WEB-INF/jsp/index.jsp"이다.

이와 같이 처리되도록 설정한 부분은 예제 6-4 의 ViewResolver 때문이다. ViewResolver에 대해서는 추후에 살펴보도록 하겠다.

그림 6-5 index.html 요청에 대한 Spring MVC의 생명주기

그림 6-5 를 보면 index.html에 대한 요청을 처리하기 위하여 ViewResolver가 사용된 것을 알 수 있다. 그 이유

는 MyUrlFilenameViewController에서 ModelAndView 클래스를 반환할 때 View에 대한 정보를 논리적인 이름인 "index"로 사용했기 때문

이다. 만약 MyUrlFilenameViewController을 다음과 같이 구현할 경우 그림 6-5 는 그림 6-6 과 같이 ViewResolver를 이용하지 않고 바

로 View 클래스를 이용하게 된다.

예제 6-5 수정된 MyUrlFilenameViewController.java

package net.javajigi.common.web;

.... 중간 생략 ....

public class MyUrlFilenameViewController implements Controller {

public ModelAndView handleRequest(HttpServletRequest request,

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (6 / 18) [2008-02-19

Page 7: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

HttpServletResponse response) {

.... [예제 6-2]와 동일 ....

String url = "/WEB-INF/jsp/" + fileName + ".jsp"; InternalResourceView view = new InternalResourceView(url);

return new ModelAndView(view); }}

예제 6-5 는 메인 화면의 뷰에 대한 정보를 구현하기 위하여 View 클래스(InternalResourceView)를 직접 이용하고 있는 것을 확인 할 수

있다.

그림 6-6 View 객체를 이용하여 View 정보를 전달하는 경우의 생명주기

Controller에서는 이와 같이 두가지 방법으로 View 정보를 전달할 수 있다. 그러나 예제 6-5 와 같이 Controller내부에서 View 객체를 직접

생성할 경우 예제 6-5 MyUrlFilenameViewController는 JSP 용도로 밖에 사용할 수 없다. 예제 6-2 와 같이 논리적 이름으로 View 정보를

표현하기 위하여 사용할 경우 빈 설정파일에서 ViewResolver 정보를 변경함으로서 Velocity, Excel, PDF등을 View로서 이용하는 것이 가능

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (7 / 18) [2008-02-19

Page 8: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

하다. 따라서 예제 6-5 와 같이 Controller에서 View 객체를 직접 생성함으로서 유연성을 저하시킬 것이 아니라, 예제 6-2 와 같이 논리적 이

름을 사용함으로서 ViewResolver를 사용하도록 구현하는 것이 좋은 개발방법이다.

3.2 MultiActionController를 이용하여 다수의 요청 처리하기

웹 애플리케이션을 개발하면서 하나의 페이지가 추가될 때마다 새로운 Controller를 하나씩 추가해야한다는 것은 상당히 짜증나는 작업이 아

닐 수 없다. 짜증나는 작업을 뒤로 하고서라도 페이지 수가 많아지면 많아질수록 관리해야될 Controller 클래스의 수도 같이 증가하게 된다. 빈

설정파일 또한 상당히 복잡해 질 것은 불을 보듯 뻔한 결과이다.

Controller의 이 같은 문제점을 해결하기 위하여 Spring MVC는 MultiActionController를 제공한다. MultiActionController는 하나

의 Controller를 구현함으로서 다수의 요청을 처리하는 것이 가능하도록 지원한다.

MultiActionController는 사용자 리스트 화면, 사용자 정보보기 화면과 같이 클라이언트가 전달하는 입력데이터가 많지 않아 특별한 유효성 체

크가 필요하지 않고 비즈니스 계층과의 통신이 필요한 경우에 유용하게 사용될 수 있다. 샘플 애플리케이션의 사용자 관리 프로젝트와 자료실

게시판의 많은 부분을 이 Controller 기반으로 구현하였다.

먼저 사용자 관리 프로젝트의 사용자 리스트 화면과 사용자 정보보기 화면을 MultiActionController을 이용하여 구현한 예제 소스를 살펴보면

다음과 같다.

예제 6-6 UserController.java - 사용자 리스트 및 정보보기 화면

package net.javajigi.user.web;

.... 중간 생략 ....

public class UserController extends MultiActionController { protected static final Log logger = LogFactory.getLog(UserController.class);

private UserService userService = null;

public void setUserService(UserService userService) { this.userService = userService; }

public ModelAndView view(HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { logger.debug("entering 'view' method..."); }

String userId = RequestUtils.getRequiredStringParameter(request, "userId");

return new ModelAndView("user/view", "user", userService .findUser(userId)); }

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (8 / 18) [2008-02-19

Page 9: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

public ModelAndView list(HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { logger.debug("entering 'list' method..."); }

return new ModelAndView("user/list", "userList", userService .findUserList()); }}

예제 6-6 은 사용자 관리 프로젝트의 사용자 리스트 화면(list() 메써드)과 사용자 정보보기 화면(view() 메써드)을 구현하기 위한 Controller

이다. MultiActionController를 상속할 경우 하나의 Controller에서 다수의 요청을 처리하는 것이 가능해진다.

예제 6-6 을 빈 설정파일에서 매핑하는 방법은 다음과 같다.

예제 6-7 action-servlet-xml - 예제 6-6 을 URL과 매핑하는 부분

<bean name="/user/listUser.do /user/viewUser.do" class="net.javajigi.user.web.UserController"> <property name="methodNameResolver"> <ref local="userControllerMethodNameResolver" /> </property> <property name="userService" ref="userService" /></bean>

<bean id="userControllerMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"> <property name="mappings"> <props> <prop key="/user/listUser.do">list</prop> <prop key="/user/viewUser.do">view</prop> </props> </property></bean>

예제 6-7 을 보면 예제 6-6 의 UserController하나에 두개(/user/listUser.do, /user/viewUser.do)의 URL이 매핑된 것을 확인할 수 있다.

이 각각의 URL이 호출될 때 UserController의 메써드에서 어느 메써드가 호출될지에 대한 정보는 "userControllerMethodNameResolver"

빈에서 PropertiesMethodNameResolver 클래스를 이용하여 매핑할 수 있다. 이와 같이 매핑을 연결할 경우 "/user/listUser.do"가 호출될

때 UserController의 list() 메써드가 호출되게 된다.

예제 6-7 에서 눈여겨 볼 부분은 사용자 관리 프로젝트의 비즈니스 계층을 담당하고 있는 UserService 인스턴스가 Spring 프레임워크

의 Setter Injection 방식으로 전달되고 있는 것을 확인할 수 있다. 이와 같이 Spring MVC를 이용할 경우 웹 애플리케이션 개발을 위한 모든

결합이 Dependency Injection 방식으로 구현하는 것이 가능해진다.

"/user/listUser.do"가 호출될 때 비즈니스 계층에서 전달된 사용자 리스트를 출력하는 JSP파일의 예제 소스를 보면 다음과 같다.

예제 6-8 list.jsp - /WEB-INF/jsp/user/list.jsp 10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (9 / 18) [2008-02-19

Page 10: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

<%@page contentType="text/html; charset=euc-kr" %><%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>

<html><head>

<title>사용자 관리 - 리스트</title><meta http-equiv="Content-Type" content="text/html; charset=euc-kr"><link rel=stylesheet href="${pageContext.request.contextPath}/css/global.css" type="text/css">

</head><body bgcolor=#FFFFFF text=#000000 leftmargin=0 topmargin=0 marginwidth=0 marginheight=0> <!-- list --> <table border="0" cellpadding="0" cellspacing="1" width="100%" bgcolor="BBBBBB"> <tr>

<td width=30% align=center bgcolor="E6ECDE" height="22">사용자 아이디</td>

<td width=30% align=center bgcolor="E6ECDE">이름</td>

<td align=center bgcolor="E6ECDE">이메일</td> </tr>

<c:forEach items="${userList}" var="user"> <tr> <td width=30% align=center bgcolor="ffffff" height="20"> ${user.userId} </td> <td width=30% bgcolor="ffffff" style="padding-left:10"> <a href="${pageContext.request.contextPath}/user/viewUser.do?userId=${user.userId}" class="user"> ${user.name} </a> </td> <td align=center bgcolor="ffffff"> ${user.email} </td> </tr> </c:forEach> </table> <!-- /list --> <br><!-- button --> <table border="0" cellpadding="0" cellspacing="1" width="100%"> <tr> <td align="right">

<input type="button" value="사용자 추가" name="add" onClick="location.href='${pageContext.request.contextPath}/user/editUser.do'"/> </td> </tr></table> </form></body>

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (10 / 18) [2008-02-19

Page 11: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

</html>

예제 6-8 은 예제 6-6 UserController에서 전달된 사용자 리스트를 화면에 출력하고 있다. 사용자 리스트를 화면에 출력하기 위하여 JSTL을

이용하고 있다. UserController의 list() 메써드에서 사용자 리스트를 "userList"로 전달했기 때문에 예제 6-8 에서 이 이름을 사용하여 사용

자 리스트 정보를 찾고 있는 것을 확인할 수 있다. "/user/viewUser.do"에 해당하는 사용자 정보보기 화면 또한 예제 6-8 과 같은 방식으로 구

현되어 있다.

그림 6-7 "/user/listUser.do"를 실행했을 때의 사용자 리스트 화면

사용자 관리 프로젝트의 경우 UserController를 빈 설정 파일에서 URL을 다르게 함으로서 접근하도록 매핑하였다. Spring MVC에서는 이 방

법 이외에 다른 방법을 지원하고 있다. 자료실 게시판의 게시물 리스트 화면과 게시물의 내용보기 화면을 MultiActionController로 구현하면 다

음과 같다.

예제 6-9 BoardController.java

package net.javajigi.board.web;

.... 중간 생략 .....

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (11 / 18) [2008-02-19

Page 12: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

public class BoardController extends MultiActionController { protected final Log logger = LogFactory.getLog(getClass());

private static final int DEFAULT_CURRENT_PAGE = 1;

private static final int DEFAULT_COUNT_PER_PAGE = 10;

private BoardService boardService = null;

public void setBoardService(BoardService boardService) { this.boardService = boardService; }

.... 중간 생략 .....

public ModelAndView list(HttpServletRequest request, HttpServletResponse response) throws Exception { int currentPage = RequestUtils.getIntParameter(request, "currentPage", DEFAULT_CURRENT_PAGE); int countPerPage = RequestUtils.getIntParameter(request, "countPerPage", DEFAULT_COUNT_PER_PAGE);

String pageDivideForm = dividePageForm(currentPage, countPerPage, request); request.setAttribute("pageDivideForm", pageDivideForm);

return new ModelAndView("board/list", "boardList", boardService .findBoardList(currentPage, countPerPage)); }

public ModelAndView view(HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { logger.debug("entering 'view' method..."); }

int boardNo = RequestUtils.getRequiredIntParameter(request, "boardNo");

return new ModelAndView("board/view", "board", boardService .findBoardWithView(boardNo)); }}

예제 6-9 예제 소스를 보면 예제 6-6 과 별반 다르지 않다는 것을 확인할 수 있다. 자료실 게시판을 구현하기 위하여 예제 6-9 를 빈 설정파일

에서 매핑한 정보는 다음과 같다.

예제 6-10 action-servlet.xml - 예제 6-9 를 URL과 매핑하는 부분

<bean name="/board/board.do" class="net.javajigi.board.web.BoardController"> <property name="boardService" ref="boardService" />

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (12 / 18) [2008-02-19

Page 13: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

<property name="methodNameResolver" ref="methodNameResolver" /></bean>

<bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> <property name="paramName"> <value>method</value> </property> <property name="defaultMethodName"> <value>list</value> </property></bean>

예제 6-10 의 매핑 정보를 정보를 "/board/board.do" 하나의 URL에 예제 6-9 를 매핑하고 있는 것을 확인할 수 있다. 예제 6-10 의 매핑 정

보에서 BoardController의 메써드를 호출하도록 결정하는 부분은 "methodNameResolver" 빈에서 ParameterMethodNameResolver를 이

용하는 부분이다. 예제 6-10 에서 설정한 내용은 URL을 통하여 전달되는 인자 중 "method"라는 이름을 가지는 인자의 값에 해당하는 메써드

를 호출한다는 것이다. 만약 "method"라는 인자가 없을 경우에는 list() 메써드를 디폴트로 호출하게 된다.

그림 6-8 자료실 게시판의 내용보기 화면

그림 6-8 의 URL을 보면 "/board/board.do"의 인자에 "method=view"가 있는 것을 확인할 수 있다. 이처럼 호출할 경우 BoardController 10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (13 / 18) [2008-02-19

Page 14: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

의 view() 메써드가 실행된다.

Spring MVC의 ParameterMethodNameResolver을 이용할 경우 MultiActionController에 메써드가 추가되더라도 빈 설정파일에 추가적인

설정이 필요없다. 단지 화면 이동시에 추가된 메써드 이름을 인자로 전달하면 된다.

MultiActionController를 사용할 때 매핑 방식을 어떤 방식으로 사용할지는 개발자들의 취향에 달려있다. 지금까지 살펴본 두가지 사용방법 모

두 장,단점을 가지고 있기 때문에 굳이 어느 방법을 사용할지 고정시킬 필요는 없다.

3.3 HandlerMapping을 이용하여 URL과 Controller 연결하기

지금까지 Spring MVC에서 지원하는 기본적인 Controller에 대하여 살펴보았다. Spring MVC에서 사용가능한 Controller에 대하여 더 알아

보기 전에 Controller를 URL과 매핑하는 방법에 대하여 살펴보도록 하겠다.

앞에서도 잠시 언급했지만 Spring MVC는 같은 기능을 지원하기 위하여 여러가지 옵션을 제공하고 있다. 따라서 Controller와 URL의 매핑을

지원하는 HandlerMapping 또한 여러가지 방법을 가지고 있다.

3.3.1 BeanNameUrlHandlerMapping

지금까지 샘플 애플리케이션에서 Spring MVC를 적용할 때 사용한 방법이 BeanNameUrlHandlerMapping을 사용한 방법이

다. BeanNameUrlHandlerMapping은 빈 이름과 URL을 Mapping한다. BeanNameUrlHandlerMapping을 이용하여 Mapping을 연결하는

방법은 Struts 프레임워크와 같은 방법으로 Struts 프레임워크를 사용한 개발자들에게는 익숙한 방법이다.

단지 다른 점이라면 Spring MVC의 BeanNameUrlHandlerMapping은 매핑을 위한 경로정보로 ANT 빌드툴에서 경로정보를 표현하기 위하여

사용하고 있는 스타일을 사용할 수 있다는 것이다. 예를 들어 ANT 빌드툴에서 별표 , 물음표 와 같은 기호들을 사용할 수 있듯

이 BeanNameUrlHandlerMapping에서도 사용가능하다.

예제 6-4 에서 다음과 같이 사용한 것을 확인할 수 있다.

<bean name="/*/.html" class="net.javajigi.common.web.MyUrlFilenameViewController"/>

빈 설정파일에 HandlerMapping이 설정되어 있지 않을 경우 Spring MVC는 BeanNameUrlHandlerMapping을 디폴트 HandlerMapping으

로 설정한다.

3.3.2 SimpleUrlHandlerMapping

SimpleUrlHandlerMapping은 매핑에 대한 정보를 각각의 Controller에서 설정하는 것이 아니라 하나의 저장소에서 관리하는 것이

다. Controller를 개발하는 개발자들은 빈을 정의하기만하고 이 Controller가 어떻게 매핑되어서 사용되는지에 대해서는 몰라도 된다.

앞에서 BeanNameUrlHandlerMapping으로 매핑된 정보를 SimpleUrlHandlerMapping을 사용하도록 변경하면 다음과 같다.

예제 6-11 action-servlet.xml - SimpleUrlHandlerMapping을 HandlerMapping으로 사용할 경우

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (14 / 18) [2008-02-19

Page 15: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

<bean id="staticViewController" class="net.javajigi.common.web.MyUrlFilenameViewController" />

<bean id="userController" class="net.javajigi.user.web.UserController"> <property name="methodNameResolver"> <ref local="userControllerMethodNameResolver" /> </property> <property name="userService" ref="userService" /></bean>

<bean id="userControllerMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"> <property name="mappings"> <props> <prop key="/user/listUser.do">list</prop> <prop key="/user/viewUser.do">view</prop> </props> </property></bean>

<bean id="boardController" class="net.javajigi.board.web.BoardController"> <property name="boardService" ref="boardService" /> <property name="methodNameResolver" ref="methodNameResolver" /></bean>

<bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> <property name="paramName"> <value>method</value> </property> <property name="defaultMethodName"> <value>list</value> </property></bean>

<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="**/*.html">staticViewController</prop>

<prop key="/user/listUser.do">userController</prop> <prop key="/user/viewUser.do">userController</prop>

<prop key="/board/board.do">boardController</prop> </props> </property></bean>

예제 6-11 을 보면 Controller는 일반적인 빈을 정의할 때와 별반 다를 것이 없다. 매핑에 대한 모든 정보는 예제 6-11 에서 보는 바와 같이

별도의 빈에서 관리하고 있는 것을 확인할 수 있다("urlMapping").

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (15 / 18) [2008-02-19

Page 16: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

"urlMapping" 빈에서 Controller와 URL을 매핑하기 위하여 <props/> 태그를 사용하고 있는 것을 알 수 있다. 이는 빈 설정파일에서

<props/>태그를 사용하지 않고 별도의 Properties파일에서 매핑 정보를 관리할 수 있다는 것이다.

SimpleUrlHandlerMapping을 사용할 경우 매핑 정보를 빈 설정파일이 아닌 별도의 파일에서 관리하는 것이 가능해진다. 예제 6-11 의 매핑

정보를 별도의 파일에서 관리하도록 변경하면 다음과 같다.

예제 6-12 action-servlet.xml - 매핑 정보를 URLMap.properties파일에서 관리하는 경우

<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>/WEB-INF/URLMap.properties</value> </property> </bean> </property></bean>

예제 6-13 URLMap.properties

**/*.html=staticViewController

## user module mapping/user/listUser.do=userController/user/viewUser.do=userController

## board module mapping/board/board.do=boardController

SimpleUrlHandlerMapping의 경우 Controller빈을 정의하고 매핑을 별도로 설정하는 불편함이 있다. 하지만 애플리케이션의 규모가 클 경우

매핑 정보를 수정할 필요가 있을 때 BeanNameUrlHandlerMapping보다 더 효율적으로 관리하는 것이 가능하다. 개발하는 입장에서

는 SimpleUrlHandlerMapping을 사용한 매핑 방법이 더 불편할 수도 있겠지만 관리하는 입장에서는 SimpleUrlHandlerMapping을 사용하

는 것이 더 좋은 선택일 것이다.

BeanNameUrlHandlerMapping과 SimpleUrlHandlerMapping에 대한 사용방법은 현재 진행하고 있는 프로젝트가 어느 부분에 중점을 두고

있느냐에 따라 결정하면 된다.

3.3.3 CommonsPathMapHandlerMapping

CommonsPathMapHandlerMapping은 매핑에 대한 정보를 Controller 클래스에 메타데이터를 추가하여 구현하는 것이 가능하도록 지원한

다. 이 책에서는 CommonsPathMapHandlerMapping에 대해서는 자세히 다루지 않겠다.

앞으로 많은 설정 정보들이 JDK 5.0에서 등장한 Annotation을 기반으로 작성될 것이다. 그러나 CommonsPathMapHandlerMapping 방법

은 JDK 5.0의 Annotation과 비슷한 방법을 지원하지만 별도의 컴파일 과정을 거처야 함으로서 진정한 Annotation 역할을 하지는 못하고 있

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (16 / 18) [2008-02-19

Page 17: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

는 상태이다.

3.3.4 하나의 이상의 HandlerMapping을 사용하고자 한다면

애플리케이션을 개발하다보면 HandlerMapping을 BeanNameUrlHandlerMapping와 SimpleUrlHandlerMapping 모두 사용해야하는 경우

가 발생할 수 있다. Spring MVC는 이와 같은 필요성을 지원하기 위하여 org.springframework.core.Ordered 인터페이스를 지원하고 있다.

Spring MVC는 HandlerMapping과 같이 같은 기능을 구현하기 위한 다양한 옵션을 제공하는 기능들이 많다. 그런데 이 같은 옵션들을 하나

의 ApplicationContext내에서 같이 사용하고자할 때 각 옵션에 우선 순위를 결정하는 것이 가능하다. Spring 프레임워크는

org.springframework.core.Ordered 인터페이스를 구현함으로서 이 같은 기능이 가능하도록 지원하고 있다.

Spring 프레임워크의 API에서 org.springframework.core.Ordered 인터페이스를 찾아보면 이 인터페이스를 구현하고 있는 클래스들이 상

당히 많다는 것을 알 수 있다. Spring 프레임워크에서는 Spring MVC 뿐만 아니라 다른 영역에서도 하나의 기능에 대해서 다양한 옵션을 지원

하는 곳이 많기 때문에 Ordered 인터페이스를 두어서 각각에 대한 우선순위를 결정할 수 있도록 지원하고 있다.

앞의 BeanNameUrlHandlerMapping과 SimpleUrlHandlerMapping으로 각각 매핑하였던 예제 소스를 BeanNameUrlHandlerMapping

와 SimpleUrlHandlerMapping을 같이 사용하도록 빈 설정파일을 변경하면 다음과 같다.

예제 6-14 action-servlet.xml - BeanNameUrlHandlerMapping와 SimpleUrlHandlerMapping을 모두 사용하는 경우

<bean name="/**/*.html" class="net.javajigi.common.web.MyUrlFilenameViewController" />

<bean name="/user/listUser.do /user/viewUser.do" class="net.javajigi.user.web.UserController"> <property name="methodNameResolver"> <ref local="userControllerMethodNameResolver" /> </property> <property name="userService" ref="userService" /></bean>

<bean id="userControllerMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"> <property name="mappings"> <props> <prop key="/user/listUser.do">list</prop> <prop key="/user/viewUser.do">view</prop> </props> </property></bean>

<bean id="boardController" class="net.javajigi.board.web.BoardController"> <property name="boardService" ref="boardService" />

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (17 / 18) [2008-02-19

Page 18: Spring MVC Ⅰ - jetzt.tistory.com fileSpring 프레임워크 워크북 6장 3강 - Spring MVC - Spring Framework - Confluence 정적인 페이지의 경우 비즈니스 계층과

- Spring MVC - Spring Framework - Confluence강 3장 6워크북 프레임워크Spring

<property name="methodNameResolver" ref="methodNameResolver" /></bean>

<bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> <property name="paramName"> <value>method</value> </property> <property name="defaultMethodName"> <value>list</value> </property></bean>

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> <property name="order"><value>1</value></property></bean>

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="order"><value>2</value></property> <property name="mappings"> <props> <prop key="/board/board.do">boardController</prop> </props> </property></bean>

예제 6-14 를 보면 하나의 빈 설정파일에서 BeanNameUrlHandlerMapping와 SimpleUrlHandlerMapping을 모두 사용하고 있는 것을 확

인할 수 있다. 그러나 실무 프로젝트를 진행할 때 위처럼 두가지의 HandlerMapping을 사용하는 경우는 많지 않을 것이다. 대부분의 프로젝트

들이 프로젝트 초반에 어느 HandlerMapping을 사용할지 결정한 다음 진행할 것이다.

● 이전 글 : Spring 프레임워크 워크북 6장 2강 - Spring MVC

● 다음 글 : Spring 프레임워크 워크북 6장 4강 - Spring MVC

Children Hide Children | View in hierarchy

Spring 프레임워크 워크북 6장 4강 - Spring MVC (Spring Framework)

Add Comment

Site running on a free Atlassian Confluence Open Source Project License granted to JavaJiGi Project. Evaluate Confluence today.

Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.3.1 Build:#643 1월 22, 2007) - Bug/feature request -

Contact Administrators

10:02:54]오후http://wiki.javajigi.net/pages/viewpage.action?pageId=28377093 (18 / 18) [2008-02-19