spring mvc Ⅰ file을 도메인 모델로 데이터 바인딩(data binding)하는 기능이...

19
Spring 프레임워크 워크북 64- Spring MVC - Spring Framework - Confluence Spring 프레임워크 워크북 64- Spring MVC Dashboard > Spring Framework > ... > Spring 프레임워크 워크북 63- Spring MVC > Spring 프레임워크 워크북 64- Spring MVC Community Spring Framework Log In | Sign Up Browse Space Add News View Attachments (6) Info Added by 박재성, last edited by 박재성 on 602, 2007 Labels: (None) 6. Spring MVC 3. 샘플 애플리케이션에 Spring MVC 적용 3.4 사용자 추가 수정화면 구현하기 사용자 관리 프로젝트의 사용자 추가(또는 회원가입) 수정화면과 같은 기능을 구현하기 위해서는 입력하는 값에 대한 유효성 체크와 입력값 도메인 모델로 데이터 바인딩(Data Binding)하는 기능이 필요하다. 애플리케이션을 구현하면서 가장 많은 시간이 소요되는 부분이 입력 데이터에 대한 유효성 체크와 데이터 바인딩을 처리하는 부분이다. 지금까지 대부분의 개발자들은 유효성을 체크하기 위하여 무수히 많은 자바 스크립트를 사용해왔으며, 데이터 바인딩 작업은 HttpServletRequest의하여 전달되는 인자를 하드코딩하는 것이 일반적이다. Spring MVC에서는 같은 불편함을 덜기 위하여 입력 데이터에 대한 유효성 체크와 데이터 바인딩 기능을 지원하고 있다. 절에서는 가지 기능 데이터 바인딩 기능에 대해서만 살펴보도록 하겠다. 나머지 유효성 체크에 대해서는 7장에서 자세하게 다루도록 하겠다. Spring MVC에서는 입력 화면(또는 수정화면)에서 전달되는 입력 데이터를 비즈니스 계층에 전달하기 위하여 HttpServletRequest담긴 자와 도메인 모델의 속성을 자동적으로 연결하는 데이터 바인딩을 지원하고 있다. 먼저 MultiActionController이용하여 데이터바인딩을 리하는 방법에 대하여 살펴보도록 하겠다. 예제 6-6 UserController사용자 추가 수정화면을 구현하기 위한 메써드를 추가하면 다음과 같다. 예제 6-15 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) { http://wiki.javajigi.net/pages/viewpage.action?pageId=28377095 (1 / 19) [2008-02-19 오후 10:03:04]

Upload: others

Post on 31-Oct-2019

5 views

Category:

Documents


0 download

TRANSCRIPT

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

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

- Spring MVC

Community Spring

Framework

Log In | Sign Up

Browse Space Add News View Attachments (6) Info

Added by 박재성, last edited by 박재성 on 6월 02, 2007

Labels: (None)

6장. Spring MVC Ⅰ

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

3.4 사용자 추가 및 수정화면 구현하기

사용자 관리 프로젝트의 사용자 추가(또는 회원가입) 및 수정화면과 같은 기능을 구현하기 위해서는 입력하는 값에 대한 유효성 체크와 입력값

을 도메인 모델로 데이터 바인딩(Data Binding)하는 기능이 필요하다. 웹 애플리케이션을 구현하면서 가장 많은 시간이 소요되는 부분이 입력

데이터에 대한 유효성 체크와 데이터 바인딩을 처리하는 부분이다. 지금까지 대부분의 개발자들은 유효성을 체크하기 위하여 무수히 많은 자바

스크립트를 사용해왔으며, 데이터 바인딩 작업은 HttpServletRequest에 의하여 전달되는 인자를 하드코딩하는 것이 일반적이다.

Spring MVC에서는 이 같은 불편함을 덜기 위하여 입력 데이터에 대한 유효성 체크와 데이터 바인딩 기능을 지원하고 있다. 이 절에서는 이 두

가지 기능 중 데이터 바인딩 기능에 대해서만 살펴보도록 하겠다. 나머지 유효성 체크에 대해서는 7장에서 자세하게 다루도록 하겠다.

Spring MVC에서는 입력 화면(또는 수정화면)에서 전달되는 입력 데이터를 비즈니스 계층에 전달하기 위하여 HttpServletRequest에 담긴 인

자와 도메인 모델의 속성을 자동적으로 연결하는 데이터 바인딩을 지원하고 있다. 먼저 MultiActionController를 이용하여 데이터바인딩을 처

리하는 방법에 대하여 살펴보도록 하겠다.

예제 6-6 UserController에 사용자 추가 및 수정화면을 구현하기 위한 메써드를 추가하면 다음과 같다.

예제 6-15 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) {

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

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

this.userService = userService; }

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

