Professional Documents
Culture Documents
http://javaboutique.internet.com/tutorials/strutsform/article.html
Back to Article
Introduction
This article is about the more advanced features Jakarta Struts offers in building HTML forms. If you know how to create forms in plain HTML then the step to building simple forms in Struts with, for example, a couple of input text elds, a checkbox or a radio button is not very complicated. When it comes to the more complex controls like the multi-valued selection list or a variable length list of input elds it gets more challenging. This is especially true when the possible selections are not xed, but taken from some external source like a database instead. I've too often found myself struggling with the syntax and semantics of the HTML-tags when the forms get complex, and if you search the web for advice, you'll soon see that you have to collect information from many sources. In this article I've tried to collect solutions to the most common non-trivial cases. Every case, of course, is not covered here. Remember to also read Struts' own documentation, starting with the documentation for the HTML-tags. You might nd what you need there. At the end of the article is a table with an overview of the solutions. I'm sure you'll nd it useful when coding your Struts applications. Here's a link to a zip le containing all the examples shown in the article.
1 de 11
17/01/12 06:37
http://javaboutique.internet.com/tutorials/strutsform/article.html
1 of many xed values. Gives you the same functionality as the radio buttons, only the presentation differs. Several of many xed values
Several of many xed values. Gives you the same functionality as the multi selection list, only the presentation differs.
In Struts you dene a control with a tag from Struts' HTML- library. The next table shows how these are mapped to the old, well-known HTML tags: Type 1. Text eld 2. Text area eld 3. Checkbox Struts html-tag
<html:text property="firstname"/> <html:textarea property="address"/> <html:checkbox property="married" value="yes"/> value="Diners"/> . . .
HTML tag
<input type="text" name="firstname"> <textarea name="address"> <input type="checkbox" name="married" value="yes"> <input type="radio" name="card" value="Diners"> . . . <select name="country"> <option value="F"> . . .
4. Radio button <html:radio property="card" 5. Selection list <html:select property="country"> and <html:option value="F"/> . . . single type 6. Selection list <html:select property="food" multiple="true"> and <html:option value="milk"/> . . . multiple type 7. List of checkboxes
<html:multibox property="site"> . . .
To begin with, you'll notice that where Struts uses the attribute name "property", HTML uses "name". This is a bit confusing since Struts also has an attribute called "name", which is used to give the name of the bean whose "property" maps the control. The default for the "name" attribute is the name of the form's corresponding bean, so normally you don't need to use the "name" attribute.
2 de 11
17/01/12 06:37
http://javaboutique.internet.com/tutorials/strutsform/article.html
1. a Java ActionForm bean dened in the form-beans section of the struts-cong le, for example:
<form-bean name="detailForm" type="hansen.playground.DetailForm"/>
2. a "dynamic" form bean, also dened in the form-beans section of struts-cong, for example:
<form-bean name="simpleForm" type="org.apache.struts.action.DynaActionForm"> <form-property name="firstname" type="java.lang.String"/> <form-property name="site" type="java.lang.String[]"/> </form-bean>
Note that a control may be mapped to an array if it contains more than one value. Rule #2: You may get or set the data in the controls from the execute method in the Action class: 1. ActionForm bean:
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { DetailForm df = (DetailForm)form; String index = df.getFirstName(); String[] site = df.getSite(); . . . df.setFirstName("John"); . . .
You may of course also get or set the data in the ActionForm itself - for example in the validate method. 2. Dynamic form bean:
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { DynaActionForm f = (DynaActionForm)form; String firstName = (String)f.get("firstname"); String[] site = (String[])f.get("site"); . . . f.set("firstname", "John"); . . .
3 de 11
17/01/12 06:37
http://javaboutique.internet.com/tutorials/strutsform/article.html
your classes. Instead we'll look further at the controls that have a set of options or values attached.
Dynamic options
It's much more interesting--seen from a programmer's point of view--when the selectable options are computed in the application, for example read from a database. Struts has solutions for all the remaining controls--marked 4, 5, 6, and 7 above--but unfortunately they're rather different. One thing is, however, common for some of them: they use the logic:iterate tag to loop over the set of selectable options. So let's take a quick recap of how to use the iterate tag. A simple example:
<table border=1> <logic:iterate id="customer" name="customers"> <tr> <td><bean:write name="customer" property="firstName"/></td> <td><bean:write name="customer" property="lastName"/></td> <td><bean:write name="customer" property="address"/></td> </tr> </logic:iterate> </table>
The iterate tag's name-attribute refers to a Collection of beans stored in request or session scope. The id-attribute gives the (logical) name of the bean created in each iteration. Other tags--for example the bean:write tag--may then refer to this bean with their name-attribute. The propertyattribute nally selects the wanted property from the bean. You might now think that you simply use the name- and property-attributes with the html-tags, but it's not that simple. The html-tags already use the property- attribute for the name of the property in the ActionForm, so there's a conict here. The tag inventors have had other challenges as well, so therefore the syntax for the HTML-tags when handling sets of options are a bit heterogeneous. The Radio Button Now I'll present a solution, and afterwards discuss the explanations. First the struts-cong le, where we dene a dynamic form bean (but you could just as well use the old ActionForm bean):
4 de 11
17/01/12 06:37
http://javaboutique.internet.com/tutorials/strutsform/article.html
We're using a Collection of beans with properties value and label. When the idName attribute is used the radio-tag's value-attribute denotes a property in the bean given by idName. It's the id-attribute in the iterate-tag and the idName in the radio-tag that links the tags together. Struts has a utility bean class called LabelValueBean with exactly these properties: value and label, and it may be used to construct a "minimal" bean to put in a Collection, for example:
import org.apache.struts.util.LabelValueBean; . . . Collection choices = new ArrayList(); choices.add(new LabelValueBean("American Express", "AE")); choices.add(new LabelValueBean("MasterCard", "MC")); choices.add(new LabelValueBean("Diners", "DN")); request.setAttribute("choices", choices);
You don't have to use this utility class, any bean will do, as long as it has properties that can be used for the value attribute in the html:radio tag and the property attribute in the bean:write tag. You may set or get the current value of the radio buttons in the execute method, as described earlier. The name we've used for the radio buttons, control, will also be used in the following examples. The Selection List - Single Type Since the single type selection list returns one value only, we can use the same setup in struts-cong as for the radio buttons:
<form-bean name="singleSelectForm" type="org.apache.struts.action.DynaActionForm"> <form-property name="control" type="java.lang.String"/> </form-bean>
Now assume that we have a bean, Customer, with String properties firstName, lastName, address, and id. If you have a Collection of Customer beans then you can show a list of all the customers using jsp-code like this:
<html:select property="control" size="2"> <logic:iterate id="customer" name="customers" type="hansen.playground.Customer"> <html:option value="<%=customer.getId()%>"> <bean:write name="customer" property="firstName"/>
5 de 11
17/01/12 06:37
http://javaboutique.internet.com/tutorials/strutsform/article.html
You'll have to specify the type attribute of the iterate tag or the scriptlet will fail. There is a much nicer solution, however:
<html:select property="control" size="2"> <html:options collection="customers" property="id" labelProperty="fullName"/> </html:select>
This time we use the options tag, where the collection attribute gives the name of the Collection of beans, and property gives the name of the property in the bean whose value will be returned when the form is submitted. labelProperty is the bean property that will be displayed. I've created a pseudo-property, fullName, in the Customer bean with a getter-method that returns the firstName and the lastName. In the browser we could have this presented:
An almost identical solution, but using less confusing attribute names, is this:
<html:select property="control" size="2"> <html:optionsCollection name="customers" value="id" label="fullName"/> </html:select>
The current value of the list is again set or get in the execute method--as described previously. The Selection List - multiple type You may copy the solutions from the single choice selection list if you add multiple="true" to the html:select-tag:
<html:select multiple="true" property="control" size="2"> <html:optionsCollection name="customers" value="id" label="fullName"/> </html:select>
This time, however, you'll have to dene the control property in the ActionForm as a String array:
<form-bean name="multiSelectForm" type="org.apache.struts.action.DynaActionForm"> <form-property name="control" type="java.lang.String[]"/> </form-bean>
6 de 11
17/01/12 06:37
http://javaboutique.internet.com/tutorials/strutsform/article.html
List of checkboxes Finally, the case with a set of checkboxes, where the user may select zero, one or many of the presented options. This resembles the multi selection list, only the GUI is different. You might think that a solution like this will work:
<logic:iterate id="customer" name="customers" type="hansen.playground.Customer"> <html:checkbox property="control" value="<%=customer.getId()%>"/> <bean:write name="customer" property="fullName"/> <br> </logic:iterate>
It will not work 100%. The GUI is OK, and you may also submit the correct data, but if you return to the same page you have lost the data you just typed in. There is, however, a special tag for this case called the multibox, and it will work:
<logic:iterate id="customer" name="customers"> <html:multibox property="control"> <bean:write name="customer" property="id"/> </html:multibox> <bean:write name="customer" property="fullName"/> <br> </logic:iterate>
7 de 11
17/01/12 06:37
http://javaboutique.internet.com/tutorials/strutsform/article.html
If you deselect all choices and submit the form you'll observe that nothing happens: the previously selected values are still selected. The reason is, since you haven't selected anything, nothing is actually submitted. The ActionForm is therefore not updated. You may correct this behavior if you dene a reset method in your ActionForm that initializes the control's array to an empty array:
public void reset( ActionMapping mapping, HttpServletRequest request) { this.control = new String[0]; }
If you are using a DynaActionForm you'd have to code an extension of the DynaActionForm:
package hansen.playground; import javax.servlet.http.HttpServletRequest; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.DynaActionForm; public class MyDynaActionForm extends DynaActionForm { public void reset( ActionMapping mapping, HttpServletRequest request) { this.set("control", new String[0]); } }
This situation only occurs for an action dened in session scope. In request scope you get a new bean for every request, with the control's property initially set to an empty array.
The persons are taken from a database, so the number of "lines" is a variable. This is a case for Struts' "Indexed Properties". We'll once more use the Customer class, so rst we dene this form in struts-cong:
<form-bean name="listTextForm" type="org.apache.struts.action.DynaActionForm"> <form-property name="customer" type="hansen.playground.Customer[]"/> </form-bean>
8 de 11
17/01/12 06:37
http://javaboutique.internet.com/tutorials/strutsform/article.html
This is a very different setup from what we have seen before. This time we dene a "control" which is an array of Customers. The action in the struts-cong must have scope="session":
<action path="/listtext" type="hansen.playground.ListTextAction" scope="session" name="listTextForm"> <forward name="OK" path="/listtext.jsp"/> </action>
This time we get an array of Customers in the ActionForm. The jsp-page could look like this:
<html:form action="listtext"> <html:submit/> <logic:iterate id="customer" <html:text name="customer" <html:text name="customer" <html:text name="customer" <br> name="listTextForm" property="customer"> property="firstName" indexed="true"/> property="lastName" indexed="true"/> property="address" indexed="true"/>
9 de 11
17/01/12 06:37
http://javaboutique.internet.com/tutorials/strutsform/article.html
</logic:iterate> </html:form>
The new thing here is the indexed attribute. We iterate over the array of Customers, and for each bean we use its attributes in the text elds. Note that we'll have to use the name "customer" in several places to have the Indexed Properties feature working. If you were to look in the generated HTML you would see this:
<input type="text" name="customer[0].firstName" value="John"> <input type="text" name="customer[0].lastName" value="Doe"> <input type="text" name="customer[0].address" value="X-Street 7"> <br> <input type="text" name="customer[1].firstName" value="Peter"> <input type="text" name="customer[1].lastName" value="Smith"> <input type="text" name="customer[1].address" value="Computer blvd. 123"> <br> <input type="text" name="customer[2].firstName" value="Keld"> <input type="text" name="customer[2].lastName" value="Hansen"> <input type="text" name="customer[2].address" value="Java Road 13"> <br>
When such a form is submitted Struts will recognize the syntax of the name-attributes as Indexed Properties, and ll the ActionForm correctly. This setup will also work for lists of other controls as well. Read more about Indexed Properties in the Struts documentation.
Recap
1. Always dene properties in the ActionForm matching the property attribute from the html-tag. The exception is Indexed Properties, where you must dene an array of the object you iterate through 2. Use setters and getters from the ActionForm to access the data in the form. 3. Use these tags in your jsp: Radiobuttons
<logic:iterate id="customer" name="customers"> <html:radio property="control" idName="customer" value="id"/> <bean:write name="customer" property="fullName"/> <br> </logic:iterate> <html:select property="control" size="2"> <html:optionsCollection name="customers" value="id" label="fullName"/> </html:select> <html:select property="control" size="2" multiple="true"> <html:optionsCollection name="customers" value="id" label="fullName"/> </html:select> <logic:iterate id="customer" name="customers"> <html:multibox property="control"> <bean:write name="customer" property="id"/> </html:multibox>
Selection list - single value Selection list - multiple values List of checkboxes
10 de 11
17/01/12 06:37
http://javaboutique.internet.com/tutorials/strutsform/article.html
<bean:write name="customer" property="fullName"/> <br> </logic:iterate> <logic:iterate id="customer" name="listTextForm" property="customer"> <html:text name="customer" property="firstName" indexed="true"/> <html:text name="customer" property="lastName" indexed="true"/> <html:text name="customer" property="address" indexed="true"/> <br> </logic:iterate>
Conclusion
Struts has a rich set of HTML-tags for building form controls. Unfortunately it's often rather difcult to predict the exact syntax to use in a given situation. The examples presented above should be possible to copy/paste into your own applications. If you dig up another clever solution you're welcome to e-mail me, and I'll try to put your solution in one of my upcoming articles. Happy coding! Keld is currently working as a web architect for one of the largest IT companies in Denmark. He battled with the mainframes during the 70's when they were the size of a gymnasium and had the power of your PalmPilot. He also struggled with CASE-tools in the 90s and now explores the cutting edge technology of the Web. While not busy at his computer he likes to vacation on the Greek islands.
Resources
A zip le with all examples from the article The home of Struts: jakarta.apache.org/struts Struts' User and Developer Guide Struts' documentation on the HTML-tags Previous articles from JavaBoutique about Struts: - "Stepping through Jakarta Struts" - "Coding your second Jakarta Struts Application" - "Introducing: the Struts bean and logic Tag Libraries" - "Stepping through the Struts 1.1 Validator" - "StrutsTestCase: The Tool for Struts Unit testing" - "Handling Messages, Errors and Exceptions in Struts 1.1" "Succeeding With Struts: Indexed Properties and Beans as Properties" Tips on various forms questions, by Ted Husted
11 de 11
17/01/12 06:37