Spring MVC - 기타 Controller

2010. 9. 2. 00:54plming/Java - Spring

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

 write.jsp - 사용자 추가 화면용 JSP
 <input type="text" style="width:150" name="userId"/>

 public class UserModel extends BaseObject {
     private String userId = null;

 public class UserController extends MultiActionController {

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

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



Spring MVC의 MultiActionController는 입력 데이터에 대한 유효성 체크 기능을 지원하지 않는다.
Spring MVC에서는 데이터 바인딩 기능뿐만 아니라 유효성 체크기능까지 입력폼을 처리하기 위한 모든 기능을 지원하기 위하여 AbstractCommandController 클래스를 지원하고 있다.  하지만, 입력 화면이 추가될 때마다 하나씩의 Controller가 추가되어야 하며, 빈 설정 정보 또한 수정해 주어야 한다는 단점이 있다.


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


SimpleFormController를 기반으로 자료실 게시판을 구현하기 위하여 개발자들은 하나의 URL(/board/editBoard.do), 하나의 Controller (BoardFormController - SimpleFormController를 상속하고 있다.), 하나의 JSP (/WEB-INF/jsp/board/edit.jsp)가 필요할 뿐이다.  특이할만한 부분은 같은 URL 임에도 불구하고 URL이 GET 방식으로 호출되었느냐, POST 방식으로 호출되었느냐에 따라 다르게 동작한다.  SimpleFormController를 사용하는 경우 입력(또는 수정)폼에 접근할 때는 GET 방식으로 접근해야 하며, 게시물 추가, 수정과 같이 실질적인 데이터의 변경이 필요한 경우에는 POST 방식으로 접근해야 한다.

 SimpleFormController의 isFormSubmission(HttpServletRequest) 메써드는 디폴트로 HTTP 요청이 GET방식인지 POST 방식인지에 따라서 다른 워크플로우를 가진다.  만약 디폴트로 구현되어 있는 GET/POST에 의한 구분을 변경하고 싶다면 SimpleFormController의 isFormSubmission(HttpServletRequest) 메써드를 오버라이딩(Overriding)하면 된다.

Controller에 GET 방식으로 접근하게 될 경우에는 formBackingObject() 메써드가 실행되면서 폼 화면(edit.jsp)에서 필요한 데이터들을 전달하게 된다.  POST 방식으로 접근하게 될 경우에는 onSubmit() 메써드가 실행되면서 폼 화면에서 전달한 데이터를 이용하여 비즈니스 계층과 통신 작업을 실행하게 된다.

SimpleFormController가 폼 기능을 수행하기 위하여 실행되는 작업 흐름이 간단하지 않다.  SimpleFormController는 개발자들에게 유연성을 주기 위하여 많은 콜백 메써드들을 지원하고 있다.  SimpleFormController를 이해하고 제대로 사용하는 것이 생각만큼 쉽지 않다.


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

 <%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>

 <spring:bind path="board.name">
     <input type="text" style="width:150" name="name" value="${status.value}" />
     <span class="fieldError">${status.errorMessage}</span>
 </spring:bind>

 <spring:bind path="board.password">
     <input type="password" style="width:150" name="password" value="${status.value}" />
     <span class="fieldError">${status.errorMessage}</span>
 </spring:bind>

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

 <input type="submit" value="게시물 생성" name="add">


Spring MVC의 <bind/> 커스텀 태그를 이용하여 BoardFormController에서 전달된 모델 데이터를 출력한다.  위에서 사용하고 있는 "board" 이름은 Controller의 생성자에서 "setCommandName("board")"에서 지정한 값을 사용하는 것이다.  "board"이름에 저장되는 Command는 formBackingObject()메써드에서 반환되는 인스턴스이다.  그러므로 게시물 생성화면과 같이 "boardNo"가 존재하지 않는 경우에는 아무 값도 가지지 않는 Board 인스턴스가 반환되고, 수정화면과 같이 "boardNo"가 존재하는 경우에는 "boardNo"에 해당하는 Board 인스턴스가 반환되는 것이다.
onSubmit()메써드에서 입력 화면을 통하여 전달된 값에 대하여 게시물을 생성, 수정할지에 대한 판단은 submit 버튼의 이름에 따라 결정되게 된다.  Submit 버튼의 이름이 "add"이면 게시물 생성, "modify"이면 게시물 수정 작업을 진행하게 되는 것이다.




1. 처음으로 호출되는 메써드는formBackingObject() 메써드이다. formBackingObject() 메써드는 디폴트로 설정한 Command 클래스의 인스턴스를 생성한다. 만약 수정화면과 같이 데이터베이스로부터 데이터를 추출해야 하는 경우 이 메써드를 오버라이드(Override)해야한다. 이 메써드에 대한 자세한 내용은 예제 6-22 에서 볼 수 있다.
2. Request 패러미터로 전달되는 모든 값은 String이다. 그러나 바인딩할 Command 클래스의 속성으로는 모든 타입을 가질 수 있다. 심지어 String을 Object 타입으로 바인딩해야하는 경우도 있다. 이와 같이 Request 패러미터를 Command 클래스의 속성과 바인딩시키기 위하여 생성한 Custom Property Editor가 있다면 initBinder() 메써드에서 등록할 수 있다. 이 메써드에 대한 구현부분은 [예제 6-30]에서 볼 수 있다.
3. 빈 설정파일에서 bindOnNewForm 속성이 true로 설정되어 있다면 Request 패러미터와 Command 클래스의 데이터바인딩을 실행한다.
4. 빈 설정파일에서 sessionForm 속성이 true로 설정되어 있다면 Command 클래스를 세션에 저장한다.
5. referenceData() 메써드는 폼 화면을 구현하기 위하여 Command 클래스 이외에 다른 데이터가 필요할 때 오버라이드하여 새롭게 구현하는 것이 가능하다.
6. showForm() 메써드는 디폴트로 빈 설정파일에서 정의한 "formView" 속성에 해당하는 ModelAndView 객체를 반환한다. 만약 요청 인자, 상태에 따라 다른 페이지로 이동하고자 한다면 이 메써드를 오버라이드하여 새롭게 구현하는 것이 가능하다.




POST 방식으로 접근할 때가 GET 방식으로 접근할 때보다 상당히 복잡한 워크플로우를 가지는 것을 확인할 수 있다.  그 이유는 POST 방식으로 폼 화면의 데이터를 전송하고 있기 때문에 데이터 바인딩, 데이터에 대한 유효성 체크 기능이 추가적으로 구현되어야 하기 때문이다.

1. POST 방식으로 접근할 때의 첫 단계는 빈 설정파일에 sessionForm 속성이 true로 설정되어 있는지에 따라 나뉜다. sessionForm 속성이 true로 설정되어 있다면 세션에 저장되어 있는 Command 클래스를 반환하게 된다. 만약 Command 클래스가 세션에 존재하지 않는다면 handleInvalidSubmit() 메써드가 호출되면서 에러 페이지로 이동하게 된다.
2. sessionForm속성이 설정되어 있지 않다면(디폴트 false) GET 방식으로 접근할 때와 같이 formBackingObject(), initBinder() 메써드를 실행한다.
3. Request 패러미터와 Command 클래스의 데이터 바인딩을 진행한다.
4. 데이터 바인딩 후에 추가적인 구현이 필요하다면 onBind() 콜백 메써드를 오버라이드하여 구현하면 된다.
5. 빈 설정파일에 추가된 Validator가 존재한다면 Validator의 validate() 메써드를 호출함으로서 유효성 체크를 진행한다.
6. 유효성 체크까지 완료한 후 추가적인 구현이 필요하다면 onBindAndValidate() 콜백 메써드를 오버라이드하여 구현하면 된다.
7. BindException의 에러 리스트에 에러가 존재할 경우 showForm() 메써드를 호출하여 빈 설정파일의 formView 속성으로 정의되어 있는 페이지로 이동하게 된다.
8. BindException 에러 없이 정상적으로 처리될 경우 onSubmit() 또는 doSubmitAction() 메써드가 호출된다. onSubmit() 또는 doSubmitAction() 메써드의 디폴트 ModelAndView는 빈 설정파일의 successView 속성으로 정의되어 있는 페이지로 이동한다. 만약 Request 패러미터로 전달되는 값에 따라 다른 페이지로 이동해야한다면 오버라이드함으로서 구현하는 것이 가능하다.


[출처] http://www.javajigi.net/pages/viewpage.action?pageId=28377095
[출처] Spring 프레임워크 워크북