public ModelAndView add(HttpServletRequest request, HttpServletResponse response) throws Exception { User command = new User(); bind(request, command);

userService.addUser(command);

return dispatchView(request, response); }

public ModelAndView update(HttpServletRequest request, HttpServletResponse response) throws Exception { User command = new User(); bind(request, command);

userService.updateUser(command);

return dispatchView(request, response); }

private ModelAndView dispatchView(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpSession session = request.getSession();

if (session.getAttribute("loginUser") != null) { User loginUser = (User) session.getAttribute("loginUser"); if (loginUser.isAdmin()) { return list(request, response); } }

return new ModelAndView("redirect:/index.html"); }}

예제 6-15 를 보면 MultiActionController 클래스의 bind() 메써드를 이용하여 HttpServletRequest에 전달된 인자를 User 도메인 모델에 전

달하고 있는 것을 확인할 수 있다.

클라이언트가 입력한 데이터를 도메인 모델과 데이터 바인딩하기 위해서는 입력 화면에서 사용한 속성이름과 도메인 모델의 속성 이름이 같아

야한다.

예제 6-16 write.jsp - 사용자 추가 화면용 JSP

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

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

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

<table border="0" cellpadding="0" cellspacing="1" width="100%" bgcolor="BBBBBB"> <tr>

<td width=150 align=center bgcolor="E6ECDE" height="22">사용자 아이디</td> <td bgcolor="ffffff" style="padding-left:10"> <input type="text" style="width:150" name="userId"/> </td> </tr> <tr>

<td width=150 align=center bgcolor="E6ECDE" height="22">비밀번호</td> <td bgcolor="ffffff" style="padding-left:10"> <input type="password" style="width:150" name="password"/> </td> </tr> <tr>

<td width=150 align=center bgcolor="E6ECDE" height="22">비밀번호 확인</td> <td bgcolor="ffffff" style="padding-left:10"> <input type="password" style="width:150" name="password2"/> </td> </tr> <tr>

<td width=150 align=center bgcolor="E6ECDE" height="22">이름</td> <td bgcolor="ffffff" style="padding-left:10"> <input type="text" style="width:240" name="name"/> </td> </tr> <tr>

<td width=150 align=center bgcolor="E6ECDE" height="22">이메일 주소</td> <td bgcolor="ffffff" style="padding-left:10"> <input type="text" style="width:240" name="email"/> </td> </tr> <c:if test="${ loginUser.admin }"> <tr>

<td width=150 align=center bgcolor="E6ECDE" height="22">Admin 유무</td> <td bgcolor="ffffff" style="padding-left:10"> <input type="checkbox" name="admin" value="true" /> </td> </tr> </c:if></table>

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

예제 6-17 User.java

package net.javajigi.user.model;

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

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

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

public class User extends BaseObject { private String userId = null; private String password = null; private String password2 = null; private String name = null; private String email = null; private boolean admin = false;

.... 각 속성에 대한 setter, getter 메써드 ....}

예제 6-15 UserController와 같이 하나의 Controller에 사용자 관리 프로젝트의 모든 기능을 구현하도록 개발하는 것은 Controller 개발을 용

이하게 할 뿐만 아니라 빈 설정파일이 단순해지기 때문에 많은 잇점을 가져온다.

그런데 Spring MVC의 MultiActionController는 입력 데이터에 대한 유효성 체크 기능을 지원하지 않는다. 따라서 Spring MVC에서 지원하는

