Section 5: Handling Forms

Prepopulating and Redisplaying Input Forms

Alert: the HTML version of this tutorial is no longer being actively maintained, and still covers Struts 1.1. For additional topics, updates for Struts 1.2, and complete source code, please see Jakarta Struts Tutorial: Prepopulating and Redisplaying Input Forms (in PDF).

5.1 Summary of Techniques Introduced 5.2 The Six Basic Steps: Recap
5.3 Details & Example: Prepopulating Forms 5.4 Details & Example: Redisplaying Forms
5.5 Source Code for this Section
Struts Tutorial Table of Contents More Info

This section explains how to use the Struts html: tags to build HTML forms that have two important characteristics:

5.1 Summary of Techniques Introduced in This Section

Displaying HTML forms whose values are associated with Java objects requires the following steps not covered in earlier sections:

5.2 The Six Basic Steps in Using Jakarta Struts:
Recap with New Steps Incorporated

With Struts, the normal processing flow is that a form submits data to a URL of the form blah.do. The new wrinkle in this section is that this form uses the html:form tag to associate a bean with the form to give the form initial values. That blah.do address is mapped by struts-config.xml to an Action object, whose execute method handles the request. One of the arguments to execute is a form bean that is automatically created and whose properties are automatically populated with the incoming form data. The Action object then invokes business logic and data-access logic, placing the results in normal beans stored in request, session, or application scope. The Action uses mapping.findForward to return a condition, and the conditions are mapped by struts-config.xml to various JSP pages. The system forwards the request to the appropriate JSP page, where the bean:write tag is used to output properties of the form bean and results beans. Optionally, both the input form and the final JSP pages can use bean:message to output standard messages and labels as defined in a system properties file.

The first section outlines the six basic steps needed to implement this process, and gives examples that illustrate four of the steps (the ones not involving beans). The second section shows how to use beans and properties files, and provides examples of the other two steps. This section shows how to improve the initial form so that its values can be taken from a Java object either for the initial display or for redisplay when the form is submitted with incomplete data.

Here is a summary of the steps once the html:form tags are used.

  1. Modify struts-config.xml.
    We still use the action and forward elements to specify the Action object and destination URLs, and we still use the form-bean element to declare form beans. However, in addition to the path, type, name and scope attributes of the action element, we add a fifth attribute: input. This attribute tells the system to associate a form-bean of the type designated by name (which should match a name in the form-bean element) with the input form. Finally, as before, we can still use a message-resources element to declare a properties file containing standard messages, names, and labels.
  2. Define a form bean.
    This bean will be defined in the same way as before. However, in addition to being used in the execute method of the Action and (optionally) in the final JSP pages, the bean will also be used in the initial input form to give names and values to the various input elements.
  3. Create results beans.
    These are normal beans of the sort used in MVC when implemented directly with RequestDispatcher, and are created and used in the same way as described in the previous section.
  4. Create an Action object to handle requests.
    As in the previous section, rather than calling request.getParameter explicitly, the execute method casts the ActionForm argument to the specific form bean class, then uses getter methods to access the properties of the object.
  5. Create form that invokes blah.do.
    Rather than using the standard HTML FORM and INPUT tags, we now use html:form and html:text (and related tags) to build the input form. The html:form tag automatically associates a bean with the form, and html:text automatically uses the bean property names for each textfield NAME and the bean property values for each textfield VALUE. In addition, as in the previous section, this form can still use the bean:message tag to output standard messages and text labels that are defined in the properties file that is declared with message-resources in struts-config.xml.
  6. Display results in JSP.
    As before, the JSP page uses the bean:write tag to output properties of the form and result beans. It may also use the bean:message tag to output standard messages and text labels that are defined in the standard properties file.

5.3 Details & Example: Prepopulating Forms

