blob: 8c3ac9d5301d6d070652fbe96e6c7671c3295316 [file] [log] [blame]
<?xml version="1.0"?>
<!--
$Id$
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
// ======================================================================== 78
-->
<faqs title="Newbie FAQ">
<part id="general">
<faq id="chain">
<question>How do I load a custom chain config file?</question>
<answer>
<p>Use the <code>chainConfig</code> init param for
ActionServlet to specify a comma delimited list of
chain config files.
</p>
<p>This will override the default value of
<code>chainConfig</code>, so unless you are
overriding the default request processing chain, you
must include the default chain config file in the list.
</p>
<pre>
&lt;init-param>
&lt;param-name>chainConfig&lt;/param-name>
&lt;param-value>
org/apache/struts/chain/chain-config.xml,
/WEB-INF/custom-chain-config.xml
&lt;/param-value>
&lt;/init-param>
</pre>
<p>For another method of loading chain config files, see
<a href="http://jakarta.apache.org/commons/chain/cookbook.html#Load_a_Catalog_From_a_Web_Application">
Load a Catalog From a Web Application</a>
in the Commons Chain Cookbook.
</p>
</answer>
</faq>
<faq id="modules">
<question>What is a modular application? What does module-relative mean?</question>
<answer>
<p>
Since Struts 1.1, the framework supports multiple
application modules. All applications have at
least one root, or default, module. Like the root
directory in a file system, the default application
has no name. (Or is named with an empty string, depending
your viewpoint.) Developing an application
with only a default module is no different from how
applications were developed under Struts 1.0.
Since Struts 1.1, you can add additional modules to your
application, each of which can have their
own configuration files, messages resources, and so forth.
Each module is developed in the same way as
the default module. Applications that were developed as a
single module can added to a multiple
module application, and modules can promoted to a
standalone application without change. For more
about configuring your application to support multiple
modules, see
<a href="../userGuide/configuration.html#dd_config_modules">
Configuring Applications</a>
in the
User Guide.
</p>
<p>
But to answer the question =:0), a modular application is
an application that uses more than
one module. Module-relative means that the URI starts at
the module level, rather than at
the context level, or the absolute-URL level.
</p>
<ul>
<li>Absolute URL:
http://localhost/myApplication/myModule/myAction.do</li>
<li>context-relative: /myModule/myAction.do</li>
<li>module-relative: /myAction.do</li>
</ul>
<p>
The Struts Examples application is a modular application
that was assembled from several
applications that were created independently.
</p>
</answer>
</faq>
<faq id="naming">
<question>Why are some of the class and element names counter-intuitive?</question>
<answer>
<p>
The framework grew in the telling and, as it evolved, some
of the names
drifted.
</p>
<p>The good thing about a nightly build, is that everything
becomes
available to the community as soon as it is written. The
bad thing about
a nightly build is that things like class names get locked
down early and
then become difficult to change.
</p>
</answer>
</faq>
<faq id="actionForms">
<question>Whither ActionForms?</question>
<answer>
<p>
<a href="http://www.mail-archive.com/struts-user@jakarta.apache.org/msg19281.html">
http://www.mail-archive.com/struts-user@jakarta.apache.org/msg19281.html</a>
<br/>
<a href="http://www.mail-archive.com/struts-user@jakarta.apache.org/msg19338.html">
http://www.mail-archive.com/struts-user@jakarta.apache.org/msg19338.html</a>
<br/>
<a href="http://www.mail-archive.com/struts-user@jakarta.apache.org/msg20833.html">
http://www.mail-archive.com/struts-user@jakarta.apache.org/msg20833.html</a>
<br/>
</p>
</answer>
</faq>
<faq id="actionFormInterface">
<question>Why is ActionForm a base class rather than an interface?</question>
<answer>
<p>
Originally, the rationale as that making ActionForm a
class takes advantage of the single
inheritance restriction of Java to it makes it more
difficult for people to do
things that they should not do. At the time, EJBs were
becoming popular, and
most developers were trying to combine EJB remoting with
ActionForms,
and the result was not pretty.
</p>
<p>
Since then, most developers use different approaches to
data persistent,
and most developers now have a good understanding of why
we want to separate
the model from the view.
Accordingly, we do plan to introduce more interfaces into
the framework.
It's just a matter of when.
</p>
<p>
Meanwhile, DynaActionForms relieve developers of
maintaining simple ActionForms.
For near zero maintenance, try
<a href="../userGuide/building_controller.html#lazy_action_form_classes/">
LazyActionForm</a>
and Hubert Rabago's
<a href="https://formdef.dev.java.net/">FormDef.</a>
</p>
</answer>
</faq>
<faq id="JavaBeans">
<question>Do ActionForms have to be true JavaBeans?</question>
<answer>
<p>
The utilities that the framework uses (Commons-BeanUtils
since 1.1) require that ActionForm properties follow
the JavaBean patterns for mutators and accessors
(get*,set*,is*). Since the framework uses the
Introspection API
with the ActionForms, some containers may require that all
the JavaBean patterns be followed, including
declaring
<code>"implements Serializable"</code>
for each subclass. The safest thing is to review the
<a href="../userGuide/preface.html#javabeans">JavaBean
specification</a>
and follow all the prescribed patterns.
</p>
<p>
Since Struts 1.1, you can also use DynaActionForms and
mapped-backed forms, which are not true JavaBeans.
For more see
<a href="../userGuide/building_controller.html#action_form_classes">
ActionForm classes</a>
in the User Guide
and
<a href="#otherBeans">Using Hashmaps with ActionForms</a>
in this FAQ.
</p>
</answer>
</faq>
<faq id="otherBeans">
<question>Can I use other beans or hashmaps with ActionForms?</question>
<answer>
<p>
Yes. There are several ways that you can use other beans
or hashmaps with ActionForms.
</p>
<ul>
<li>
ActionForms can have other beans or hashmaps as
properties
</li>
<li>
"Value Beans" or "Data Transfer Objects" (DTOs) can be
used independently of
ActionForms to transfer data to the view
</li>
<li>
ActionForms can use Maps to support "dynamic"
properties (since Struts 1.1)
</li>
</ul>
<p>
ActionForms (a.k.a. "form beans") are really just JavaBeans
(with a few special methods) that the framework creates
and puts into session or request scope for you.
There is nothing preventing you from using other beans, or
including them in your form beans.
Let's look at some examples.
</p>
<p>
<em>Collections as properties</em>
Suppose that you need to display a pulldown list of
available colors on an input form in your application. You
can include a string-valued
<code>colorSelected</code>
property in your
<code>ActionForm</code>
to represent the user's
selection and a
<code>colorOptions</code>
property implemented as a
<code>Collection</code>
(of strings) to store the available color choices.
Assuming that you have defined the getters
and setters for the
<code>colorSelected</code>
and
<code>colorOptions</code>
properties
in your
<code>orderEntryForm</code>
form bean, you can render the
pulldown list using:
</p>
<source>
&lt;html:select property="colorSelected"&gt;
&lt;html:options property="colorOptions"
name="orderEntryForm"/&gt;
&lt;/html:select&gt;
</source>
<p>
The list will be populated using the strings in the
<code>colorOptions</code>
collection of the
<code>orderEntryForm</code>
and the value that the user selects
will go into the
<code>colorSelected</code>
property that gets posted to the subsequent
<code>Action</code>
. Note that we are assuming here that the
<code>colorOptions</code>
property of the
<code>orderEntryForm</code>
has already been set.
</p>
<p>
See
<a href="#prepopulate">How can I prepopulate a form?</a>
for instructions on how to set
form bean properties before rendering edit forms that
expect properties to be pre-set.
</p>
<p>
<em>Independent DTO</em>
An
<code>Action</code>
that retrieves a list of open orders (as an
<code>ArrayList</code>
of
<code>Order</code>
objects) can use a DTO independently of any
form bean to transfer search results to the view. First,
the Action's
<code>execute</code>
method performs the search and puts the DTO into the
request:
</p>
<source>
ArrayList results =
businessObject.executeSearch(searchParameters);
request.setAttribute("searchResults",results);
</source>
<p>
Then the view can iterate through the results using the
"searchResults" request key to
reference the DTO:
`</p>
<source>
&lt;logic:iterate id="order" name="searchResults"
type="com.foo.bar.Order"&gt;
&lt;tr&gt;&lt;td&gt;&lt;bean:write name="order"
property="orderNumber"/&gt;&lt;td&gt;
&lt;td&gt;..other properties...&lt;/td&gt;&lt;/tr&gt;
&lt;/logic:iterate&gt;
</source>
<p>
See also:
<a href="../userGuide/building_controller.html#map_action_form_classes">
Map-Backed ActionForms</a>
(since Struts 1.1)
</p>
</answer>
</faq>
<faq id="authenticate">
<question>How can I authenticate my users?</question>
<answer>
<p>
<a href="http://www.mail-archive.com/struts-user@jakarta.apache.org/msg24504.html">
http://www.mail-archive.com/struts-user@jakarta.apache.org/msg24504.html</a>
<br/>
<a href="http://www.mail-archive.com/struts-user@jakarta.apache.org/msg22949.html">
http://www.mail-archive.com/struts-user@jakarta.apache.org/msg22949.html</a>
</p>
</answer>
</faq>
<faq id="jsp">
<question>Do I have to use JSPs with my application?</question>
<answer>
<p>
The short answer to this question is: No, you are not
limited to
JavaServer Pages.
</p>
<p>
The longer answer is that you can use any type of
presentation technology
which can be returned by a web server or Java container.
The list includes but is not limited to:
</p>
<ul>
<li>
JavaServer Pages,
</li>
<li>
HTML pages,
</li>
<li>
WML files,
</li>
<li>
Java servlets,
</li>
<li>
Velocity templates, and
</li>
<li>
XML/XLST
</li>
</ul>
<p>
Some people even mix and match apparently unrelated
technologies,
like PHP, into the same web application.
</p>
</answer>
</faq>
<faq id="formbeans">
<question>Do ActionForms have to be true JavaBeans?</question>
<answer>
<p>ActionForms are added to a servlet scope (session or
request)
as beans. What this means is that, for certain
functionality to
be available, your ActionForms will have to follow a few
simple
rules.</p>
<p>First, your ActionForm bean must have a zero-arguments
constructor. This is required because the framework must
be able to
dynamically create new instances of your form bean class,
while
knowing only the class name. This is not an onerous
restriction,
however, because the framework will also populate your
form bean's
properties (from the request parameters) for you.</p>
<p>Second, the fields of your form bean are made available to
the
framework by supplying public getter and setter methods
that
follow the naming design patterns described in the
JavaBeans
Specification. For most users, that means using the
following
idiom for each of your form bean's properties:</p>
<pre>
private {type} fieldName;
public {type} getFieldName() {
return (this.fieldName);
}
public void setFieldName({type} fieldName) {
this.fieldName = fieldName;
}
</pre>
<p>
<strong>NOTE</strong>
- you
<em>MUST</em>
obey the capitalization
conventions shown above for your ActionForm properties to
be recognized.
The property name in this example is "fieldName", and that
must also be
the name of the input field that corresponds to this
property. A bean
property may have a "getter" method and a "setter" method
(in a form bean,
it is typical to have both) whose name starts with "get"
or "set",
followed by the property name with the first character
capitalized.
(For boolean properties, it is also legal to use "is"
instead of "get"
as the prefix for the getter method.)
</p>
<p>Advanced JavaBeans users will know that you can tell the
system
you want to use different names for the getter and setter
methods, by
using a
<code>java.beans.BeanInfo</code>
class associated with your form
bean. Normally, however, it is much more convenient to
follow the
standard conventions.
</p>
<p>
<strong>WARNING</strong>
- developers might be tempted to use one of
the following techniques, but any of them will cause your
property not
to be recognized by the JavaBeans introspection
facilities, and therefore
cause your applications to misbehave:
</p>
<ul>
<li>
<em>Using getter and setter method names that do not
match</em>
- if you have a
<code>getFoo()</code>
method for your
getter, but a
<code>setBar()</code>
method for your setter, Java
will not recognize these methods as referring to the
same property.
Instead, the language will think you have a read-only
property named
"foo" and a write-only property named "bar".
</li>
<li>
<em>Using more than one setter method with the same
name</em>
- The Java language lets you "overload" methods, as
long
as the argument types are different. For example, you
could have a
<code>setStartDate(java.util.Date date)</code>
method and a
<code>setStartDate(String date)</code>
method in the same class, and
the compiled code would know which method to call
based on the
parameter type being passed. However, doing this for
form bean
properties will prevent Java from recognizing that you
have a
"startDate" property at all.
</li>
</ul>
<p>There are other rules to follow if you want other features
of your form beans to be exposed,
especially in terms of indexed attributes and mapped attributes.
Specific rules are covered in detail in other areas of
the documentation, in particular,
<a href="indexedprops.html">
Indexed Properties, Mapped Properties, and Indexed Tags.
</a></p>
<p>For a complete explanation of what a JavaBean is, and
everything it can do,
see the
<a href="http://java.sun.com/products/javabeans/docs/beans.101.pdf">
JavaBeans Specification (version 1.01).</a></p>
</answer>
</faq>
<faq id="separate">
<question>Do I have to have a separate ActionForm bean for every HTML form?</question>
<answer>
<p>This is an interesting question. As a newbie, it is a good
practice to create a new
<code>ActionForm</code>
for each action
sequence. You can use
<code>DynaActionForm</code>
s to help reduce
the effort required, or use the code generation facilities
of your IDE.
</p>
<p>Some issues to keep in mind regarding reuse of form beans
are as follows:</p>
<ul>
<li>
<em>Validation</em>
- You might need to use different
validation rules depending upon the action that is
currently
being executed.
</li>
<li>
<em>Persistence</em>
- Be careful that a form populated in
one action is not
<strong>unexpectedly</strong>
reused in a
different action. Multiple
<code>&lt;form-bean&gt;</code>
entries in
<code>struts-config.xml</code>
for the same
<code>ActionForm</code>
subclass can help (especially if you
store your form beans in session scope).
Alternatively,
storing form beans in request scope can avoid
unexpected
interactions (as well as reduce the memory footprint
of your
application, because no server-side objects will need
to be
saved in between requests.
</li>
<li>
<em>Checkboxes</em>
- If you do as recommended and reset
your boolean properties (for fields presented as
checkboxes),
and the page you are currently displaying does not
have a
checkbox for every boolean property on the form bean,
the
undisplayed boolean properties will always appear to
have a
<code>false</code>
value.
</li>
<li>
<em>Workflow</em>
- The most common need for form bean
reuse is workflow. Out of the box, the framework has
limited support
for workflow, but a common pattern is to use a single
form bean
with all of the properties for all of the pages of a
workflow.
You will need a good understanding of the
environment (
<code>ActionForm</code>
s,
<code>Action</code>
s,
etc.) prior to being able to put together a smooth
workflow
environment using a single form bean.
</li>
</ul>
<p>As you get more comfortable, there are a few shortcuts you
can
take in order to reuse your
<code>ActionForm</code>
beans. Most of
these shortcuts depend on how you have chosen to implement
your
<code>Action</code>
/
<code>ActionForm</code>
combinations.
</p>
</answer>
</faq>
<faq id="prepopulate">
<question>How can I prepopulate a form?</question>
<answer>
<p>The simplest way to prepopulate a form is to have an
<code>Action</code>
whose sole purpose is to populate an
<code>ActionForm</code>
and forward
to the servlet or JSP to render that form back to the
client. A separate
<code>Action</code>
would then be use to process the submitted form fields,
by declaring an instance of the same form bean name.
</p>
<p>The
<em>MailReader</em>
application, part of the Struts Applications
subrpoject, illustrates this design pattern nicely. Note
the following
definitions from the
<code>struts-config.xml</code>
file:
</p>
<pre>
...
&lt;form-beans&gt;
...
&lt;-- Registration form bean --&gt;
&lt;form-bean name="registrationForm"
type="org.apache.struts.webapp.example.RegistrationForm"/&gt;
...
&lt;/form-beans&gt;
...
&lt;action-mappings&gt;
...
&lt;-- Edit user registration --&gt;
&lt;action path="/editRegistration"
type="org.apache.struts.webapp.example.EditRegistrationAction"
name="registrationForm"
scope="request"
validate="false"/&gt;
...
&lt;-- Save user registration --&gt;
&lt;action path="/saveRegistration"
type="org.apache.struts.webapp.example.SaveRegistrationAction"
name="registrationForm"
input="registration"
scope="request"/&gt;
...
&lt;/action-mappings&gt;
</pre>
<p>Note the following features of this approach:</p>
<ul>
<li>Both the
<code>/editRegistration</code>
and
<code>/saveRegistration</code>
actions use the same form bean.
</li>
<li>When the
<code>/editRegistration</code>
action is entered, the
framework will have pre-created an empty form bean
instance, and passed it to
the
<code>execute()</code>
method. The setup action is free to
preconfigure the values that will be displayed when
the form is
rendered, simply by setting the corresponding form
bean properties.
</li>
<li>When the setup action completes configuring the
properties of the
form bean, it should return an
<code>ActionForm</code>
that points
at the page which will display this form. If you are
using the
Struts JSP tag library, the
<code>action</code>
attribute on your
&lt;html:form&gt; tag will be set to
<code>/saveRegistration</code>
in order for the form to be submitted to the
processing action.
</li>
<li>Note that the setup action (
<code>/editRegistration</code>
) turns off
validation on the form that is being set up. You will
normally want
to include this attribute in the configuration of your
setup actions,
because you are not planning to actually process the
results -- you
simply want to take advantage of the fact that the
framework will precreate
a form bean instance of the correct class for you.
</li>
<li>The processing action (
<code>/saveRegistration</code>
), on the other
hand, leaves out the
<code>validate</code>
attribute, which defaults
to
<code>true</code>
. This tells the framework to perform the validations
associated with this form bean before invoking the
processing action
at all. If any validation errors have occurred, the
framework will forward
back to your input page (technically, it forwards back
to an
<code>ActionForward</code>
named "registration" in this case, because
the example webapp uses the
<code>inputForward</code>
attribute in the
<code>&lt;controller&gt;</code>
element -- see the documentation
describing
<code>struts-config.xml</code>
for more information)
instead of calling your processing action.
</li>
</ul>
</answer>
</faq>
<faq id="noForm">
<question>Can I have an Action without a form?</question>
<answer>
<p>
Yes. If your
<code>Action</code>
does not need any data and it does not need to make any
data available to the view or controller component that it
forwards to, it doesn't need
a form. A good example of an
<code>Action</code>
with no
<code>ActionForm</code>
is the
<code>LogoffAction</code>
in the Struts MailReader application:
</p>
<pre>
&lt;action path="/logoff"
type="org.apache.struts.webapp.example.LogoffAction"&gt;
&lt;forward name="success" path="/index.jsp"/&gt;
&lt;/action&gt;
</pre>
<p>
This action needs no data other than the user's session,
which it can get from the
<code>Request</code>
, and it doesn't need to prepare any view elements for
display,
so it does not need a form.
</p>
<p>
However, you cannot use the &lt;html:form&gt;
<strong>tag</strong>
without an ActionForm.
Even if you want to use the &lt;html:form&gt; tag with a
simple Action that does not require input,
the tag will expect you to use some type of ActionForm,
even if it is an empty subclass without any properties.
</p>
</answer>
</faq>
<faq id="requiredif">
<question>Can you give me a simple example of using the requiredif Validator rule?</question>
<answer>
<p>First off, there's an even newer Validator rule called
<code>validwhen</code>
,
which is almost certainly what you want to use, since it
is much easier and
more powerful. It will be available in the first release
after 1.1 ships.
The example shown below could be coded with validwhen as:
</p>
<pre>
&lt;form name="medicalStatusForm"&gt;
&lt;field
property="pregnancyTest" depends="validwhen"&gt;
&lt;arg0 key="medicalStatusForm.pregnancyTest.label"/&gt;
&lt;var&gt;
&lt;var-name&gt;test&lt;/var-name&gt;
&lt;var-value&gt;((((sex == 'm') OR (sex == 'M')) AND
(*this* == null)) OR (*this* != null))&lt;/test&gt;
&lt;/var&gt;
&lt;/field&gt;
</pre>
<p>Let's assume you have a medical information form with three
fields, sex, pregnancyTest, and testResult.
If sex is 'f' or 'F', pregnancyTest is required. If
pregnancyTest is not blank, testResult is required.
The entry in your validation.xml file would look like
this:
</p>
<pre>
&lt;form name="medicalStatusForm"&gt;
&lt;field
property="pregnancyTest" depends="requiredif"&gt;
&lt;arg0 key="medicalStatusForm.pregnancyTest.label"/&gt;
&lt;var&gt;
&lt;var-name&gt;field[0]&lt;/var-name&gt;
&lt;var-value&gt;sex&lt;/var-value&gt;
&lt;/var&gt;
&lt;var&gt;
&lt;var-name&gt;fieldTest[0]&lt;/var-name&gt;
&lt;var-value&gt;EQUAL&lt;/var-value&gt;
&lt;/var&gt;
&lt;var&gt;
&lt;var-name&gt;fieldValue[0]&lt;/var-name&gt;
&lt;var-value&gt;F&lt;/var-value&gt;
&lt;/var&gt;
&lt;var&gt;
&lt;var-name&gt;field[1]&lt;/var-name&gt;
&lt;var-value&gt;sex&lt;/var-value&gt;
&lt;/var&gt;
&lt;var&gt;
&lt;var-name&gt;fieldTest[1]&lt;/var-name&gt;
&lt;var-value&gt;EQUAL&lt;/var-value&gt;
&lt;/var&gt;
&lt;var&gt;
&lt;var-name&gt;fieldValue[1]&lt;/var-name&gt;
&lt;var-value&gt;f&lt;/var-value&gt;
&lt;/var&gt;
&lt;var&gt;
&lt;var-name&gt;fieldJoin&lt;/var-name&gt;
&lt;var-value&gt;OR&lt;/var-value&gt;
&lt;/var&gt;
&lt;/field&gt;
&lt;field
property="testResult" depends="requiredif"&gt;
&lt;arg0 key="medicalStatusForm.testResult.label"/&gt;
&lt;var&gt;
&lt;var-name&gt;field[0]&lt;/var-name&gt;
&lt;var-value&gt;pregnancyTest&lt;/var-value&gt;
&lt;/var&gt;
&lt;var&gt;
&lt;var-name&gt;fieldTest[0]&lt;/var-name&gt;
&lt;var-value&gt;NOTNULL&lt;/var-value&gt;
&lt;/var&gt;
&lt;/field&gt;
&lt;/form&gt;
</pre>
</answer>
</faq>
<faq id="validate">
<question>When is the best time to validate input?</question>
<answer>
<p>
This is an excellent question. Let's step back a second
and think about a
typical mid to large size application. If we start from
the back end and work
toward the view we have:
</p>
<p>
1) Database: Most modern databases are going to validate
for required
fields, duplicate records, security constraints, etc.</p>
<p>
2) Business Logic: Here you are going to check for valid
data relationships
and things that make sense for the particular problem you
are triing to
solve.</p>
<p>
... This is where the framework comes into the picture, by
now the system should be
pretty well bulletproof. What we are going to do is make
validation friendlier
and informative. Rember it is OK to have duplicate
validations...</p>
<p>
3)
<code>ActionErrors validate(ActionMapping map,
HttpServletRequest req)</code>
is where you can do your validation and feed back to the
view,
information required to correct any errors.
<code>validate</code>
is run after
the form has been
<code>reset</code>
and after the
<code>ActionForm</code>
properties have been set from corresponding view based
input. Also remember you
can turn validation off with
<code>validate="false"</code>
in the
<code>action</code>
mapping in the
<code>struts-config.xml</code>
. This is done
by returning an
<code>ActionErrors</code>
collection with messages from your
<code>ApplicationResources.properties</code>
file.
</p>
<p>
Here you have access to the request so you can see what
kinds of action is
being requested to fine tune your validations. The &lt;html:error&gt;
tag
allows you to dump all errors on your page or a particular
error associated
with a particular property. The
<code>input</code>
attribute of the
<code>struts-config.xml</code>
<code>action</code>
allows you to send
validation errors to a particular jsp / html / tile page.
</p>
<p>
4) You can have the system perform low level validations
and client side
feedback using a
<code>ValidatorForm</code>
or its derivatives. This will
generate javascript and give instant feedback to the user
for simple data entry
errors. You code your validations in the
<code>validator-rules.xml</code>
file. A working knowledge of
<a href="http://etext.lib.virginia.edu/helpsheets/regex.html">
regular
expressions</a>
is necessary to use this feature effectively. For more
information, see
<a href="../userGuide/dev_validator.html">
User Guide</a>
</p>
</answer>
</faq>
<faq id="avoidValidate">
<question>How can I avoid validating a form before data is entered?"</question>
<answer>
<p>
The simplest way is to have two actions. The first one has
the job of setting
the form data, i.e. a blank registration screen. The
second action in our
writes the registration data to the database. The
framework
would take care of invoking the validation and returning
the user to the
correct screen if validation was not complete.
</p>
<p>
The EditRegistration action in the Struts MailReader
application illustrates this:
</p>
<source>
&lt;action path="/editRegistration"
type="org.apache.struts.webapp.example.EditRegistrationAction"
attribute="registrationForm"
scope="request"
validate="false"&gt;
&lt;forward name="success path="/registration.jsp"/&gt;
&lt;/action&gt;
</source>
<p>
When the /editRegistration action is invoked, a
registrationForm is created and added to the request,
but its validate method is not called. The default value
of the
<code>validate</code>
attribute is
<code>true</code>
, so if you do not want an action to trigger form
validation, you need to remember
to add this attribute and set it to
<code>false</code>
.
</p>
</answer>
</faq>
<faq id="wizard">
<question>How can I create a wizard workflow?</question>
<answer>
<p>
The basic idea is a series of actions with next, back,
cancel
and finish actions with a common bean. Using a
LookupDispatchAction is
reccomended as it fits the design pattern well and can be
internationalized
easily. Since the bean is shared, each choice made will
add data to the
wizards base of information. A sample of struts-config.xml
follows:
</p>
<source>
&lt;form-beans&gt;
&lt;form-bean name="MyWizard"
type="forms.MyWizard" /&gt;
&lt;/form-beans&gt;
&lt;!-- the first screen of the wizard (next action only
available) --&gt;
&lt;!-- no validation, since the finish action is not
available --&gt;
&lt;actions&gt;
&lt;action path="/mywizard1"
type="actions.MyWizard"
name="MyWizard"
validate="false"
input="/WEB-INF/jsp/mywizard1.jsp"&gt;
&lt;forward name="next"
path="/WEB-INF/jsp/mywizard2.jsp" /&gt;
&lt;forward name="cancel"
path="/WEB-INF/jsp/mywizardcancel.jsp" /&gt;
&lt;/action&gt;
&lt;!-- the second screen of the wizard (back, next and
finish) --&gt;
&lt;!-- since finish action is available, bean should
validated, note
validation should not necessarily validate if back action
requested, you
might delay validation or do conditional validation --&gt;
&lt;action path="/mywizard2"
type="actions.MyWizard"
name="MyWizard"
validate="true"
input="/WEB-INF/jsp/mywizard2.jsp"&gt;
&lt;forward name="back"
path="/WEB-INF/jsp/mywizard1.jsp" /&gt;
&lt;forward name="next"
path="/WEB-INF/jsp/mywizard3.jsp" /&gt;
&lt;forward name="finish"
path="/WEB-INF/jsp/mywizarddone.jsp" /&gt;
&lt;forward name="cancel"
path="/WEB-INF/jsp/mywizardcancel.jsp" /&gt;
&lt;/action&gt;
&lt;!-- the last screen of the wizard (back, finish and
cancel only) --&gt;
&lt;action path="/mywizard3"
type="actions.MyWizard"
name="MyWizard"
validate="true"
input="/WEB-INF/jsp/mywizard3.jsp"&gt;
&lt;forward name="back"
path="/WEB-INF/jsp/mywizard2.jsp" /&gt;
&lt;forward name="finish"
path="/WEB-INF/jsp/mywizarddone.jsp" /&gt;
&lt;forward name="cancel"
path="/WEB-INF/jsp/mywizardcancel.jsp" /&gt;
&lt;/action&gt;
</source>
<p>
The pieces of the wizard are as follows:
</p>
<p>
<strong>forms.MyWizard.java</strong>
- the form bean holding the information required
</p>
<p>
<strong>actions.MyWizard.java</strong>
- the actions of the wizard, note the use of
LookupDispatchAction allows for one action class with
several methods. All the
real work will be done in the 'finish' method.
</p>
<p>
<strong>mywizard[x].jsp</strong>
- the data collection jsp's
</p>
<p>
<strong>mywizarddone.jsp</strong>
- the 'success' page
</p>
<p>
<strong>mywizardcancel.jsp</strong>
- the 'cancel' page
</p>
</answer>
</faq>
<faq id="chaining">
<question>How can I 'chain' Actions?</question>
<answer>
<p>
Chaining actions can be done by simply using the proper
mapping in your
forward entries in the struts-config.xml file. Assume you
had the following
two classes:
</p>
<source><![CDATA[
/* com/AAction.java */
...
public class AAction extends Action
{
public ActionForward
execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws
Exception
{
// Do something
return mapping.findForward("success");
}
}
]]></source>
<source><![CDATA[
/* com/BAction.java */
...
public class BAction extends Action
{
public ActionForward
execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws
Exception
{
// Do something else
return mapping.findForward("success");
}
}
]]></source>
<p>
Then you can chain together these two actions with the
Struts
configuration as shown in the following excerpt:
</p>
<source><![CDATA[
...
<action-mappings type="org.apache.struts.action.ActionMapping">
<action path="/A"
type="com.AAction"
validate="false">
<forward name="success" path="/B.do" />
</action>
<action path="/B"
type="com.BAction"
scope="session"
validate="false">
<forward name="success" path="/result.jsp" />
</action>
</action-mappings>
...
]]></source>
<p>
Here we are assuming you are using a suffix-based (
<code>.do</code>
) servlet
mapping, which is recommended since module support
requires it. When you
send your browser to the web application and name the
action
<code>A.do</code>
(i.e.
<code>http://localhost:8080/app/A.do</code>
) it will
execute
<code>AAction.execute()</code>
, which will then forward to the
"success" mapping.
</p>
<p>
This causes the execution of
<code>BAction.execute()</code>
since the
<code>&lt;forward&gt;</code>
entry for "success" in the configuration file
uses the
<code>.do</code>
suffix.
</p>
<p>
Of course it is also possible to chain actions
programmatically, but the
power and ease of being able to "reroute" your web
application's structure
using the XML configuration file is much easier to
maintain.
</p>
<p>
As a rule, chaining Actions is
<strong>not</strong>
recommended.
If your business classes are properly factored, you should
be able to call
whatever methods you need from any Action, without
splicing them together
into a cybernetic Rube Goldberg device.
</p>
<p>
If you must chain Actions, be aware of the following:
calling the second Action from the first Action has the
same effect as calling the second
Action from scratch.
If both of your Actions change the properties of a
formbean,
the changes made by the first Action will be lost because
the framework calls the reset() method on
the formbean when the second Action is called.
</p>
</answer>
</faq>
<faq id="undocumented">
<question>If you would like to contribute, here is a list of popular but undocumented questions</question>
<answer>
<ul>
<li>How can I capture binary or formatted values, like
dates or telephone numbers?</li>
<li>Can I create dynamic ActionForwards?</li>
<li>How can I use my own (ActionForm, ActionForward,
ActionMapping, ActionServlet) class?</li>
</ul>
</answer>
</faq>
</part>
</faqs>