유효성 체크기능을 사용하지 않고 데이터 바인딩 기능만을 이용하고자할 때는 MultiActionController를 이용하여 구현하는 것이 가능하다.

Spring MVC에서는 데이터 바인딩 기능뿐만 아니라 유효성 체크기능까지 입력폼을 처리하기 위한 모든 기능을 지원하기 위하

여 AbstractCommandController 클래스를 지원하고 있다. 이 Controller는 데이터 바인딩 뿐만 아니라 유효성 체크까지 지원하고 있다. 예

제 6-15 를 AbstractCommandController 클래스를 이용하도록 구현하면 다음과 같다.

예제 6-18 BaseUserCommandController.java

package net.javajigi.user.web;

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

public abstract class BaseUserCommandController extends AbstractCommandController { protected UserService userService = null;

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

protected ModelAndView dispatchView(HttpServletRequest request) throws Exception { HttpSession session = request.getSession();

if (session.getAttribute("loginUser") != null) { User loginUser = (User) session.getAttribute("loginUser"); if (loginUser.isAdmin()) { return new ModelAndView("redirect:/user/listUser.do"); } }

return new ModelAndView("redirect:/index.html");

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

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

}}

예제 6-19 AddUserCommandController.java

package net.javajigi.user.web;

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

public class AddUserCommandController extends BaseUserCommandController { public AddUserCommandController() { setCommandClass(User.class); }

protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException ex) throws Exception { User user = (User)command; userService.addUser(user);

return dispatchView(request); }}

예제 6-20 UpdateUserCommandController.java

package net.javajigi.user.web;

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

public class UpdateUserCommandController extends BaseUserCommandController { public UpdateUserCommandController() { setCommandClass(User.class); }

protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException ex) throws Exception { User user = (User)command; userService.updateUser(user);

return dispatchView(request); }}

예제 6-15 에서는 MultiActionController 기반으로 Controller를 만들었기 때문에 하나의 Controllerd에서 사용자 추가와 수정 기능을 구현

하는 것이 가능했다. AbstractCommandController를 기반으로 이 기능을 구현하기 위해서는 예제 6-19, 예제 6-20 과 같이 각각

의 Controller가 필요하다. 예제 6-19, 예제 6-20 에서는 AbstractCommandController의 데이터 바인딩 기능만을 이용하고 있다. 데이터

유효성 체크 기능에 대해서는 7장에서 다루도록 하겠다.

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

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

AbstractCommandController을 이용하여 데이터 바인딩을 처리하는 것 또한 쉽게 구현할 수 있다. AbstractCommandController이 데이터

바인딩 및 데이터에 대한 유효성 체크 기능을 지원하고 있지만 이 Controller를 이용할 경우 입력 화면이 추가될 때마다 하나씩의 Controller

가 추가되어야 하며, 빈 설정 정보 또한 수정해 주어야 한다는 단점이 있다.

예제 6-19, 예제 6-20 을 URL과 매핑 시키기 위하여 정의한 빈 설정파일은 다음과 같다.

예제 6-21 action-servlet.xml - 사용자 추가 및 수정화면을 위한 빈 설정

<bean name="/user/addUser.do" class="net.javajigi.user.web.AddUserCommandController"> <property name="userService" ref="userService" /></bean>

<bean name="/user/editUser.do" class="net.javajigi.user.web.UpdateUserCommandController"> <property name="userService" ref="userService" /></bean>

3.5 SimpleFormController를 이용하여 자료실 게시판 입력 폼 구현하기

Spring MVC는 입력 폼을 구현하기 위하여 SimpleFormController라는 새로운 형태의 Controller를 지원하고 있다. SimpleFormController

는 하나의 Controller만으로 자료실 게시판 입력, 수정화면에 대한 정교한 처리가 가능하도록 지원하고 있다. SimpleFormController를 제대

로 이해하고 사용할 경우 입력폼을 구현하기 위하여 필요로 했던 많은 작업들을 처리하는 것이 가능해진다.

