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 "DataEntryForm" by MichaelJouravlev
Date Sat, 18 Feb 2006 05:31:03 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/DataEntryForm

------------------------------------------------------------------------------
  
  == Setup/submit pattern ==
  
- In general, an interactive web application can operate in two phases. On input phase (or
accept phase) a browser sends user input to a web resource, usually by submitting an HTML
form. On output phase (or render phase) web resource displays a view matching its state.
+ An interactive web application can operate in two phases. On ''render phase'' (or output
phase) browser requests a web resource from the server, and web resource displays a page matching
its state. On ''accept phase'' (or submit phase) browser sends user input to a web resource,
usually by submitting an HTML form. 
  
- Struts exploits this idea using two types of actions: 
+ Struts exploits this idea utilizing ''setup/submit pattern'' and two types of actions: 
-  * setup action (pre-action, output action, render action) is used to prepare output data
before displaying a JSP page;
+  * ''setup action'' (pre-action, output action, render action) is used to prepare output
data before displaying a JSP page;
-  * submit action (post-action, input action, accept action) is used to accept user input.
+  * ''submit action'' (post-action, input action, accept action) is used to accept user input.
  
  Setup/submit action pattern is a standard practice for building interactive application
with Struts.
  
- It is common to have several actions of either type for a web resource. For example, if
you deal with Customer resource, you are likely to define two setup actions: viewCustomer.do
and editCustomer.do and three submit actions: addCustomer.do, updateCustomer.do and deleteCustomer.do.

+ It is common to have several actions of either type for a web resource. For example, if
you deal with {{{Customer}}} web resource, you are likely to define two setup actions: {{{viewCustomer.do}}}
and {{{editCustomer.do}}} and three submit actions: {{{addCustomer.do}}}, {{{updateCustomer.do}}}
and {{{deleteCustomer.do}}}. 
  
- Setup actions load data from database and queue it into one or more arbitrary objects located
in the request or session scope. Submit actions process input data and redisplay the same
data entry form if errors has been found in the input. If input does not contain errors, submit
actions accept it and forward to a success page. Success page often corresponds to a logically
different web resource.
+ inline:setup_submit_01.gif
  
- This approach has its issues, though:
+ Setup action loads data from database and queue it into one or more arbitrary objects located
in the request or session scope. Submit action processes input data and redisplays the same
data entry form if errors has been found in the input. If input does not contain errors, submit
action accepts it and forwards to a success page. 
+ 
+ This approach is far from perfect:
+  * classic setup/submit pattern is focused on a JSP page, not on a web resource in general.
+  * Every page of a web resource is likely to have its own pair of setup and submit actions.
-  * One web resource is defined with several action mappings in the struts-config.xml file
as well as with several Java classes.
+  * One web resource is defined with several action mappings in the {{{struts-config.xml}}}
file as well as with several Java classes.
-  * Output data is scattered in an uncontrolled manner throughout request and session scope
+  * Output data is scattered in an uncontrolled manner throughout request and session scope.
   * In case of error the data entry form is redisplayed by a submit action; that opens a
whole can of worms:
-   * If input data is invalid and autovalidation is turned on, submit action is never get
called and cannot affect the workflow.
+   * If input data is invalid and autovalidation is turned on, a submit action class is never
get called and cannot affect the workflow.
    * One page is represented with two different URLs in the browser.
-   * An attempt to refresh a page after it has been submitted and then redisplayed, causes
double submit.
+   * An attempt to refresh a page after it has been redisplayed causes double submit.
-  * Submit action that forwards to a success page corresponding to another web resource leads
to a spaghetti code both in Java code as well as in struts-config.xml file.
+  * Success page often corresponds to a logically different web resource, this leads to a
spaghetti code both in Java code as well as in {{{struts-config.xml}}} file.
  
- The remainder of this page shows how to improve classic Setup/Submit pattern step by step.
+ The remainder of this page shows the ways to improve classic Setup/Submit pattern.
  
  == Step 1: Share one ActionForm as input/output buffer ==
  
@@ -43, +47 @@

   * When HTML form is submitted, the !ActionForm is populated automatically by Struts with
values from the request.
   * If input is invalid, data entry form is redisplayed; it will have contained data submitted
by a user on a previous step.
  
- Therefore, instead of queueing output data to arbitrary objects in request or session scope,
a setup action has to use an !ActionForm as the holder of input/output data. Mappings of both
setup action and submit action should refer to the same !ActionForm in their "name" attribute.
+ Therefore, instead of queueing output data to arbitrary objects in request or session scope,
a setup action has to use an !ActionForm as the holder of input/output data. Mappings of both
setup action and submit action would refer to the same !ActionForm in their "name" attribute.
+ 
+ inline:setup_submit_02.gif
  
  Shared !ActionForm makes it easy to preserve incremental changes made by a user in a data
entry form.
  
  == Step 2: Do not forward to a page that does not belong to current web resource ==
  
- A submit action should not forward to a success page belonging to another logical web resource.
Instead, it should forward (or even better, redirect) to a setup action of the success page.
This allows to break a convoluted M:M relationship between actions and pages down to simple
and observable 1:M relationship. That is, several pages should correspond to one web resource.
Not vice versa!
+ A submit action should not forward to a success page belonging to another logical web resource.
Instead, it should forward (or even better, redirect) to a setup action of the success page.
This allows to break a convoluted M:M relationship between actions and pages down to simple
and observable 1:M relationship. That is, several pages should correspond to one web resource,
not the opposite!
  
- Another benefit of transferring to a setup action is that now you don't care about what
will be displayed on success page. You do not have to select a proper page and you do not
need to setup output data for that page. This is the business of the web resource you are
transferring to, this is what its setup action should do.
+ Another benefit of transferring to an action instead of a page is that you don't need to
care about what will be displayed on success page. You do not have to select a proper page
and you do not need to setup output data for that page. This is the business of the web resource
you are transferring to, this is what its setup action should do.
  
