Prevent resubmit on refresh in Struts 1

4k Views Asked by At

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>
2

There are 2 best solutions below

1
Mohammad Faisal On BEST ANSWER

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;
    }
}
9
Roman C On

In applyWaiver() on successful saving values I'm resetting the form fields and forwarding it to the same page.

This is a problem, because after submitting you should redirect to an action that would show you a page. In the action you can also populate a form bean if it's not a session scoped. So, in the code use the forward that redirect to the action

public ActionForward applyWaiver( final ActionMapping inMapping,
                                  final ActionForm inForm,
                                  final HttpServletRequest inRequest,
                                  final HttpServletResponse inResponse )
{
    ...

    if (! errors.isEmpty() )
    {
        errors.add( IAppConstants.APP_ERROR, new ActionMessage( "error.msg.key" ) ;

        // resetting the form fields
        qrcForm.setCustWaiverPojo( new CrmCustWaiverPojo() );
        qrcForm.setRemarksPojo( new RemarksPojo() );
        qrcForm.setSrTicketNo( null );

        saveErrors( inRequest, errors );
        saveMessages( inRequest, messages );
        return inMapping.findForward( forward );
    }

    MessageResources mr = (MessageResources) inRequest.getAttribute(Globals.MESSAGES_KEY);
    // saving data to database
    if ( success )
        inRequest.setAttribute( IAppConstants.APP_MESSAGE, mr.getMessage( "success.msg.key" ) );
    else
        inRequest.setAttribute( IAppConstants.APP_MESSAGE, mr.getMessage( "error.msg.key" ) );

    return new ActionForward(inMapping.findForward( forward ).getPath(), true ); //true is for redirect 
}