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
  
+ ----
+ 
+ ==== 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: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to