Double Submit Prevention

Spring MVC에서는 double submit을 방지하기 위해 AbstractFormController를 제공하고, 폼 컨트롤러를 구현 시에 사용하는 SimpleFormController 또한 AbstractFormController를 상속받았기 때문에 위와 같은 처리가 가능하다. XML 기반의 double submit 방지 기능 적용 방법은 본 매뉴얼 >> Spring MVC >> Extension >> Double Submit 부분을 참고한다. 본 문서에서는 Annotation을 사용하여 다른 클래스를 상속받지 않고도 double submit 방지 기능을 구현하는 방법에 대해서 자세히 알아본다.

Annotation을 이용한 Double Submit 방지

annotation을 이용한 Double Submit 방지는 다음과 같은 원리로 구현된다.
  • Double submission을 방지하고자 하는 form 객체를 model로 저장

  • 다음 예제와 같이 ModelAndView, ModelMap 등을 이용하여 저장한다.
    @RequestMapping(params = "param=addView")
    public ModelAndView addUserView() {
        ModelAndView mnv = new ModelAndView("/jsp/user/userForm.jsp");
        mnv.addObject("user", new User());
        return mnv;
    }
    @RequestMapping(params = "param=addView")
    public String addUserView(ModelMap map) {
        map.addAttribute("user", new User());
        return "/jsp/user/userForm.jsp";
    }
  • 저장한 model을 @SessionAttributes로 정의

  • 다음 예제와 같이 컨트롤러 클래스 선언부에 @SessionAttributes("user")로 정의한다.
    @Controller
    @RequestMapping("/user.do")
    @SessionAttributes("user")
    public class EditUserController {
    	...중략...
    }
  • 컨트롤러 메소드에서 폼 처리 완료 후 Session status 변경
  • @RequestMapping(params = "param=add")
    public String addUser(HttpServletRequest request, @ModelAttribute("user")
      User user, BindingResult result, SessionStatus status) throws Exception {
        userService.addUser(user);
        status.setComplete();
        return "/userList.do";    
    }
  • status.setComplete()는 session에서 저장된 model을 삭제하는 이벤트 발생
  • 따라서, 이후에 다시 submit 요청이 온 경우 session에 저장된 model이 삭제되었기 때문에 아래와 같이 org.springframework.web.HttpSessionRequiredException발생
  • org.springframework.web.HttpSessionRequiredException: 
          	Session attribute 'dept' required - not found in session
  • 단, 여러 thread가 동시에 Session에 접근할 수 있는 경우 반드시 AnnotationMethodHandlerAdapter의 synchronizeOnSession 속성을 true로 설정해야만 위와 같은 결과를 얻을 수 있다.
  • <bean id="annotationHandlerAdaptor"
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="synchronizeOnSession" value="true" />
    </bean>

Resources