Spring MVC 기반하에서 사용자 관리 프로젝트의 입력폼을 구현하기 위하여 구현하는 과정을 살펴보면 다음과 같다.

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

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

그림 6-9 사용자 관리 프로젝트 입력, 수정 폼을 처리하기 위한 흐름도

그림 6-9 를 보면 사용자 관리 프로젝트의 입력, 수정폼과 같이 간단한 화면을 구현하기 위하여 상당히 복잡한 과정을 거치고 있다는 것을 알

수 있다. 사용자 관리 프로젝트의 입력, 수정폼을 구현하기 위하여 개발자는 모두 4개의 서로 다른 URL이 필요하며, 4개의 Controller, 두개

의 JSP파일이 필요하다. 그림 6-9 는 에러 없이 정상적으로 처리되었을 때의 페이지 흐름도를 보여주고 있다. 만약 데이터에 대한 유효성 체

크시, 비즈니스 계층과의 통신시 발생하는 에러처리까지 모두 고려한다면 그림 6-9 는 훨씬 더 복잡해질 것이다.

Spring MVC에서는 이와 같이 복잡한 폼 화면을 구현하기 위하여 SimpleFormController를 두고 있다. 자료실 게시판에서 게시물 추가와 수

정 기능을 SimpleFormController를 기반으로 구현해보면서 SimpleFormController가 가지고 있는 기능에 대하여 자세하게 살펴보도록 하

겠다.

먼저 SimpleFormController를 기반으로 자료실 게시판의 폼 기능을 구현할 경우의 흐름도를 살펴보면 다음과 같다.

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

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

그림 6-10 자료실 게시판 입력, 수정폼을 처리하기 위한 위한 흐름도 - SimpleFormController를 사용할 경우

그림 6-10 은 SimpleFormController를 기반으로 자료실 게시판의 폼 기능을 처리했을 때의 흐름도이다. 그림 6-10 을 보면 자료실 게시판

을 구현하기 위하여 개발자들은 하나의 URL(/board/editBoard.do), 하나의 Controller (BoardFormController - SimpleFormController

를 상속하고 있다.), 하나의 JSP (/WEB-INF/jsp/board/edit.jsp)가 필요할 뿐이다. 단 그림 6-10 에서 특이할만한 부분은 같은 URL 임에도

불구하고 URL이 GET 방식으로 호출되었느냐, POST 방식으로 호출되었느냐에 따라서 다른 동작을 하고 있는 것을 알 수 있

다. SimpleFormController를 사용하는 경우 입력(또는 수정)폼에 접근할 때는 GET 방식으로 접근해야 하며, 게시물 추가, 수정과 같이 실질

적인 데이터의 변경이 필요한 경우에는 POST 방식으로 접근해야 한다.

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

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

SimpleFormController의 isFormSubmission(HttpServletRequest) 메써드는 디폴트로 [그림 6-30]과 같이 HTTP 요청이 GET방식인

지 POST 방식인지에 따라서 다른 워크플로우를 가진다. 만약 디폴트로 구현되어 있는 GET/POST에 의한 구분을 변경하고 싶다

면 SimpleFormController의 isFormSubmission(HttpServletRequest) 메써드를 오버라이딩(Overriding)하면 된다.

정말 그림 6-10 의 흐름도에서 볼 수 있는 것처럼 구현하는 것이 가능하다는 이야기인가? 자료실 게시판의 폼 기능을 구현하기 위하여 개발한

예제 소스를 보면서 확인해 보도록 하겠다.

예제 6-22 BoardFormController.java

package net.javajigi.board.web;

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

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

private String realUploadPath = null;

private BoardService boardService = null;

public void setRealUploadPath(String realUploadPath) { this.realUploadPath = realUploadPath; }

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

public BoardFormController() { setCommandName("board"); setCommandClass(Board.class); }

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

