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>
Roman C
  • 49,761
  • 33
  • 66
  • 176
Mohammad Faisal
  • 5,783
  • 15
  • 70
  • 117

2 Answers2

1

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 
}
Roman C
  • 49,761
  • 33
  • 66
  • 176
  • Post the JSP that has a form is submitted. – Roman C Oct 31 '14 at 12:33
  • Do you use any reset method on action form? What is the code? – Roman C Oct 31 '14 at 13:07
  • in reset: `qrcForm.setCustWaiverPojo( new CrmCustWaiverPojo() ); qrcForm.setRemarksPojo( new RemarksPojo() ); qrcForm.setSrTicketNo( null );`. You might wonder why `qrcForm.____`? because the form is passes to a helper class. – Mohammad Faisal Oct 31 '14 at 13:09
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/64029/discussion-between-mohammad-faisal-and-roman-c). – Mohammad Faisal Oct 31 '14 at 14:04
  • why you had added that comment? The discussion chat comment was from Oct 2014 and the accepted answer was posted few days later. I posted the chat link maybe because I was unable to understand your reasoning at that time, and there would be many more questions to have clear and better understanding. – Mohammad Faisal Aug 30 '21 at 04:52
  • @MohammadFaisal Because you still don't understand why and which answer should be accepted. Firstly you asked this question and was looking for help, and after the help was provided you submitted your own solution. This behaviour is not appropriate and not aknolagable on SO. I have a huge amount of such answers. They all asking for help and after getting the help leave you alone without aknolage. This is disregard of help and how SO is worked. I think you don't understand this yet, that's why I posted a reminder for this answer. – Roman C Aug 30 '21 at 07:54
  • The approach you suggested is quite different the one I used at that time... and there could always be more than one possible solutions to a problem (to which I think you will also be agree). I accepted my own answer because that's what I had used in the project and not the one which you had suggested. So I don't think you need to force someone to accept your answer. Although, I am thankful of you to have given that approach which I could not have understood that time. Thanks again but I could not accept your answer even now. – Mohammad Faisal Aug 31 '21 at 02:35
  • And it is also depends on the future visitors to give a vote up if they find your solution helpful over mine... I think there are numerous unaccepted answers which have high votes than the one with accepted answer. I hope you understand me and in any way I am not trying to be rude. – Mohammad Faisal Aug 31 '21 at 02:37
  • @MohammadFaisal Next time if you post a question make sure you check the box for self-answering one. No one is interesting to provide his/her expertize without aknolage. I appreciate you are very thankful, but SO doesn't work like you think. – Roman C Aug 31 '21 at 10:25
1

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;
    }
}
Mohammad Faisal
  • 5,783
  • 15
  • 70
  • 117