You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by Apache Wiki <wi...@apache.org> on 2006/02/17 01:16:12 UTC

[Struts Wiki] Update of "StrutsCatalogActionForms" by MichaelJouravlev

Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Struts Wiki" for change notification.

The following page has been changed by MichaelJouravlev:
http://wiki.apache.org/struts/StrutsCatalogActionForms

The comment on the change is:
This is junk; bless wiki for being able to remove my articles.

------------------------------------------------------------------------------
- What are the possible choices for storing and accessing input and output data from an action class?
+ deleted
  
- === Not using action forms ===
- 
- This is the radical choice. Proponents of this choice do not see added value of action forms. They can obtain input data directly from the request object, and they can display information directly from the business object or another bean. They prefer to validate input data by explicitly calling the validator, or they have their own validation techniques.
- 
- Another reason for not using action forms is using presentation engine different from JSP. Quoting Don Brown: "My primary app uses stxx (http://stxx.sf.net) so without taglibs, there isn't much left to !ActionForms.  My forms are XML based, so I use commons-validator with custom XML validators, and JXPath to populate (treats the form element names as xpath expressions). My wizards that use Struts Flow use the same population and validation methods."
- 
- attachment:noform.gif
- 
- This approach is used by 22% of developers, who participated in the quick poll.
- 
- === Using action form for input only ===
- 
- Struts populates form bean with input data from the request. After input is processed and domain model is updated, output data is generated manually and pushed into request or session scope, either field by field or packaged into a bean. This approach makes sense if a page is rendered with non-JSP engine, too.
- 
- attachment:forminput.gif
- 
- Used by 11% of respondents.
- 
- === Using action form for output only ===
- 
- This is quite an exotic choice. To make this work, action form should not have any setters, since Struts uses setters to populate action form bean. 
- 
- attachment:formoutput.gif
- 
- No one who responded to the poll, uses this approach.
- 
- === Using same action form for both input and output data ===
- 
- This choice turned out to be quite popular, 50% usage out of all respondents. Here is an outline:
- 
-    * HTML FORM is submitted from the input page, usually using POST request method.
-    * Struts populates form bean with request data.
-    * Form bean validates input and if something wrong, it generates error messages.
-    * If validate() returns errors, Struts does not bother to call action class. Instead, it forwards to location, which is defined in "input" property of <action> element.
-    * If, on the other hand, input data is correct, Struts calls execute() method of the action class.
-    * execute() usually performs model update, then fills out form bean with output values, and forwards to JSP page, which displays output data.
- 
- attachment:forminputoutput.gif
- 
- === Using input form and output form ===
- 
- Action mapping does not allow to assign more than one action form to an action class declaratively. If you want to use action form for both input and output, but do not want to keep the data in the single form, then you can use two action classes, each with its own action form.
- 
- attachment:twoforms.gif
- 
- In this scheme each action class and form bean performs its own specific task.
- 
-    * Input form bean is populated with input data.
-    * Input Form bean validates input and if something wrong, it generates error messages.
-    * If validate() returns errors, Struts forwards to location, which is defined in "input" property of <action> element.
-    * If input data is correct, Struts calls execute() method of the input action class.
-    * Input action class forwards to output action mapping. This is basically a simple action chaining.
- 
- Struts will try to populate output form bean, but here is the trick: you do not need to define setters for properties in the output form. Also, the field on the output form usually differ from fields on the input form.
- 
- Now we have clean separation of input and output data, and each class is doing a small but specific task. About 17% of respondents use separate input and output form beans.
- 
- === Separating input phase from output phase ===
- 
- Separating data may be important for a web developer, but it is invisible for a browser. The only thing that browser knows, is that to obtain a certain page it has to issue a certain request. Putting it differently: each page has a unique location. What does it really mean?
- 
- When a browser submits data, it sends a request to the server. By default, when browser submits an HTML form, the request has POST type. Server application processes input data, updates domain objects, and responds with result page. From browser's point of view, the result page has an address, which is a combination of URL and browser input data. To reload the result page the browser needs to send to the server exactly the same address. Thus, when a user clicks Reload button, browser resends to the server information that has been already submitted.
- 
- HTTP specification distinguishes between POST and GET request types. GET should be used for requests, which do not produce side effects when repeated. POST should be used primarily for changing server state. Because of that, when the same POST is resent to the server, browser is obliged to ask a user for confirmation. Obviously, if application does not check for duplicate input data, the same server activity can be performed twice, say, a user credit card can be charged once again.
- 
- This situation is known as "postdata situation" or "double submit problem". Struts provides a special object, token, to detect that a particular request is resubmitted. While this helps to fight with the double submit, what if we can avoid double submits altogether?
- 
- To accomplish that, we need to ensure that when a user clicks Reload, browser does not send another POST request to the browser. That means that result page must have a different address. That, in turn, means that result page cannot be generated in response to POST request. Instead, it should be generated in response to GET request. This means, that we need to make two requests out of one, and the second response must have GET type.
- 
- Combining this information together, we can come up with a logical solution:
-    * Browser submits input data using POST request.
-    * Server application processes input data and updates domain model.
-    * Server redirects to the address of result page. Redirection codes 302 and 303 produce GET request. 302 code is automatically generated with Java !HttpServletResponse.sendRedirect method.
-    * Browser uses new address to load the result page.
- 
- Now, when a user clicks Reload button, browser uses address from GET request to reload a page. Thus, no input data is resubmitted to the server. Also, because this request has GET type, browser does not show warning dialog window.
- 
- === Remove "input" property and use redirect ===
- 
- Usually, when form bean is used for input, errors are forwarded to location, defined in "input" property. By default, "input" property does not allow redirection. Redirection can be enabled, but for the whole application. Because most applications forward to input page instead of redirecting, page is sent back to browser immediately in response to POST request. This results in POSTDATA situation when a user tries to reload input page afterwards.
- 
- So, as a first step of splitting one request into two I suggest either to get rid of "input" property and automatic validation, or to set controller property, that allows redirection for "input" location.
- 
- Then we need to use redirection instead of forwarding between the action mappings, and this is it! 
- 
- attachment:twoformsredirect.gif
- 
- Well, we are almost there, but not quite. Because now we need to find a place, where to store intermediate data and error messages between requests. This data can either be passed in the redirected request, or saved in the session. The choice is yours. I prefer to store most of the data in the session, and to pass only object ID as the request parameter. I will discuss the details of redirecting from POST to GET on a separate page.
- 
- === Dialog Action ===
- 
- What if we need to use one form? Say, we have a wizard or a dialog, which shares data between pages. No problem, just use one form bean with session scope instead of two, and it will retain all input data between requests. You can use one action class as well. To avoid endless loop, you need to check the request method. It it is POST, then you redirect to the same action mapping again. If it is GET, you display the result page.
- 
- attachment:twoformsdialog.gif
- 
- Separation between input and output phases using redirection provides freedom of browsing. Now we can reload result page without risking to resubmit input data. And we can go back and forward again without invoking POST requests.
- 
- == Comments ==
- 
-    * [http://www.mail-archive.com/user%40struts.apache.org/msg26454.html Thread on Struts user list] 
-    * This page was heavily updated since after the comments on Struts user list
- 
- == How do you use action forms (aka form beans)? ==
- 
- Please, cast your vote here: http://jmikus.freepolls.com/cgi-bin/polls/001/poll_center.htm
- 
- Please note, that employing "input" property and redisplaying input page with error message does not count as using form bean for output.
- 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org