Search code examples
javastrutsstruts-1double-submit-problem

Prevent resubmit on refresh in Struts 1


I have gone through the answers with same problem but isn't there any default way in Struts to prevent resubmission? Also, in my case if I do reset the form fields it still save the old values (but how do it getting those values)?

I have an dispatch action class as:

public class QrcAction extends DispatchAction
{
    public ActionForward waiverPage( final ActionMapping inMapping,
                                     final ActionForm inForm,
                                     final HttpServletRequest inRequest,
                                     final HttpServletResponse inResponse )
    {
        QrcForm qrcForm = (QrcForm) inForm;
        if ( StringUtils.isEmpty( qrcForm.getCustomerId() ) )
        {
            ActionMessages errors = getErrors( inRequest );
            errors.add( IAppConstants.APP_ERROR, new ActionMessage( IPropertiesConstant.ERROR_INVALID_CUSTOMER_ID ) );
            saveErrors( inRequest, errors );
            return inMapping.findForward( IActionForwardConstant.QRC_SEARCH_CUSTOMER_PAGE );
        }
        qrcForm.setCustWaiverPojo( new CrmCustWaiverPojo() );
        qrcForm.setRemarksPojo( new RemarksPojo() );
        return inMapping.findForward( IActionForwardConstant.WAIVER_PAGE );
    }

    public ActionForward applyWaiver( final ActionMapping inMapping,
                                      final ActionForm inForm,
                                      final HttpServletRequest inRequest,
                                      final HttpServletResponse inResponse )
    {
        String forward = IActionForwardConstant.WAIVER_PAGE;
        QrcForm qrcForm = (QrcForm) inForm;
        ActionMessages messages = getMessages( inRequest );
        ActionMessages errors = getErrors( inRequest );
        CrmuserDetailsDto userDto = (CrmuserDetailsDto) inRequest.getSession( false )
                .getAttribute( IAppConstants.CRM_USER_OBJECT );
        
        double waiverLimit = 0;
        if ( StringUtils.isNotEmpty( userDto.getWaiverLimitAmmount() ) )
            waiverLimit = Double.parseDouble( userDto.getWaiverLimitAmmount() );
        if ( waiverLimit < qrcForm.getCustWaiverPojo().getWaiverAmount().doubleValue() )
        {
            errors.add( IAppConstants.APP_ERROR, new ActionMessage( IPropertiesConstant.ERROR_INVALID_WAIVER_LIMIT,
                                                                    waiverLimit ) );
        }
        QrcFormHelper.validateWaiver( errors, qrcForm );  // validates pojo fields

        if ( errors.isEmpty() )
        {
            // saving data to database
            if ( success )
            {
                messages.add( IAppConstants.APP_MESSAGE, new ActionMessage( "success.msg.key" ) );
                // resetting the form fields
                qrcForm.setCustWaiverPojo( new CrmCustWaiverPojo() );
                qrcForm.setRemarksPojo( new RemarksPojo() );
                qrcForm.setSrTicketNo( null );
            }
            else
                errors.add( IAppConstants.APP_ERROR, new ActionMessage( "error.msg.key" ) );
        }
        saveErrors( inRequest, errors );
        saveMessages( inRequest, messages );
        return inMapping.findForward( forward );
    }
}

The waiverPage() is called to display the form and submitted to applyWaiver(). In applyWaiver() on successful saving values I'm resetting the form fields and forwarding it to the same page. After submit and success a message is display and the form is cleared and after that if I do refresh it again make entry in db with same previous values.
Could there be any solution to this problem?

Update
waiver.jsp

<html:form action="manageQrc.do?method=applyWaiver">
    <html:hidden property="custWaiverPojo.customerId" name="qrcForm" value="${ qrcForm.customerId }"/>
    <label class="label_radio"> 
        <html:radio property="custWaiverPojo.waiverType" value="Goodwill Wavier" name="qrcForm" styleClass="waiverType">Goodwill</html:radio>
    </label> 
    <label class="label_radio"> 
        <html:radio property="custWaiverPojo.waiverType" value="Process Wavier" name="qrcForm" styleClass="waiverType">Process</html:radio>
    </label>
    <strong> Select Category </strong> 
    <span class="LmsdropdownWithoutJs"> 
        <html:select property="custWaiverPojo.waiverHead" name="qrcForm" styleId="waiverHead">
            <html:option value="">Please Select</html:option> <!-- options are filled after radio button selection -->
      </html:select>
    </span>
    <strong>Amount</strong>
    <html:text property="custWaiverPojo.waiverAmount" name="qrcForm" styleClass="textbox" styleId="waiverAmount" maxlength="10"></html:text>
    <strong>Bill No. </strong> 
    <span class="LmsdropdownWithoutJs"> 
        <html:select property="custWaiverPojo.billNo" name="qrcForm" styleId="waiverBill">
            <html:option value="0">Please Select</html:option>
            <html:option value="20140101">20140101</html:option>
            <html:option value="20140201">20140201</html:option>
            <html:option value="20140301">20140301</html:option>
            <html:option value="20140401">20140401</html:option>
        </html:select>
    </span>
    <strong>Ticket ID</strong>
    <html:text property="srTicketNo" name="qrcForm" maxlength="20" styleClass="textbox" styleId="waiverSRT"></html:text>
    <strong> Remarks</strong>
    <html:textarea property="remarksPojo.remarks" name="qrcForm" styleClass="LmsRemarkstextarea" styleId="waiverRemarks"></html:textarea>
    <html:submit />
</html:form>

Solution

  • The solution in this blog uses token to identify the request as:

    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;
        }
    }