본문 바로가기

카테고리 없음

sessionForm example

브라우저의 [새로고침], [뒤로가기] 기능을 사용하여 재전송된 폼을 처리하지 않는 방법

폼을 전송하여 처리된 후에 출력되는 다음 페이지에서 [새로고침]이나 [뒤로가기] 버튼을 이용하면 다시 폼이 전송되고 정상적으로 폼 데이터가 처리되어 중복전송되는 경우를 볼 수 있다. 즉, 폼을 이용하지도 않고 브라우저는 기존 내용을 저장하고 있다가 다시 폼을 전송할 수가 있다는 것이다. 그러나 대부분의 경우에 이런 기능은 불필요하거나 오히려 원하지 않은 상품의 주문과 같은 부작용을 낳기도 한다. Spring 프레임워크에서는 직접적으로 폼을 이용하지 않는 상태의 데이터 전송을 식별하여 전송된 데이터를 처리하지 않도록 하는 방법으로 이러한 부작용을 피할 수 있도록 하고 있다. 내부적으로 HttpSession객체와 폼 데이터를 저장하는 커맨드객체를 이용하여 이러한 기능을 지원하고 있다.

AbstractFormController, SimpleFormController등의 콘트롤러에 sessionForm="true"로 설정하면 formView가 화면에 출력될 때 서버측의 HttpSession객체에 커맨드객체가 저장된다. 그리고 POST방식으로 폼을 전송하면 서버측의 세션객체에 커맨드객체가 저장되어 있는지 확인하여 저장되어 있지 않다면 handleInvalidSubmit()를 호출한다. 만약 폼 전송시에 서버측의 세션에 커맨드 객체가 생성되어 있다면 세션객체를 지우고 폼처리를 실행하게 된다.

브라우저에 폼이 출력될 때 서버측에서는 세션객체에 커맨드객체를 생성하여 저장하기 때문에 서버측에 커맨드객체가 존재한다는 것은 그 이용자는 브라우저의 폼을 이용하여 데이터를 전송한다는 것을 의미하므로 유효한 전송으로 간주할 수가 있기 때문에 바로 폼을 처리하는 로직이 실행되는 것이고, 데이터를 전송할 때 서버의 세션객체 안에 커맨드객체가 저장되어 있지 않다는 것은 정상적인 폼을 이용하여 데이터를 전송하는 상태가 아니라는 것으로 간주되므로 handleInvalidSubmit() 메소드를 호출하여 개발자로 하여금 무효한 데이터 전송을 처리할 기회를 주자는 의도이다.

[새로고침]이나 [뒤로]버튼을 눌렀을 때 폼이 재전송되는 것은 데이터를 중복해서 전송하는 무효한 전송으로 여길 때가 대부분이므로 이런 경우에 handleInvalidSubmit()를 오버라이드하여 폼이 재전송되는 것을 막고 다시 formView를 출력하는 내용으로 변경하는 것이 좋을 것이다. handleInvalidSubmit() 메소드는 디폴트 동작으로 폼 데이터를 재전송하도록 되어 있다.

bindOnNewForm="true"를 설정하면 GET방식으로 폼을 요청할 때 생성되는 커맨드객체에 파라미터를 바인드할 것인지의 여부를 설정하는 것이다. 폼 전송시 뿐만 아니라 formView를 요청하는 GET방식의 경우에도 파라미터는 전송할 수 있으므로 그 파라미터를 커맨드객체에 바인드하고 한다면 이 속성을 true로 설정하면 된다.

In session form mode, a submission without an existing form object in the session is considered invalid, like in case of a resubmit/reload by the browser. The handleInvalidSubmit method is invoked then, by default trying to resubmit. It can be overridden in subclasses to show corresponding messages or to redirect to a new form, in order to avoid duplicate submissions.

사용자 삽입 이미지






handleInvalidSubmit()메소드의 원형은 다음과 같다. 디폴트로 재전송된 폼 데이터도 정상적으로 처리하도록 되어 있다
protected ModelAndView handleInvalidSubmit(HttpServletRequest  request,
 HttpServletResponse  response) throws Exception  {
 
 Object  command = formBackingObject(request);
 ServletRequestDataBinder binder = bindAndValidate(request, command);
 BindException errors = new BindException(binder.getBindingResult());
 return processFormSubmission(request, response, command, errors);
}



부주의하게 재전송된 폼 데이터를 처리하지 않으려면 다음과 같이 handleInvalidSubmit 메소드를 오버라이드해 주면 된다.
 @Override
 protected ModelAndView handleInvalidSubmit(HttpServletRequest request,
   HttpServletResponse response) throws Exception {
  return new ModelAndView("loginForm", "resubmit", "폼 데이터가 중복전송되어서 서버에서 처리하지 않았습니다");
 }



handleInvalidSubmit()가 실행되려면 dispatcher-servlet.xml 파일에 설정해 주어야 한다.

dispatcher-servlet.xml파일의 일부 내용

<bean name="authenticator"
 class="test.Authenticator"/>

<bean name="loginCommandValidator"
 class="test.LoginCommandValidator"/>
 
<bean name="/login.htm"
     class="test.LoginFormController"
     p:sessionForm="true"
     p:validator-ref="loginCommandValidator"
     p:authenticator-ref="authenticator"
     p:commandClass="test.LoginCommand"
     p:commandName="loginCommand"
     p:successView="loginSuccess"
     p:formView="loginForm" />