In many cases, you want the initial form to be based on data defined in your application. If the application data changes, you want the initial values of the form fields to change automatically. To implement this behavior:


  1. Modify struts-config.xml.
  2. Define a form bean.
  3. Create results beans.
  4. Create an Action object to handle requests.
  5. Create form that invokes blah.do.
  6. Display results in JSP.
  7. Final results for this example.

  1. Modify struts-config.xml.
    Use WEB-INF/struts-config.xml to:
    • Designate Action classes to handle requests for blah.do. As before, we use the action element.
    • Specify the URLs that apply in various situations. As before, we use multiple forward elements within the action element.
    • Declare any form beans that are being used. As before, we use name and type attributes in the form-bean declaration. As before, we also add name (the bean name as given in form-bean) and scope (request since we aren't redisplaying the form) attributes to the action declaration. Finally, to tie the bean to the input form, we add one new attribute of action: input. The input attribute specifies the relative address of the JSP page that contains the input form. Here is an example.
          <action path="/actions/signup1"
                  type="coreservlets.SignupAction1"
                  name="contactFormBean"
                  scope="request"
                  input="/forms/signup1.jsp">
            ...
          </action>

    Here is the resultant struts-config.xml (download the source code here).
    struts-config.xml (Excerpt)
    <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC ... > <struts-config> <form-beans> <form-bean name="contactFormBean" type="coreservlets.ContactFormBean"/> </form-beans> <action-mappings> <action path="/actions/signup1" type="coreservlets.SignupAction1" name="contactFormBean" scope="request" input="/forms/signup1.jsp"> <forward name="missing-value" path="/WEB-INF/results/missing-value.jsp"/> <forward name="success" path="/WEB-INF/results/confirmation.jsp"/> </action> ... </action-mappings> </struts-config>
  2. Define a form bean.
    As before, the form bean will be automatically filled in with the incoming form parameters and passed to the execute method. In addition, a new instance of the form bean will be created and used to fill in the fields of the input form, with the NAME of the input field coming from the bean property name and the VALUE coming from the bean property value. For example, here is a form bean corresponding to contact information for a person that will be added to an email/fax list in our application. It contains properties for first name, last name, email address, etc. (Download the source code here).
    ContactFormBean.java
    package coreservlets; import org.apache.struts.action.*; public class ContactFormBean extends ActionForm { private String firstName = "First name"; private String lastName = "Last name"; private String email = "user@host"; private String faxNumber = "xxx-yyy-zzzz"; public String getFirstName() { return(firstName); } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return(lastName); } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return(email); } public void setEmail(String email) { this.email = email; } public String getFaxNumber() { return(faxNumber); } public void setFaxNumber(String faxNumber) { this.faxNumber = faxNumber; } ... }
  3. Create results beans.
    The form bean represents the input data: the data that came from the HTML form. The results beans represent the output data: the data created by the business logic to represent the results of the computation or database lookup. Following is a bean (MessageBean) that will be used to store simple error messages. (Download the source code here.)
    MessageBean.java
    package coreservlets; public class MessageBean { private String message = ""; public String getMessage() { return(message); } public void setMessage(String message) { this.message = message; } }
  4. Create an Action object to handle requests.
    In this example, we check each of the required input parameters (first name, last name, email address, and fax number) to see if it is missing. If it is missing, we use mapping.findForward to return a "missing-value" condition, which is mapped by struts-config.xml to an error page that contains a message saying which parameter was missing. If all parameters are present, we return "success", which results in an order-confirmation page.

    This example is similar to the previous one. Again, we do do not call request.getParameter explicitly, but instead extract the request parameters from the already populated form bean. Specifically, we take the ActionForm argument supplied to execute, cast it to ContactFormBean (our concrete class that extends ActionForm), and then call getter methods on that bean. Also, we pass the error message to the JSP page by creating a MessageBean and storing it in request scope. Here is the code (download the source code here).

    SignupAction1.java
    package coreservlets; import javax.servlet.http.*; import org.apache.struts.action.*; public class SignupAction1 extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ContactFormBean userBean = (ContactFormBean)form; String firstName = userBean.getFirstName(); String lastName = userBean.getLastName(); String email = userBean.getEmail(); String faxNumber = userBean.getFaxNumber(); MessageBean messageBean = new MessageBean(); request.setAttribute("messageBean", messageBean); if (isMissing(firstName)) { makeWarning(request, "first name"); return(mapping.findForward("missing-value")); } else if (isMissing(lastName)) { makeWarning(request, "last name"); return(mapping.findForward("missing-value")); } else if ((isMissing(email)) || (email.indexOf("@") == -1)) { makeWarning(request, "email address"); return(mapping.findForward("missing-value")); } else if (isMissing(faxNumber)) { makeWarning(request, "fax number"); return(mapping.findForward("missing-value")); } else { return(mapping.findForward("success")); } } private boolean isMissing(String value) { return((value == null) || (value.trim().equals(""))); } protected void makeWarning(HttpServletRequest request, String message) { MessageBean messageBean = (MessageBean)request.getAttribute("messageBean"); messageBean.setMessage(message); } }
  5. Create form that invokes blah.do.
    This form is very different from the ones in the previous examples. Instead of using the standard HTML FORM tag, we import and use the html:form tag. The Web application prefix, the .do suffix, and the POST method are all generated automatically. So, we use
    <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
    <html:form action="/actions/signup1">
      ...
    </html:form>
    
    to get something equivalent to:
    <FORM ACTION="/signup/actions/signup1.do" METHOD="POST">
      ...
    </FORM>
    
    Since the location of the input form matches the input attribute of the action declaration in struts-config.xml, a bean is automatically created when the input page is accessed. The type of bean created is determined by looking at the name that goes with the input attribute, and finding the form-bean with the same name. In this case, this process results in a ContactFormBean being created.

    After declaring the form and associating it with a bean, we use html:text to build input elements whose NAME and VALUE are taken from the form bean property names and values. So, for example,

    First name: <html:text property="firstName"/>
    
    results in something similar to:
    <% coreservlets.ContactFormBean contactBean =
         new coreservlets.ContactFormBean(); %>
    First name:
    <INPUT TYPE="TEXT" NAME="firstName"
           VALUE="<%= contactBean.getFirstName() %>">
    
    Here is the code (download the source code here).
    signup1.jsp
    <!DOCTYPE ...> <HTML> <HEAD><TITLE>Sign Up</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <H1 ALIGN="CENTER">Sign Up</H1> Looking to receive late-breaking unverified virus alerts, unknown ebay secrets, can't miss stock tips, works-in-your-sleep diet plans, and all sorts of medications? Want to get them both by email <I>and</I> by fax? Look no further: the Single Provider of Alert Memos system lets you sign up for them all in one easy request! <P> <CENTER> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <html:form action="/actions/signup1"> First name: <html:text property="firstName"/><BR> Last name: <html:text property="lastName"/><BR> Email address: <html:text property="email"/><BR> Fax number: <html:text property="faxNumber"/><BR> <html:submit value="Sign Me Up!"/> </html:form> </CENTER> </BODY></HTML>
  6. Display results in JSP.
    In this example, there are two possible JSP pages: one for missing input and one for success. We use the MessageBean to customize the error messages in the page that is used for missing input. That way, there does not need to be a separate page for each type of error. As in the previous example, the bean:write tag is used to output bean properties without having to resort to explicit Java code. Here are the two files (download the source code here).
    missing-value.jsp
    <!DOCTYPE ...> <HTML> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <HEAD><TITLE>Missing <bean:write name="messageBean" property="message"/> </TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H2>Missing <bean:write name="messageBean" property="message"/>!</H2> Please <A HREF="../forms/signup1.jsp">try again</A>. </CENTER> </BODY></HTML>
    confirmation.jsp
    <!DOCTYPE ...> <HTML> <HEAD><TITLE>Confirmation</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>Confirmation</H1> Congratulations. You are now signed up for the Single Provider of Alert Memos network! <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <UL> <LI>First name: <bean:write name="contactFormBean" property="firstName"/> <LI>Last name: <bean:write name="contactFormBean" property="lastName"/> <LI>Email address: <bean:write name="contactFormBean" property="email"/> <LI>Fax number: <bean:write name="contactFormBean" property="faxNumber"/> </UL> To be removed from the network, send email <A HREF="mailto:blackhole@spam-network.com">here</A>. </CENTER> </BODY></HTML>
  7. Final Results.
    First, the HTML form is invoked with the URL http://localhost/signup/forms/signup1.jsp, as follows. Notice that the textfields are prepopulated with the values of the ContactFormBean bean properties.

    Input form 1

    The action in the html:form element is /actions/signup1, and this results in the URL http://localhost/signup/actions/signup1.do. This address is mapped by struts-config.xml to the SignupAction1 class, whose execute method is invoked. This method examines the first name, last name, email address, and fax number to see if any are missing. If so, it returns mapping.findForward with a value of "missing-value". That value is mapped by struts-config.xml to /WEB-INF/results/missing-value.jsp. which is the final result displayed to the user for missing input. However, since the MessageBean stores the specific error message, the error page is different in each of the cases. For example, the following figures show the results when the form is submitted with a missing first and last name, respectively.

    Submission with missing first name

    Submission with missing first name


    In the next case, the form is submitted with all of the required parameters. The action in the html:form element is /actions/signup1, and this results in the URL http://localhost/signup/actions/signup1.do. This address is mapped by struts-config.xml to the SignupAction1 class, whose execute method is invoked. This method examines the first name, last name, email address, and fax number to see if any are missing. Since none are, it returns mapping.findForward with a value of "success". That value is mapped by struts-config.xml to /WEB-INF/results/confirmation.jsp. which is the final result displayed to the user, as shown below.

    Confirmation page: result of successful submission