- With this simple change an application can now be broken into separate independent chunks.
There is no need to build inflexible "flow" from one page to another. Proper page is selected
and displayed by its respective setup action.
+ With this simple change an application can be broken into separate independent chunks. There
is no need to build inflexible "flow" from one page to another. Proper page is selected and
displayed by its respective setup action.
  
  == Step 3: Do not use autovalidation ==
  
  Turn autovalidation off and perform validation manually. This ensures your full control
over input data and over the workflow. With autovalidation turned off your action class will
always be called, so you can make a better decision what to do in case of error, whether you
want to redisplay the same data entry form, shoud you transfer the control to another web
resource or maybe you need to modify your business object instead.
  
+ inline:setup_submit_03.gif
+ 
+ == Step 4: Reload setup action to redisplay a page ==
+ 
  Autovalidation is used together with "input" attribute of action mapping in struts-config.xml
file. If !ActionForm.valiadate returns non-empty error object during autovalidation, Struts
forwards to location defined in the "input" attribute. Usually, it is the same data entry
form that was just submitted. Therefore, the same form can be represented in the browser with
two different URLs: one URL when it is rendered by a setup action, and another URL when it
is redisplayed by a submit action. In most cases the browser is forwarded to the page, not
redirected, so an attempt to refresh a page after it has been redisplayed causes double submit.

  
  These are techniques worth considering when you need to redisplay data entry form:
   * Forward to data entry page from submit action, use Struts token feature to catch the
resubmit. This approach does not protect a user from an unfriendly POSTDATA message and it
does not help with two URLs situation. Use this approach if your !ActionForm is request-scoped
and you want to reuse data entered by a user.
+  * Forward to a setup action (not directly to a page) to better separate your input and
output code. This approach ensures that each of your action classes perfoms only the tasks
in is intended to perform: submit action should not render a page.
   * Redirect to a setup action (not directly to a page) appending a business object ID and
another relevant information to the target URL. This approach eliminates resubmit on page
refresh, and it solves dual URLs issue. Use this option if you want to provide the better
and cleaner user experience but you don't want to use session-scoped !ActionForms. Your setup
action must be able to initialize the !ActionForm using ID and another request parameters
that you have sent in redirected request. If your data entry form is quite large, sending
all information in a redirected request may not be feasible.
   * Redirect to a setup action (not directly to a page), keeping data entered by a user in
a session-scoped !ActionForm. This approach is user-friendly, it  eliminates resubmit on page
refresh, solves dual URLs issue and provides a clean redirected URL. The only downside of
it is keeping !ActionForm in the session between requests; this may not be desirable for some
applications.
  
+ These techniques (except the first one) can be commonly called as ''action reloading'',
because a page is redisplayed using the same approach, as for initial display. Using redirection
instead of forwarding protects from implicit double submit and hides the submit URL from the
browser and from the user. This way a page is visible and accessible only from one URL, the
setup (render) URL.
+ 
+ inline:setup_submit_04.gif
+ 
- == Step 4: initialise ActionForm manually in setup action ==
+ == Step 5: Initialize ActionForm manually in setup action ==
  
  !ActionForm should be populated only on submit phase. To protect !ActionForm from unintended
modification by setup action, do not set "name" attribute in setup action mapping. This will
prevent Struts from instantiating and populating the !ActionForm. To setup !ActionForm data
you need to instantiate it yourself and to put in into appropriate scope, either into request
or into session. You will also have to refer to the !ActionForm explicitly using "name" attribute
of your input elements.
  
- == Step 5: consolidate your actions; use one of the DispatchAction flavors ==
+ == Step 6: Consolidate your actions; use DispatchAction flavor for submit action ==
  
  A simple web resource like Customer can have couple of setup action mappings like viewCustomer.do
and editCustomer.do and several submit action mappings like addCustomer.do, updateCustomer.do
and deleteCustomer.do.  Of course, this does not mean that you need to define five corresponding
Java classes. It would be great if you could reduce number of action classes down to two:
one setup action and one submit action per web resource. It would be also great to reduce
number of action mappings in struts-config.xml file.
  
@@ -83, +98 @@

  
  Therefore I recommend using !ParameterMappingDispatchAction as your entry point to a web
resource. You would define all event handlers in the "parameter" attrubute of action mapping,
including default method name. Then, on the data entry form, you would set "name" attributes
of various submit buttons to corresponding event name, like "edit", "view" or "delete".
  
- == Step 6: Reduce number of actions down to one ==
+ == Step 7: Reduce number of actions down to one ==
  
  !ParameterMappingDispatchAction mentioned in the previous section, is pretty smart. It can
detect the logical type of request that it receives: is it a render request or submit request.
It does this by looking for event in the request. 
  
@@ -91, +106 @@

  
  If !ParameterMappingDispatchAction cannot find event in the request, it calls default method.
This is a render phase, so you can prepare the !ActionForm and render a page.
  
+ inline:setup_submit_05.gif
+ 
  As you can see from the picture, the whole web resource is now controlled with only one
action class and has only one URL. Neat! A web resource can have several JSP pages corresponding
to it, so you can choose a proper one depending on the incoming event and on the state of
the resource. For example, if you create a login component, you may decide to have two pages:
Login and Logout, and you can display either one depending on user login status.
  
  Remember, the primary object in a web application is a web resource, not a page. A page
is just a view; one web resource can have several views. Do not build application around pages,
build it around web resources. In Struts, web resources are represented with Action and !ActionForm
classes.

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


Mime
View raw message