protected Object formBackingObject(HttpServletRequest request) throws ServletException { if (logger.isDebugEnabled()) { logger.debug("entering 'formBackingObject' method..."); }

int boardNo = RequestUtils.getIntParameter(request, "boardNo", 0);

http://wiki.javajigi.net/pages/viewpage.action?pageId=28377095 (9 / 19) [2008-02-19 오후 10:03:04]

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

if ( boardNo != 0 ) {

// 게시물 수정시 Board board = boardService.findBoard(boardNo);

if (board == null) { return new Board(); }

return board; } else {

// 게시물 추가시 return new Board(); } }

protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException exception) throws Exception { if (logger.isDebugEnabled()) { logger.debug("entering 'onSubmit' method..."); logger.debug("Board : " + command); }

Board board = (Board)command; List boardFileList = getBoardFileList(request); board.setBoardFiles(boardFileList);

if (request.getParameter("add") != null) { if (logger.isDebugEnabled()) { logger.debug("executing 'add Board' method..."); }

boardService.addBoard(board); } else { if (logger.isDebugEnabled()) { logger.debug("executing 'update Board' method..."); }

boardService.updateBoard(board); }

return new ModelAndView(getSuccessView()); } }

예제 6-22 는 SimpleFormController의 하위 클래스로서 자료실 게시판의 폼 기능을 구현하고 있는 Controller이다. 예상보다는 간단한 것

을 확인할 수 있다. 예제 6-22 BoardFormController에 GET 방식으로 접근하게 될 경우에는 formBackingObject() 메써드가 실행되면서

폼 화면(edit.jsp)에서 필요한 데이터들을 전달하게 된다. POST 방식으로 접근하게 될 경우에는 onSubmit () 메써드가 실행되면서 폼 화면에

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

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

서 전달한 데이터를 이용하여 비즈니스 계층과 통신 작업을 실행하게 된다.

SimpleFormController가 폼 기능을 수행하기 위하여 실행되는 작업 흐름이 앞에서 설명한 것처럼 간단하지 않다. SimpleFormController는

개발자들에게 유연성을 주기 위하여 많은 콜백 메써드들을 지원하고 있다. SimpleFormController를 이해하고 제대로 사용하는 것이 생각만

큼 쉽지 않다. 그런데 처음부터 SimpleFormController가 지원하는 모든 메써드들을 설명할 경우 독자들이 이해하기 더 힘들 것으로 생각한다.

따라서 이 부분에서는 SimpleFormController의 가지고 있는 기능 중 일부분의 기능에 대해서만 살펴보고 SimpleFormController가 지원하

는 다른 메써드들에 대해서는 추후에 살펴보도록 하겠다.

예제 6-22 를 빈 설정 파일에서 URL과 매핑한 정보를 살펴보면 다음과 같다.

예제 6-23 action-servlet.xml - 예제 6-22 매핑 정보

<bean name="/board/editBoard.do" class="net.javajigi.board.web.BoardFormController"> <property name="boardService" ref="boardService" /> <property name="realUploadPath"> <value>D:/Temp/fileupload/upload/</value> </property> <property name="formView" value="board/edit" /> <property name="successView" value="redirect:/board/board.do" /></bean>

SimpleFormController를 빈 설정파일에서 정의할 때 입력화면에 대한 정보와 작업이 성공적으로 완료했을 때 이동하게될 URL 정보를 설정

하는 것이 가능하다.

마지막으로 살펴볼 예제 소스는 입력과 수정시 사용하게 될 JSP파일이다. 어떻게 하나의 JSP파일로 입력과 수정 작업을 같이 진행할 수 있는

지에 대하여 살펴보도록 하겠다.

예제 6-24 edit.jsp - 자료실 게시판 게시물 생성 및 수정화면을 담당하는 JSP

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

<html><head>

<title>자료실 게시판 - 게시물 추가</title><meta http-equiv="Content-Type" content="text/html; charset=euc-kr"><link rel=stylesheet href="${pageContext.request.contextPath}/css/board.css" type="text/css"></head><body bgcolor=#FFFFFF text=#000000 leftmargin=0 topmargin=0 marginwidth=0 marginheight=0><!-- write Form --><form name="boardForm" action="${pageContext.request.contextPath}/board/editBoard.do" method="post" enctype="multipart/form-data"><input type="hidden" name="boardNo" value="${board.boardNo}"/> <table border="0" cellpadding="0" cellspacing="1" width="100%" bgcolor="BBBBBB">

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

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