5.4 Details & Example: Redisplaying Forms

In the previous example, we show how to display a form whose initial values come from a newly-created (i.e., request-scoped) JavaBeans component. In this example, we show how to redisplay a form and base its values on a session-scoped bean. This second technique lets you submit a form, check if all the required data is supplied, and redisplay the form if any of the data is missing. Most importantly, when you redisplay the form, you can maintain the previous values that the end user entered. To implement this behavior, you declare a form-bean in struts-config.xml as before, use the input attribute of action to designate the URL of the input page (so that a bean can be created) as before, and again use the html:form and html:text tags in the input form. However, there are three differences:


  1. Modify struts-config.xml.
  2. Define a form bean.
  3. Create results beans.
  4. Create an Action object to handle requests.
  5. Create form that invokes blah.do.
  6. Display results in JSP.
  7. Final results for this example.

  1. Modify struts-config.xml.
    Use WEB-INF/struts-config.xml to:
    • Designate Action classes to handle requests for blah.do. As before, we use the action element.
    • Specify the URLs that apply in various situations. As before, we use multiple forward elements within the action element. However, for the "missing-value" entry, we specify the location of the original input form, rather than the location of a new JSP page. We also use redirect="true" so that the system uses an HTTP redirect, not RequestDispatcher.forward, to transfer to the input form. That way, the URL of the input form is shown to the user, which looks more familiar and lets the user bookmark the address. Here is the action declaration:
          <action path="/actions/signup2"
                  type="coreservlets.SignupAction2"
                  name="contactFormBean"
                  scope="session"
                  input="/forms/signup2.jsp">
            <forward name="missing-value"
                     path="/forms/signup2.jsp"
                     redirect="true"/>
            <forward name="success"
                     path="/WEB-INF/results/confirmation.jsp"/>
          </action>
    • Declare any form beans that are being used. As before, we use name and type attributes in the form-bean declaration. As before, we also add name, input, and scope attributes to the action declaration. However, in this case we use scope="session" instead of scope="request" so that the values are available to the input-form-page when we redirect to it.

    Here is the resultant struts-config.xml (download the source code here).
    struts-config.xml (Excerpt)
    <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC ... > <struts-config> <form-beans> <form-bean name="contactFormBean" type="coreservlets.ContactFormBean"/> </form-beans> <action-mappings> ... <action path="/actions/signup2" type="coreservlets.SignupAction2" name="contactFormBean" scope="session" input="/forms/signup2.jsp"> <forward name="missing-value" path="/forms/signup2.jsp" redirect="true"/> <forward name="success" path="/WEB-INF/results/confirmation.jsp"/> </action> </action-mappings> </struts-config>
  2. Define a form bean.
    This example uses the same ContactFormBean as the previous example. However, in this example we make use of the warning property, which does not correspond to a request parameter but rather is used to send missing-entry-warnings to the input form. Here is the code (Download the source code here).
    ContactFormBean.java
    package coreservlets; import org.apache.struts.action.*; public class ContactFormBean extends ActionForm { private String firstName = "First name"; private String lastName = "Last name"; private String email = "user@host"; private String faxNumber = "xxx-yyy-zzzz"; private String warning = ""; public String getFirstName() { return(firstName); } public void setFirstName(String firstName) { this.firstName = firstName; } ... // lastName, emailAddress, and faxNumber properties } public String getWarning() { return(warning); } public void setWarning(String baseWarning) { this.warning = "<H2><FONT COLOR=RED>Missing " + baseWarning + "!</FONT></H2>"; } }
  3. Create results beans.
    Since the confirmation page merely displays the data entered by the user (which is taken from the form bean), this example uses no results beans.
  4. Create an Action object to handle requests.
    This example is very similar to the previous one. However, instead of storing missing-value warning messages in a separate bean that will be displayed in a separate JSP page, the warnings are stored in form-bean, which is used when the original input page is redisplayed. To do this, we keep the same execute method, but replace the showWarning method with a version that stores the warnings in the form-bean (intended for the original input page) rather than in the MessageBean (intended for a custom error page). Here is the code (download the source code here).
    SignupAction2.java
    package coreservlets; import javax.servlet.http.*; public class SignupAction2 extends SignupAction1 { protected void makeWarning(HttpServletRequest request, String message) { HttpSession session = request.getSession(); ContactFormBean contactFormBean = (ContactFormBean)session.getAttribute("contactFormBean"); contactFormBean.setWarning(message); } }
  5. Create form that invokes blah.do.
    This form is very similar to the one in the previous example. Again, we use the html:form and html:text elements to build an HTML form whose formfield values are derived from bean properties. However, this time the bean is session-scoped, so when the form is redisplayed the bean property values are the ones that the user previously entered. Furthermore, we output a warning message that reminds the user which field they omitted. The default warning message is an empty string, so rather than testing to see if the form is being initially displayed or redisplayed, we always output the error message (with filter="false" because the error message can contain HTML tags). Here is the code (download the source code here).
    signup2.jsp
    <!DOCTYPE ...> <HTML> <HEAD><TITLE>Sign Up</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <H1 ALIGN="CENTER">Sign Up</H1> Looking to receive late-breaking unverified virus alerts, unknown ebay secrets, can't miss stock tips, works-in-your-sleep diet plans, and all sorts of medications? Want to get them both by email <I>and</I> by fax? Look no further: the Single Provider of Alert Memos system lets you sign up for them all in one easy request! <P> <CENTER> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <html:form action="/actions/signup2"> <bean:write name="contactFormBean" property="warning" filter="false"/> First name: <html:text property="firstName"/><BR> Last name: <html:text property="lastName"/><BR> Email address: <html:text property="email"/><BR> Fax number: <html:text property="faxNumber"/><BR> <html:submit value="Sign Me Up!"/> </html:form> </CENTER> </BODY></HTML>
  6. Display results in JSP.
    In this example, there are two possible return values from the execute method of the Action object: "missing-value" and "success". Since the "missing-value" is mapped by struts-config.xml back to the original input page, there is only one real results page. Since the results in this example are exactly the same as in the previous example, we use the same JSP page. Here it is, repeated verbatim from the previous example (download the source code here).
    confirmation.jsp
    <!DOCTYPE ...> <HTML> <HEAD><TITLE>Confirmation</TITLE></HEAD> <BODY BGCOLOR="#FDF5E6"> <CENTER> <H1>Confirmation</H1> Congratulations. You are now signed up for the Single Provider of Alert Memos network! <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <UL> <LI>First name: <bean:write name="contactFormBean" property="firstName"/> <LI>Last name: <bean:write name="contactFormBean" property="lastName"/> <LI>Email address: <bean:write name="contactFormBean" property="email"/> <LI>Fax number: <bean:write name="contactFormBean" property="faxNumber"/> </UL> To be removed from the network, send email <A HREF="mailto:blackhole@spam-network.com">here</A>. </CENTER> </BODY></HTML>
  7. Final Results.
    First, the HTML form is invoked with the URL http://localhost/signup/forms/signup2.jsp, as follows. As before, the textfields are prepopulated with the values from the ContactFormBean properties, as illustrated in the following figures.

    Input form 2

    The action in the html:form element is /actions/signup2, and this results in the URL http://localhost/signup/actions/signup2.do. This address is mapped by struts-config.xml to the SignupAction2 class, whose execute method is invoked. This method examines the first name, last name, email address, and fax number to see if any are missing. If so, it returns mapping.findForward with a value of "missing-value". That value is mapped by struts-config.xml back to the original input form. And, since redirect="true" is used, the user is transferred there by an HTTP redirect (as with response.sendRedirect), and the URL of the input page is displayed to the user. The execute method stores warnings about missing values in the warning property of the form bean (which defaults to an empty string), so notifying the user that they omitted a value is merely a matter of outputting that property. For example, the following figures show the results when the form is submitted with a missing first and last name, respectively.

    Submission with missing first name

    Submission with missing last name


    In the next case, the form is submitted with all of the required parameters. The action in the html:form element is /actions/signup2, and this results in the URL http://localhost/signup/actions/signup2.do. This address is mapped by struts-config.xml to the SignupAction2 class, whose execute method is invoked. This method examines the first name, last name, email address, and fax number to see if any are missing. Since none are, it returns mapping.findForward with a value of "success". That value is mapped by struts-config.xml to /WEB-INF/results/confirmation.jsp, the same confirmation page as used in the previous example. Here is a representative result.

    Confirmation page: result of successful submission

5.5 Source Code for this Section

The following list gives the source code to all files described in this section, listed in the order that they appear. These examples are part of a Web application called signup, which is distinct from the struts-test application used in the previous examples.

To download the code, right-click on the links and choose "Save Target As". Be sure to reproduce the same directory structure as given here. The easiest approach is to download and unjar the entire signup WAR file, but this takes some time since this WAR file includes the Struts JAR files in addition to the sample code.

Next section: Validating User Input

More Information

J2EE Short Courses
Personally developed and taught by the author of Core Servlets & JSP, More Servlets & JSP, and this Jakarta Struts tutorial.
Contact Marty
Send email to hall@coreservlets.com to report errors and omissions in this writeup, or to inquire about training courses on Struts, JSP, servlets, JSF, AJAX, or Java 5 programming.
References
Jakarta Struts Books
Servlet & JSP Books