Clean Code that Works.

http://blog.springsource.org/2012/08/29/integrating-spring-mvc-with-jquery-for-validation-rules/

위에 있는 내용 간단히 번역 및 소스 만들기


컨트롤러들에서 리퀘스트 맵핑, 어노테이션을 통한 리퀘스트 데이터 추출, 데이터 바인딩, 파일업로드 등등  전형적인 Spring MVC 의 특징들을 볼 수 있다.

반면에 JSP 안에서는 대부분의 HTML들이 기본적으로 존재 하고 있다.(Spring MVC 태그에 의해 생성되기를 반대하는) 더욱이 Spring MVC 태그 라이브러리들은 어떤 자바스크립트 코드도 생성 하지 않는다.

처음으로 상의 해야 할 내용은 어떻게 Spring MVC와 Jquery 그리고 Bean Validatin을 통합할 것인가 이다. 어떻게 JSP를 줄일 수 있는지 살펴보자

BEAN VALIDATION?

JSR 3030 Bean Validataion은  포괄적인 방법으로 선언적 Validation 방법을 제공한다. 

아래예제를 살펴 보자.

public class DiningForm {
  @Pattern(regexp="\\d{16}")
 
  private String creditCardNumber;
 
  @Size(1)
  private String merchantNumber;
 
  @Min(0)
  private double monetaryAmount;
 
  @NotNull
  private Date date;
 
  ...
 
}

유효성 검증이 호츨 되면 DiningForm의 인스턴스는 위의 Annontations에 의해 유효성이 검증 된다.

Spring 3.0에서, Spring MVC는 유효성 검증을 위한 Bean Validation을 통합했다.(위 방식의 @MVC의 유일한 방법은 아니나 명백하게 가장 대중적인 접근 방법이다.)

컨트롤러 메소드에서 아래와 같이 @Valid를 사용할 수 있다.

@RequestMapping(value="/update", method=RequestMethod.POST)
  public String update(@Valid DiningForm diningForm, BindingResult result) {
 
    if (result.hasErrors()) {
      return “rewards/edit”;
    }
 
    // continue on success...
 
  }
}

JSP 화면에서 에러메세지는 <form:errors /> 를 사용해서 표시될 수 있다.

<form:form modelAttribute="diningForm">
  <form:input path="firstName"/>
  <form:errors path="firstName"/>
  
</form:form>

위의 코드는 잘 작동하고 매우 심플하다. 하지만 어떠한 자바스크립트 코드도 생성하지 않는다. 따라서 부분적인 렌더링이나 클라이언트 측 유효성검사를 하지 않는다. 이 방법을 어떻게 행상시키는지 보도록 하자!


부분 렌더링을 위한 자바스크립트 추가.


"first name" 부분이 비어 있을때 무슨일이 발생하는지 살펴보자.

이전 예제에서 form 이 전송될 때 마다 모든 페이지가 전부 새로고침된다.

응답받은 HTML 소스는 아래와 같다.

우리의 목표는 응답 사이즈를 최소화 하는 것이다. JSON 방식을 사용해서 할 수 있다.

{"status":"FAIL","result":[{"fieldName":"firstName","message":"firstName  may not be empty"}]}

먼저 from 유효성 검증을 위해 jQuery form 전송을 사용할 것이다. form 이 유효성 검증을 통과할 때 form 일반적인 HTML form 전송 방식을 통해 전송된다.(이런식으로 다른 페이지로 redirect될 수 있다.)

간단한 ValidatationResponse 클래스를 만들어 보자

public class ValidationResponse {
 private String status;
 private List errorMessageList;
 
 public String getStatus() {
   return status;
 }
 public void setStatus(String status) {
   this.status = status;
 }
 public List getErrorMessageList() {
   return this.errorMessageList;
 }
 public void setErrorMessageList(List errorMessageList) {
   this.errorMessageList = errorMessageList;
 }
}

controller 클래스에서 action method를 추가하자.

@RequestMapping(value="/user.json")
public @ResponseBody ValidationResponse processForm (Model model, @Valid User user, BindingResult result ) {
 ValidationResponse res = new ValidationResponse();
 if(!result.hasErrors()){
   res.setStatus("SUCCESS");
 }
 // …
 return res;
}

@ResponseBody annotation에게 감사를 돌린다. 응답하는 오브젝트는 아래 다이어그램에서 설명하는 것처럼 JSON  으로 변경된다.

