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 2005/05/07 08:42:41 UTC

[Struts Wiki] Update of "StrutsMultipleActionForms" 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/StrutsMultipleActionForms

------------------------------------------------------------------------------
  
  Simon Matic Langford
  
- ----
+ See also StrutsCatalogInputOutputSeparation
  
- ==== Two actions, two forms ====
- 
- I found action chaining with redirection to be the best solution. Chaining allows to have more fine-grained actions which are less dependent on each other. Redirection allows to get rid of POSTDATA situation.
- 
- attachment:twoacttwoformsredir.gif
- 
- {{{
- <action path  = "/inputAction"
-   type  = "com.acme.struts.InputAction"
-   name  = "inputForm"
-   input = "/WEB-INF/jsp/inputError.jsp">
-   <forward name="OK" path="/outputAction.do" redirect="true"/>
- </action>
- 
- <action path  = "/outputAction"
-   type  = "com.acme.struts.OutputAction"
-   name  = "outputForm"
-   input = "/WEB-INF/jsp/outputError.jsp">
-   <forward name="OK" path="/WEB-INF/jsp/viewOutput.jsp"/>
- </action>
- }}}
- 
- This design can be used to handle input and output of web applications. The source action receives the request, the source form validates the input data. If input is valid, the control is redirected to output action. Output action loads output data into output form and forwards to JSP.
- 
- The control flow in detail:
- 
-    * Struts calls reset() on the input form bean (1)
-    * Struts populates the fields of input form bean using setters (2). Input form bean does not have to define the getters.
-    * Struts calls validate() on input form bean (3)
-    * If validate() returns non-empty !ActionErrors object, control is forwarded (or redirected) to an error page identified by "input" attribute of the action mapping (4a) Before returning, validate() needs to store error messages in the session-scoped object, so errors would be available in the output action.
-    * if validate() returns empty !ActionErrors object or null, Struts calls execute() method of the input action class (4b)
-    * execute() updates business and persistent objects.
-    * in most cases, execute() cannot simply redirect to a static URL defined in struts-config.file. Input action must tell output action which object to show. The object ID can be passed either through session-scoped object or as parameter of redirected request. If ID is passed as request parameter, then execute() creates new !ActionForward instance with modified URI of the target action, adding to it the ID of an object which must be displayed.
-    * When execute() returns "OK", Struts redirects to the output action (5)
-    * Struts does its usual reset()/populate/validate() sequence on output bean. Actually there is no populate phase, since request contains no data, except object ID, which is set in the output bean. And validate() has nothing to validate in the output form, so it returns null.
-    * execute() method of the action class locates business object, using ID passed with the request, and fills out the fields of the output form.
-    * output action returns "OK" and Struts displays the result page (8)
- 
- A great side effect of this solution is that output page can be reloaded without processing the request in input action again. This helps to prevent double submission of input data.
- 
- Choosing between passing object ID in redirected request or in the session
- Passing parameter through the session-scoped object is less flexible. First, if different form beans are used, this cannot be done through a form bean, thus ID would have to be stored in the session. Consequently, output action must know about this session parameter. On the other hand, if output action were called directly, the ID would be in the request. Thus, output action would have to check session first to verify if it was redirected to, and if not, read ID from the request. 
- 
- This is too complex for my tastes. Passing parameter in the redirected request makes output action simpler and universal, it just picks the parameter from the request and uses it. It does not know or care, how exactly it was called.
- 
- ==== Follows the example from a working CRUD application. ====
- 
- {{{
- <!--
-   Create Item. Creates new object with random ID, temporarily
-   saves it in the session, attaches item ID to redirected URL
-   and redirects to editing.
-   Input: none
-   validation: none
- -->
- <action path  = "/createItem"
-   type  = "com.superinterface.items.CreateItemAction"
-   validate = "false">
-   <forward name="itemCreated" path="/editItem.do" redirect="true"/>
- </action>
- 
- <!--
-   Edit Item. Presents new or existing item for editing.
-   Item is looked up by ID. 
-   Input: item id
-   validation: item must exist in the item list
- -->
- <action path  = "/editItem"
-   type  = "org.apache.struts.actions.ForwardAction"
-   name  = "itemFormOutput"
-   input = "itemError"
-   parameter = "/WEB-INF/items/editItem.jsp">
-   <forward name="itemError" path="/WEB-INF/items/error.jsp"/>
- </action>
- 
- <!--
-   Store Item. Persists item in the storage. If item has "New" status,
-   it is persisted, if item has "Stored" status, it is updated.
-   On success redirects to home page, on error returns to editing.
-   Input: item id, item value
-   validation: input form fields are validated
- -->
- <action path  = "/storeItem"
-   type  = "com.superinterface.items.StoreItemAction"
-   name  = "itemFormInput">
-   <forward name="itemStored" path="/itemList.do" redirect="true"/>
-   <forward name="storeError" path="/editItem.do" redirect="true"/>
- </action>
- }}}
- 
- Let's check out the output action first, editItem. Notice, that it does not care where it was called from and was it forwarded to or redirected to. All it knows, that it recieves object id in the ID property of its form bean. Well, I cheated a little, using the same form bean for input and for output in this case. 
- 
- If item is not found, action forward to error page. If a user reloads error page, editItem action would try to locate the item again, which does not change server state, but can improve situation if the item is found. On the other hand, it would be cleaner to use redirection to error page, so that database would not be bothered if error page is reloaded. If item is found, editItem shows it.
- 
- Updated item is submitted to storeItem action. It is an input action and uses form bean to collect browser data. If data is incorrect, errors are generated and saved in the session, then control is redirected back to output action, editItem, which redisplays the item along with the errors. If data is correct, item is stored in the database and control is redirected to the home page. Home page can be reloaded, this will not incur item resubmit.
- 
- createItem creates new item. This would be an input action, but it has no input parameters. It does not have output data either, since it redirects to editItem which is output action for createItem.
- 

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