<tr> <td width=150 align=center bgcolor="E6ECDE" height="22">

성명 </td> <td bgcolor="ffffff" style="padding-left:10"> <c:choose> <c:when test="${not empty board.name }"> <spring:bind path="board.name"> <input type="text" style="width:150" name="name" value="${status.value}" /> <span class="fieldError">${status.errorMessage}</span> </spring:bind> </c:when> <c:otherwise> <input type="text" style="width:150" name="name" value="${loginUser.name}"> </c:otherwise> </c:choose> </td> </tr> <tr> <td width=150 align=center bgcolor="E6ECDE" height="22">

비밀번호 </td> <td bgcolor="ffffff" style="padding-left:10"> <spring:bind path="board.password"> <input type="password" style="width:150" name="password" value="${status.value}" /> <span class="fieldError">${status.errorMessage}</span> </spring:bind> </td> </tr>

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

</table><table width=100% border=0 cellpadding=0 cellspacing=0> <tr> <td align=center> <c:choose> <c:when test="${board.boardNo != 0}">

<input type="submit" value="게시물 수정" name="modify"/> </c:when> <c:otherwise>

<input type="submit" value="게시물 생성" name="add"> </c:otherwise> </c:choose> &nbsp;

<input type="button" value="목록" onClick="location.href='${pageContext.request.contextPath}/board/board.do'"> </td> </tr></table> </form>

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

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

</body></html>

Spring MVC는 Controller에서 전달되는 모델 데이터를 화면에 출력하기 위한 용도로 커스텀 태그를 지원하고 있다. 예제 6-24 를 보면

Spring MVC의 <bind/> 커스텀 태그를 이용하여 BoardFormController에서 전달된 "board" 모델 데이터를 출력하고 있다. 예제 6-24 에

서 사용하고 있는 "board" 이름은 예제 6-22 BoardFormController의 생성자에서 "setCommandName("board")"에서 지정한 값을 사용

하는 것이다. "board"이름에 저장되는 Command는 예제 6-22 의 formBackingObject() 메써드에서 반환되는 인스턴스이다. 그러므로 게

시물 생성화면과 같이 "boardNo"가 존재하지 않는 경우에는 아무 값도 가지지 않는 Board 인스턴스가 반환되고, 수정화면과 같

이 "boardNo"가 존재하는 경우에는 "boardNo"에 해당하는 Board 인스턴스가 반환되는 것이다.

예제 6-22 의 onSubmit() 메써드에서 입력 화면을 통하여 전달된 값에 대하여 게시물을 생성, 수정할지에 대한 판단은 예제 6-24 의

submit 버튼의 이름에 따라 결정되게 된다. Submit 버튼의 이름이 "add"이면 게시물 생성, "modify"이면 게시물 수정 작업을 진행하게 되는

것이다.

예제 6-24 를 실행한 결과 화면을 보면 "boardNo" 값의 존재 유무에 따라 다른 결과 화면을 보여주고 있는 것을 확인할 수 있다.

http://wiki.javajigi.net/pages/viewpage.action?pageId=28377095 (13 / 19) [2008-02-19 오후 10:03:04]

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

그림 6-11 게시물 생성화면 - boardNo 값이 없는 경우

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

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

그림 6-12 게시물 수정화면 - boardNo 값이 존재할 경우

지금까지 자료실 게시판의 폼 기능을 구현하기 위하여 Spring MVC의 SimpleFormController를 이용하는 방법에 대하여 살펴보았다. 앞의 예

제를 통해서 알 수 있듯이 SimpleFormController는 접근하는 URL이 GET/POST에 따라서 서로 다른 방식으로 실행되게 된

다. SimpleFormController가 GET/POST에 따라 처리하는 과정을 살펴보면 다음 그림과 같다.

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

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

그림 6-13 GET 방식으로 SimpleFormController에 접근할 경우의 흐름도

앞에서 구현한 자료실 게시판의 Controller를 보면 GET 방식으로 접근할 때 formBackingObject() 메써드 하나만을 구현하고 있다. 그러나

