struts-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Apache Wiki <wikidi...@apache.org>
Subject [Struts Wiki] Update of "StrutsCatalogActionForms" by MichaelJouravlev
Date Fri, 17 Feb 2006 00:16:12 GMT
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


Mime
View raw message