| <?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> |
| <init-param> |
| <param-name>chainConfig</param-name> |
| <param-value> |
| org/apache/struts/chain/chain-config.xml, |
| /WEB-INF/custom-chain-config.xml |
| </param-value> |
| </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> |
| <html:select property="colorSelected"> |
| <html:options property="colorOptions" |
| name="orderEntryForm"/> |
| </html:select> |
| </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> |
| <logic:iterate id="order" name="searchResults" |
| type="com.foo.bar.Order"> |
| <tr><td><bean:write name="order" |
| property="orderNumber"/><td> |
| <td>..other properties...</td></tr> |
| </logic:iterate> |
| </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><form-bean></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> |
| ... |
| <form-beans> |
| ... |
| <-- Registration form bean --> |
| <form-bean name="registrationForm" |
| type="org.apache.struts.webapp.example.RegistrationForm"/> |
| ... |
| </form-beans> |
| ... |
| <action-mappings> |
| ... |
| <-- Edit user registration --> |
| <action path="/editRegistration" |
| type="org.apache.struts.webapp.example.EditRegistrationAction" |
| name="registrationForm" |
| scope="request" |
| validate="false"/> |
| ... |
| <-- Save user registration --> |
| <action path="/saveRegistration" |
| type="org.apache.struts.webapp.example.SaveRegistrationAction" |
| name="registrationForm" |
| input="registration" |
| scope="request"/> |
| ... |
| </action-mappings> |
| </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 |
| <html:form> 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><controller></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> |
| <action path="/logoff" |
| type="org.apache.struts.webapp.example.LogoffAction"> |
| <forward name="success" path="/index.jsp"/> |
| </action> |
| </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 <html:form> |
| <strong>tag</strong> |
| without an ActionForm. |
| Even if you want to use the <html:form> 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> |
| <form name="medicalStatusForm"> |
| |
| <field |
| property="pregnancyTest" depends="validwhen"> |
| <arg0 key="medicalStatusForm.pregnancyTest.label"/> |
| <var> |
| <var-name>test</var-name> |
| <var-value>((((sex == 'm') OR (sex == 'M')) AND |
| (*this* == null)) OR (*this* != null))</test> |
| </var> |
| </field> |
| </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> |
| <form name="medicalStatusForm"> |
| |
| <field |
| property="pregnancyTest" depends="requiredif"> |
| <arg0 key="medicalStatusForm.pregnancyTest.label"/> |
| <var> |
| <var-name>field[0]</var-name> |
| <var-value>sex</var-value> |
| </var> |
| <var> |
| <var-name>fieldTest[0]</var-name> |
| <var-value>EQUAL</var-value> |
| </var> |
| <var> |
| <var-name>fieldValue[0]</var-name> |
| <var-value>F</var-value> |
| </var> |
| <var> |
| <var-name>field[1]</var-name> |
| <var-value>sex</var-value> |
| </var> |
| <var> |
| <var-name>fieldTest[1]</var-name> |
| <var-value>EQUAL</var-value> |
| </var> |
| <var> |
| <var-name>fieldValue[1]</var-name> |
| <var-value>f</var-value> |
| </var> |
| <var> |
| <var-name>fieldJoin</var-name> |
| <var-value>OR</var-value> |
| </var> |
| </field> |
| |
| <field |
| property="testResult" depends="requiredif"> |
| <arg0 key="medicalStatusForm.testResult.label"/> |
| <var> |
| <var-name>field[0]</var-name> |
| <var-value>pregnancyTest</var-value> |
| </var> |
| <var> |
| <var-name>fieldTest[0]</var-name> |
| <var-value>NOTNULL</var-value> |
| </var> |
| </field> |
| </form> |
| </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 <html:error> |
| 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> |
| <action path="/editRegistration" |
| type="org.apache.struts.webapp.example.EditRegistrationAction" |
| attribute="registrationForm" |
| scope="request" |
| validate="false"> |
| <forward name="success path="/registration.jsp"/> |
| </action> |
| </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> |
| <form-beans> |
| <form-bean name="MyWizard" |
| type="forms.MyWizard" /> |
| </form-beans> |
| |
| <!-- the first screen of the wizard (next action only |
| available) --> |
| <!-- no validation, since the finish action is not |
| available --> |
| <actions> |
| <action path="/mywizard1" |
| type="actions.MyWizard" |
| name="MyWizard" |
| validate="false" |
| input="/WEB-INF/jsp/mywizard1.jsp"> |
| <forward name="next" |
| path="/WEB-INF/jsp/mywizard2.jsp" /> |
| <forward name="cancel" |
| path="/WEB-INF/jsp/mywizardcancel.jsp" /> |
| </action> |
| |
| <!-- the second screen of the wizard (back, next and |
| finish) --> |
| <!-- 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 --> |
| <action path="/mywizard2" |
| type="actions.MyWizard" |
| name="MyWizard" |
| validate="true" |
| input="/WEB-INF/jsp/mywizard2.jsp"> |
| <forward name="back" |
| path="/WEB-INF/jsp/mywizard1.jsp" /> |
| <forward name="next" |
| path="/WEB-INF/jsp/mywizard3.jsp" /> |
| <forward name="finish" |
| path="/WEB-INF/jsp/mywizarddone.jsp" /> |
| <forward name="cancel" |
| path="/WEB-INF/jsp/mywizardcancel.jsp" /> |
| </action> |
| |
| <!-- the last screen of the wizard (back, finish and |
| cancel only) --> |
| <action path="/mywizard3" |
| type="actions.MyWizard" |
| name="MyWizard" |
| validate="true" |
| input="/WEB-INF/jsp/mywizard3.jsp"> |
| <forward name="back" |
| path="/WEB-INF/jsp/mywizard2.jsp" /> |
| <forward name="finish" |
| path="/WEB-INF/jsp/mywizarddone.jsp" /> |
| <forward name="cancel" |
| path="/WEB-INF/jsp/mywizardcancel.jsp" /> |
| </action> |
| </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><forward></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> |