[그림 6-13]에서 보는 바와 같이 GET 방식으로 접근할 때 여러 단계를 거친 다음에 최종 화면을 출력하게 된다. GET 방식으

로 SimpleFormController에 접근할 때의 과정을 살펴보면 다음과 같다.

● 처음으로 호출되는 메써드는formBackingObject() 메써드이다. formBackingObject() 메써드는 디폴트로 설정한 Command 클래스의 인스

턴스를 생성한다. 만약 수정화면과 같이 데이터베이스로부터 데이터를 추출해야 하는 경우 이 메써드를 오버라이드(Override)해야한다. 이 메

써드에 대한 자세한 내용은 예제 6-22 에서 볼 수 있다.

● Request 패러미터로 전달되는 모든 값은 String이다. 그러나 바인딩할 Command 클래스의 속성으로는 모든 타입을 가질 수 있다. 심지

어 String을 Object 타입으로 바인딩해야하는 경우도 있다. 이와 같이 Request 패러미터를 Command 클래스의 속성과 바인딩시키기 위하여

생성한 Custom Property Editor가 있다면 initBinder() 메써드에서 등록할 수 있다. 이 메써드에 대한 구현부분은 [예제 6-30]에서 볼 수 있다.

● 빈 설정파일에서 bindOnNewForm 속성이 true로 설정되어 있다면 Request 패러미터와 Command 클래스의 데이터바인딩을 실행한다.

● 빈 설정파일에서 sessionForm 속성이 true로 설정되어 있다면 Command 클래스를 세션에 저장한다.

● referenceData() 메써드는 폼 화면을 구현하기 위하여 Command 클래스 이외에 다른 데이터가 필요할 때 오버라이드하여 새롭게 구현하는

것이 가능하다.

● showForm() 메써드는 디폴트로 빈 설정파일에서 정의한 "formView" 속성에 해당하는 ModelAndView 객체를 반환한다. 만약 요청 인자, 상

태에 따라 다른 페이지로 이동하고자 한다면 이 메써드를 오버라이드하여 새롭게 구현하는 것이 가능하다.

이와 같이 Spring 프레임워크의 SimpleFormController는 GET 요청에 대한 워크플로우상에서 개발자들이 추가적인 기능을 구현할 수 있도

록 지원하고 있다. 그렇다면 POST 요청에 대한 워크플로우는 어떻게 될까? POST 요청에 대한 흐름도를 살펴보면 다음과 같다.

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

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

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

Spring 프레임워크 워크북 6장 4강 - Spring MVC - Spring Framework - Confluence그림 6-14 POST 방식으로 SimpleFormController에 접근할 경우의 흐름도

그림 6-14 를 보면 POST 방식으로 접근할 때가 GET 방식으로 접근할 때보다 상당히 복잡한 워크플로우를 가지는 것을 확인할 수 있다. 그 이

유는 POST 방식으로 폼 화면의 데이터를 전송하고 있기 때문에 데이터 바인딩, 데이터에 대한 유효성 체크 기능이 추가적으로 구현되어야 하

기 때문이다. 그림 6-14 에 대하여 더 구체적으로 살펴보면 다음과 같다.

● POST 방식으로 접근할 때의 첫 단계는 빈 설정파일에 sessionForm 속성이 true로 설정되어 있는지에 따라 나뉜다. sessionForm 속성이

true로 설정되어 있다면 세션에 저장되어 있는 Command 클래스를 반환하게 된다. 만약 Command 클래스가 세션에 존재하지 않는다

면 handleInvalidSubmit() 메써드가 호출되면서 에러 페이지로 이동하게 된다.

● sessionForm속성이 설정되어 있지 않다면(디폴트 false) GET 방식으로 접근할 때와 같이 formBackingObject(), initBinder() 메써드를 실

행한다.

● Request 패러미터와 Command 클래스의 데이터 바인딩을 진행한다.

● 데이터 바인딩 후에 추가적인 구현이 필요하다면 onBind() 콜백 메써드를 오버라이드하여 구현하면 된다.

