November 1, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Succeeding with Struts: Dynamically Allocated Forms

  • December 5, 2005
  • By James Turner
  • Send Email »
  • More Articles »

The peril of ending an article with a item left as a problem for the reader is that it inevitably comes back to haunt you. In my last article, Succeeding With Struts: Dynamically Sized Forms, I mentioned casually that it was possible to set up a form with indexed properties such that it could have a dynamically initialized array of values that varied depending on the number of items submitted. And, of course, I've gotten a ton of letters since then asking exactly how to go about it.

The classic example of this type of problem is a checkout form for a shopping cart. The action that displays the form knows exactly how many items are in the cart, and therefore can create the appropriate size array to service the page. But what happens when you submit? Remember that form populate happens very early in the Struts request processor, before validation or action processing. Even if you wrote a magic hidden field with the number of lines on the page, how could you get the array allocated before the form was populated, because the action runs after the form is populated? The answer lies in the one thing that does run before form population, the reset method for the ActionForm.

As always, the best way to illustrate this is with a practical example, and what better example than an actual shopping cart check out screen? To begin with, we need a bean to hold the individual items in the cart:

package com.blackbear.forms;

public class Product {

   /**
    * An individual product items
    */

   private String productNumber;
   private String productPrice;
   private String productQuantity;
   private String total;

   /**
    * @return Returns the productQuantity.
    */
   public String getProductQuantity() {
      return productQuantity;
   }
   /**
    * @param productQuantity The productQuantity to set.
    */
   public void setProductQuantity(String productQuantity) {
      this.productQuantity = productQuantity;
   }
   /**
    * @return Returns the productNumber.
    */
   public String getProductNumber() {
      return productNumber;
   }
   /**
    * @param productNumber The productNumber to set.
    */
   public void setProductNumber(String productNumber) {
      this.productNumber = productNumber;
   }
   /**
    * @return Returns the productPrice.
    */
   public String getProductPrice() {
      return productPrice;
   }
   /**
    * @param productPrice The productPrice to set.
    */
   public void setProductPrice(String productPrice) {
      this.productPrice = productPrice;
   }
   /**
    * @return Returns the total.
    */
   public String getTotal() {
      return total;
   }
   /**
    * @param total The total to set.
    */
   public void setTotal(String total) {
      this.total = total;
   }
}

Just your standard Javabean, with four properties: the product number, product quantity, product price, and subtotal. Next, you set up an ActionForm, which in this case consists of nothing but an array of Product beans. The form also has a validate method that makes sure all the quantities are parsable integers.

package com.blackbear.forms;

import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;

public class ListOfProductsForm extends ActionForm {


   /** FormItems property */
   private Product[] formItems;

   /** 
    * Method validate
    * @param mapping          The Struts Action Mapping
    * @param request          The incoming request
    * @return ActionErrors    The resulting errors
    */
   public ActionErrors validate(
      ActionMapping mapping,
      HttpServletRequest request) {

      ActionErrors errors = new ActionErrors();

      for (int i = 0; i < formItems.length; i++)
      {
         String quantity = formItems[i].getProductQuantity();
         if ((quantity != null) && (quantity.length() > 0))
         {
            try
            {
               Integer.parseInt(quantity);
            }
            catch (Exception ex)
            {
               errors.add("formItems[" + i + "].productQuantity",
                          new ActionError(
                             "com.blackbear.badquantity",
                             quantity));
            }
         }
      }
      return errors;
   }

   /**
    * Returns the FormItems.
    * @return Product
    */
   public Product[] getFormItems() {
      return formItems;
   }

   /**
    * Set the FormItems.
    * @param FormItems The FormItems to set
    */
   public void setFormItems(Product[] FormItems) {
      this.formItems = FormItems;
   }
}

The display action for the page simply creates an array of Product beans (of a random size) and populates it with random products:

package com.blackbear.action;

import java.util.Random;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.blackbear.forms.ListOfProductsForm;
import com.blackbear.forms.Product;

public class DisplayRandomListOfProductsAction extends Action {

/**
  * Create a random list of shopping cart items
  *
  * @param mapping           The Struts Action Mapping
  * @param form              The Struts Form (ListOfProductsForm)
  * @param request           The request
  * @param response          The response
  * @return ActionForward    The resulting page
  */
   public ActionForward execute(ActionMapping mapping,
                                ActionForm form,
                                HttpServletRequest request,
                                HttpServletResponse response) {

      ListOfProductsForm productForm = (ListOfProductsForm) form;

      Random rand = new Random();
      int numberOfProducts = rand.nextInt(20);

      Product[] products = new Product[numberOfProducts];
      productForm.setFormItems(products);

      for (int i = 0; i < numberOfProducts; i++) {
         products[i] = new Product();
         products[i].setProductNumber("1" + rand.nextInt(10000));
         products[i].setProductPrice(String
            .valueOf(rand.nextInt(10000) / 100.0));
         products[i].setProductQuantity(
            String.valueOf(rand.nextInt(5) + 1));
      }

      return mapping.findForward("success");
   }

}

And finally, the JSP for the page uses a JSTL c:forEach loop to render a table with editable fields for the quantities:

Dynamic Product Input Page







Dynamic Product Input Page

Product Number Product Price Quantity Total

Dynamic Product Input Page

Product NumberProduct PriceQuantity




Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel