JSP 프로그래밍에서 페이지 이동 방법이 여러가지가 있습니다.
비지니스 로직 수행에서 redirect나 forward 아니면 해당 페이지에서 직접 redirect, forward, html, javascript 를 이용한 페이지 이동 등등..
그중에서 request.getRequestDispatcher("/view.jsp").forward(request, response) 를 사용하였을때 중복 저장 또는 중복 로직 수행에 대해서 알아 보려고 합니다.
forward를 사용하는 이유는 아래처럼 정리 할 수 있지만.. forward의 특징 중 하나가 이전페이지의 객체를 보존하고 있습니다.
'특정 페이지에서 전달된 데이터를 로직을 수행하고 수행된 결과(Object Data)를 원하는 페이지에 전달 후 보여주려고 한다.'
예로
'사용자가 입력 페이지의 폼에서 저장버튼 클릭 -> 저장 로직 수행 후 DB 입력 -> 리스트 페이지 이동'
을 하였을 경우 이동한 리스트 페이지에서 F5키 나 새로고침을 하였을 경우 위의 로직을 다시 타는 경우가 발생합니다.
만약 DB의 PK 설정이 oracle의 sequence나 mssql의 시드를 이용한 자동 증가가 아닐 경우 PK 값 위반에 대한 Exception 이 일어 날 것이며 PK 가 없다면 같은 데이터가 중복 저장되는 경우가 생깁니다.
그래서 double submit을 막아 보려고 구글링 등등 이것저것 찾아 보았는데
Spring의 경우 SessionStatus, Struts의 Token, Post - Redirect- Get 패턴 등등 ;;
이미 프로젝트가 막바지라 급하게 손쓸 방법을 찾다가 쉽게 쓸수 있을 것 같아 적용해 보았는데 성공하여 포스트 합니다;;
http://blog.naver.com/PostView.nhn?blogId=canya83&logNo=40094442229&parentCategoryNo=15&viewDate=¤tPage=1&listtype=0
## 원리 ::
1. 최초 페이지(Token 없음) : jsp에서 Token을 생성 ( T1 생성)
2. 서버의 컨트롤러에서 JSP에서 생성된 Token이 컨트롤러의 Token과 같을 경우 신규 요청으로 설정
(T1 == T2 으면 Token 생성)
3. 비지니스 로직 처리 후 특정 페이지로 이동하여 새로고침 ( T1 != T2)
4. 서버의 컨트롤러에서 이전 JSP에서 생성된 Token이 컨트롤러의 Token과 다르므로 Token 생성 안함
(T1 != T2 ) 해당 요청에 대해서는 비지니스 로직을 수행 안함.
## 코드
1. 공통 Controller에서 사용할 Token.java 를 하나 만들자!
import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import javax.servlet.http.HttpServletRequest; public class Token { |
2. HttpServlet 을 재구현한 공통 컨트롤러의 forward 부분에 아래와 같이 추가 한다.
if(Token.isValid(request)) { Token.set(request); request.setAttribute("TOKEN_SAVE_CHECK", "TRUE"); } else { request.setAttribute("TOKEN_SAVE_CHECK", "FALSE"); } |
3. 중복 저장을 막고자하는 JSP 페이지 아래와 같이 추가 한다.
<% if(request.getAttribute("TOKEN_KEY")==null) Token.set(request); %> <input type="hidden" name="TOKEN_KEY" value="<%=request.getAttribute("TOKEN_KEY")%>"/> |
4. business logic을 수행하는 부분에서 CRUD 등등 처리 부분의 처음 부분에 아래와 같이 추가한다.
if("TRUE".equals(request.getAttribute("TOKEN_SAVE_CHECK"))) { // 신규 요청이므로 원하는 로직 작성 } else { // 중복 요청이므로 그에 따른 로직 작성 } |
5. 테스트!