● 빈 설정파일에 추가된 Validator가 존재한다면 Validator의 validate() 메써드를 호출함으로서 유효성 체크를 진행한다.

● 유효성 체크까지 완료한 후 추가적인 구현이 필요하다면 onBindAndValidate() 콜백 메써드를 오버라이드하여 구현하면 된다.

● BindException의 에러 리스트에 에러가 존재할 경우 showForm() 메써드를 호출하여 빈 설정파일의 formView 속성으로 정의되어 있는 페이

지로 이동하게 된다.

● BindException 에러 없이 정상적으로 처리될 경우 onSubmit() 또는 doSubmitAction() 메써드가 호출된다. onSubmit() 또

는 doSubmitAction() 메써드의 디폴트 ModelAndView는 빈 설정파일의 successView 속성으로 정의되어 있는 페이지로 이동한다. 만

약 Request 패러미터로 전달되는 값에 따라 다른 페이지로 이동해야한다면 [예제 6-22]와 같이 오버라이드함으로서 구현하는 것이 가능하다.

● "Professional Java Development with the Spring Framework", Rod Johnson, Juergen, Alef Arendsen, Thomas Risberg, Colin

Sampaleanu, 2005, Wrox 470-474Page : SimpleFormController의 워크플로우에 대하여 더 자세하게 설명하고 있다. 그림 6-13 과

그림 6-14 은 이 책의 그림 12-6 과 그림 12-7 을 인용하였다.

그림 6-13 과 그림 6-14 를 보면 SimpleFormController는 개발자들에게 유연성을 제공하기 위하여 각 단계마다 콜백 메써드를 제공하고

있다. 개발자들은 SimpleFormController를 상속하는 하위 클래스에서 이 콜백 메써드를 오버라이딩(Overriding)함으로서 개발자들이 원하

는 기능을 추가적으로 구현하는 것이 가능하다.

SimpleFormController의 흐름도를 보면 알겠지만 SimpleFormController의 기능이 생각보다 복잡하다는 것을 알 수 있다. 그러

나 SimpleFormController의 데이터 바인딩이나 유효성체크등에 특별히 추가적으로 구현할 기능이 없다면 [예제 6-22]에서 보는 바와 같

이 formBackingObject(),onSubmit() 메써드만을 오버라이드함으로서 쉽게 구현할 수 있다.

그림 6-13 과 그림 6-14 의 흐름도를 보면 알 수 있듯이 SimpleFormController를 제대로 사용하기 위해서는 많은 시간을 투자해야한다. 그

러나 시간을 투자한 만큼 지금까지 폼 기능을 처리하기 위하여 할애했던 많은 시간을 절약하는 것이 가능하며, 유지보수 또한 향상 시키는 것이

가능하다.

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

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

SimpleFormController를 사용할 경우 유지보수가 향상될 수 있다고 하였다. 그러나 이에 대한 기준은 유지보수를 담당하는 개발자가 Spring

프레임워크에 대한 지식을 알고 있으며, SimpleFormController의 메커니즘을 이해하고 있을 때를 이야기하는 것이다. 유지보수를 담당하는

개발자가 Spring 프레임워크에 대하여 모를 경우 유지보수성은 더 떨어질 수 밖에 없다.

Spring MVC는 이 장에서 다룬 Controller 이외에도 다양한 종류의 Controller를 제공하고 있다. 이 장에서는 웹 애플리케이션을 개발할 때 가

장 필요할 것으로 생각하는 Controller에 대해서만 다루고 있다. 이 장에서 다룬 Controller만 사용해도 웹 애플리케이션을 개발하는데 충분할

것이다. 그러나 Spring MVC에서 제공하는 다른 Controller를 사용할 필요가 있다면 Spring 프레임워크의 레퍼런스 문서를 참고하기 바란다.

이 장에서 다룬 Controller를 이해하고 사용할 수 있다면 새로운 Controller도 쉽게 사용할 수 있을 것이다.

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

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

Children Hide Children | View in hierarchy

Spring 프레임워크 워크북 6장 5강 - 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

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