JSP에서 에러 메시지가 도착했을 경우 이것을 파싱해서 화면에 표시 해야 한다. 이 링크에서 좀 더 자세한 자바스크립트 소스를 볼 수 있다.

진보적인 향상 모범사례에 따르면 모든 자바스크립트 코드는 HTML form 바깥에 위치 해야 한다. 클라이언트 브라우저에서 자바스크립트가 사용불가로 되었을때 form은 모든 페이지 리프레시가 되도록 지원 해야 한다.

지금 부분적인 갱신작업을 위한 유요성 검증 작업을 진행하고 있는데, 2가지 개선 포인트가 있다.

  • 페이지 화면이 구리다.
  • 이 hello-world-style 페이지는 이미 100라인이나 된다. 이것을 줄일 방법이 필요하다.


BOOTSTRAP을 사용하여 포장 하기


이것은 Spring MVC와 연관되어 있지는 않지만 이런 허접한 UI 디자인가지곤 샘플 애플리케이션이라 하기가 어려웠다. 아직 들어 본적이 없는 경우에 트위터 Bootstrap 은  CSS 프레임워크처럼 되고 있다. 많은 개발자들이 이것을 좋아하는데 그 이유는 작은 노력으로 만족할만한 웹사이트를 만들 수 잇기 때문이다. Bootstrap CSS와 이미지들을 복사하고 난 후에 사용하면 된다(상세 코드는 이 링크). form 이 아래와 같은 모습으로 변경되었다.


"JSP SOUP"를 방지하기 위한 커스텀 태그 사용.

여기가 정말 재미있어지는 부분이다. 이미 작동하는 몇가지 코드가 있기는 하지만 이것을 읽기가 좀 어렵다. HTML, Javascript, CSS 와 JSP EL을 서로 섞을 것이다. 아래 코드처럼 좀 더 읽기가 편한 JSP 코드가 될 것이다. 

<html:form modelAttribute="user"  id="add-user-form" formUrl="/userAjaxCustomTag.htm">
 <html:inputField name="firstName" label="Enter your first name:" />
 <html:inputField name="lastName" label="Enter your last name:" />
 <div>
   <button type="submit">Save changes</button>
   <button type="reset">Cancel</button>
 </div>
</html:form>

커스텀 태그는 JAVA EE 의 한 부분이고 아파치 톰캣에서 완벽하게 동작한다. 놀랍게도 커스텀 태그를 만드는 일은 매우 쉽다. form input 필드를 사용하는 간단한 예를 보자. 아래 8라인의 코드를 보자.

<div id="firstName">
 <label>Enter your first name:</label>
 <div>
   <form:input path="firstName" />
   <span>
     <form:errors path="firstName" />
   </span>
 </div>
</div>

우리 목표는 이것을 1라인으로 표시하는 것이다.

<html:inputField name="firstName" label="Enter your first name:" />

WEB-INF 폴더에다가 아래처럼 새로운 태그 파일을 작성한다.

이 내용은 아래와 같다.

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ attribute name="name" required="true" rtexprvalue="true" %>
<%@ attribute name="label" required="true" rtexprvalue="true" %>
<div id="${name}">
 <label>${label}</label>
<div>
  <form:input path="${name}"/>
  <span><form:errors path="${name}"/></span>
</div>

userForm.jsp 파일로 돌아와서 커스텀 태그를 사용하기 위해 tag 폴더를 선언해준다.

<%@ taglib prefix="html" tagdir="/WEB-INF/tags/html" %>

아래처럼 새롭게 생성된 태그가 사용 가능 하다.

<html:inputField name="firstName" label="Enter your first name:" />

커스텀 태그는 이클립스나 STS 에 잘 통합되어 있어 코드 자동완성으로 접근이 가능하다.

같은 모양으로 자바스크립트 코드를 태그로 끄집어 내서 아래처럼 한줄로 호출 할 수 있다.

<ajax:formPartialRefresh validateUrl="/userAjaxBootstrap.json" formName="add-user-form"/>

결론

Spring MVC와 폼 유효성 검증에 대한 부분적인 렌더링에 대해서 알아 봤다. 겨우 몇분만에 JSP soup 을 좀더 간단하고 이해하기 쉬운 방법으로 변경 하였다. 

샘플 코드는 이 github에서 확인할 수 있다.