Wednesday, May 9, 2012

How to avoid Duplicate submission using Struts Token with code example


There are many scenarios where we face duplicate submission problem like,

  • Using Refresh button
  • Using browser back button traverse back and re-submitting the form
  • Using browser history feature and re-submit the form and so on
To avoid this problem Struts provide 'Struts Token' concept.

How does it work? 

  1. saveToken generates a unique token and saves it in the session under the key org.apache.struts.action.TOKEN. 
  2. When the form is rendered, the struts html:form tag generates a hidden field named org.apache.struts.action.TOKEN. 
  3. Upon form submission, isTokenValid compares the token stored in the session with that submitted from the form. If they are equal, return true. Otherwise, return false.
  4. resetToken removes the token stored in the session. 

Step by step procedure to implement using Token in struts,

Step 1 :
Save the token in session using 'saveToken()' method which is implemented in Action class.


public class EmployeeLoadAction extends Action{
private final static String SUCCESS = "success";
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
ActionForward forward;
forward = mapping.findForward(SUCCESS);
saveToken(request);
return forward;
}
}


Step 2 :
In JSP file. Here in this example employee.jsp
Store the token using Hidden variable in JSP file as shown below.
Don't forget to import Globals and Constants class inside JSP file to avoid Jasper Exception

TRANSACTION_TOKEN_KEY variable inside Action class is deprecated, so use it from Globlas class instead.

<%@ page import="org.apache.struts.Globals"%> 
<%@ page import="org.apache.struts.taglib.html.Constants"%> 
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<form name="employee" action="EmployeeSubmit.do" method="POST">
<input type="hidden" name="<%= Constants.TOKEN_KEY %>" 
value="<%= session.getAttribute(Globals.TRANSACTION_TOKEN_KEY) %>" > 
<TABLE>
<TR>
<TD>Name</TD>
<TD><input type="text" name="empName"></TD>
</TR>
<TR>
<TD>ID</TD>
<TD><input type="text" name="empId"></TD>
</TR>
<TR>
<TD colspan="2"><input type="submit" value="Submit"></TD>
</TR>
</TABLE>
</form>
</body>
</html>


Step 3 :

Now actual logic for duplicate submission inside EmployeeSubmit action class.
Method 'isTokenValid()' will validate the token and returns the boolean. 
Based on that we can decide whether form has re-submitted.


public class EmployeeSubmitAction extends Action{
private final static String SUCCESS = "success";
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
ActionForward forward;
forward = mapping.findForward(SUCCESS);
EmployeeSubmitForm frm = (EmployeeSubmitForm) form;
if (isTokenValid(request)) {
System.out.println("frm.getName() : " + frm.getEmpName());
resetToken(request);
} else {
System.out.println("frm.getName() : " + frm.getEmpName());
System.out.println("Duplicate Submission of the form");
}
return forward;
}
}