Home

This Chapter
-Chapter 4: Input Validation and Data Conversion
-Data Types for Your Action Form’s Properties
-Input Validation and Data Conversion Example
-Using BeanUtils
-Efficient Conversion
-Summary

Table of Contents
-Introduction
-Chapter 1: Model 2 and Struts
-Chapter 2: Input Validation with Action Forms
-Chapter 3: The HTML Tag Library
-Chapter 4: Input Validation and Data Conversion
-Chapter 5: The Validator Plugin
-Chapter 6: The Expression Language
-Chapter 7: JSTL
-Chapter 8: The Bean Tag Library
-Chapter 9: The Logic Tag Library
-Chapter 10: Struts-EL, Nested, selectLabel
-Chapter 11: Message Handling and Internationalization
-Chapter 12: The Tiles Framework
-Chapter 13: Securing Struts Applications
-Chapter 14: The Config Object
-Chapter 15: The Persistence Layer
-Chapter 16: Object Caching
-Chapter 17: File Upload and File Download
-Chapter 18: Paging and Sorting
-Chapter 19: Preventing Double Submits
-Chapter 20: Early HttpSession Invalidation
-Chapter 21: Decorating Request Objects
-Chapter 22: How Struts Works

Previous
Next

 

Input Validation and Data Conversion Example

The app04a application demonstrates how you can validate user input by overriding the validate method of the action form. It also shows that you need to perform data conversion in both the validate method and in the action class.

The app04a application can be used to enter an order. It has two actions: displayAddOrderForm and saveOrder. The Struts configuration file for app04a is given in Listing 4.1.

Listing 4.1: The Struts configuration file for app04a.

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE struts-config PUBLIC
  "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
  "http://struts.apache.org/dtds/struts-config_1_2.dtd">

<struts-config>
  <form-beans>
    <form-bean name="orderForm" type="app04a.form.OrderForm"/>
  </form-beans>

  <action-mappings>
    <action path="/displayAddOrderForm"
      forward="/jsp/displayAddOrderForm.jsp"/>
    <action path="/saveOrder"
      type="app04a.action.SaveOrderAction"
      input="/jsp/displayAddOrderForm.jsp"
      name="orderForm">
      <forward name="success" path="/jsp/displaySavedOrder.jsp"/>
    </action>

  </action-mappings>
  <message-resources parameter="ApplicationResources"/>
</struts-config>

An order must have a product identifier, a customer name, a quantity, a price, and an order date. You will use an action form and upon successful validation of the form, produce an OrderTO object whose class is given in Listing 4.2

Listing 4.2: The OrderTO class

package app04a.to;
import java.util.Date;

public class OrderTO implements java.io.Serializable {
  private int productId;
  private String customer;
  private int quantity;
  private float price;
  private Date orderDate;

  public int getProductId() {
    return productId;
  }
  public void setProductId(int productId) {
    this.productId = productId;
  }
  public String getCustomer() {
    return customer;
  }
  public void setCustomer(String customer) {
    this.customer = customer;
  }
  public int getQuantity() {
    return quantity;
  }
  public void setQuantity(int quantity) {
    this.quantity = quantity;
  }
  public float getPrice() {
    return price;
  }
  public void setPrice(float price) {
    this.price = price;
  }
  public Date getOrderDate() {
    return orderDate;
  }
  public void setOrderDate(Date orderDate) {
    this.orderDate = orderDate;
  }
}

The action form is called orderForm. All its properties are String, except the productId property, which is an int and mapped to an HTML select element and therefore will have one of the pre-defined options as its value (in other words, the use of int as the data type of the productId property is justified because there is no risk of the user entering an invalid value). The action form’s validate method provides validation rules. No field may be empty and the order date must accept a data value having an “MM/dd/yyyy” pattern.

The action form is given in Listing 4.3

Listing 4.3: The app04a.form.OrderForm class

package app04a.form;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;

public final class OrderForm extends ActionForm {

  private static SimpleDateFormat dateFormatter =
    new SimpleDateFormat("MM/dd/yyyy");
  static {
    dateFormatter.setLenient(false);
  }

  private int productId;
  private String customer;
  private String quantity;
  private String price;
  private String orderDate;

  public String getCustomer() {
    return customer;
  }
  public void setCustomer(String customer) {
    this.customer = customer;
  }
  public String getOrderDate() {
    return orderDate;
  }
  public void setOrderDate(String orderDate) {
    this.orderDate = orderDate;
  }
  public String getPrice() {
    return price;
  }
  public void setPrice(String price) {
    this.price = price;
  }
  public int getProductId() {
    return productId;
  }
  public void setProductId(int productId) {
    this.productId = productId;
  }
  public String getQuantity() {
    return quantity;
  }
  public void setQuantity(String quantity) {
    this.quantity = quantity;
  }
  public ActionErrors validate(ActionMapping mapping,
    HttpServletRequest request) {
    ActionErrors errors = new ActionErrors();

    //Validate Customer
    if (customer.trim().equals("")) {
      errors.add("order", new ActionMessage("missing.customer"));
    }

    //Validate Quantity
    if (quantity.trim().equals("")) {
      errors.add("order", new ActionMessage("missing.quantity"));
    }
    else {
      try {
        Integer.parseInt(quantity);
      }
      catch (NumberFormatException e) {
        errors.add("order", new ActionMessage("invalid.quantity"));
      }
    }

    //Validate Price
    if (price.trim().equals("")) {
      errors.add("price", new ActionMessage("missing.price"));
    }
    else {
      try {
        Float.parseFloat(price);
      }
      catch (NumberFormatException e) {
        errors.add("price", new ActionMessage("invalid.price"));
      }
    }

    //Validate OrderDate
    if (orderDate.trim().equals("")) {
      errors.add("order", new ActionMessage("missing.orderDate"));
    }
    else {
      // if lenient=true, dateFormatter.parse(String) will parse 32 December 2004 as 1 January 2005
      try {
        dateFormatter.parse(orderDate);
      }
      catch (ParseException e) {
        errors.add("order", new ActionMessage("invalid.orderDate"));
      }
    }
    return errors;
  }
}

A SimpleDateFormat object is used to validate order dates. The displayAddOrderForm.jsp page (in Listing 4.4) contains a form mapped to the orderForm action form.

Note

The OrderTO class has the following data types: int, float, String, Date, whereas the OrderForm class uses the following data types: int, String.

Listing 4.4: The displayAddOrderForm.jsp

<%@ taglib uri="/tags/struts-html" prefix="html" %>
<html>
<title>Add Order Form</title>
</head>
<body>
<html:errors/>
<html:form action="/saveOrder">
<table>
<tr>
  <td>Product:</td>
  <td>
    <html:select property="productId">
      <html:option value="1">Monitor</html:option>
      <html:option value="2">Keyboard</html:option>
      <html:option value="3">Mouse</html:option>
    </html:select>
  </td>
</tr>
<tr>
  <td>Customer:</td>
  <td><html:text property="customer"/></td>
</tr>
<tr>
  <td>Quantity:</td>
  <td><html:text property="quantity"/></td>
</tr>
<tr>
  <td>Price:</td>
  <td><html:text property="price"/></td>
</tr>
<tr>
  <td>Order Date:</td>
  <td><html:text property="orderDate"/></td>
</tr>
<tr>
<td><html:submit>Ok</html:submit></td>
<td><html:cancel>Cancel</html:cancel></td>
</tr>
</table>
</html:form>
</body>
</html>

You can invoke the action by directing your browser to this URL:

http://localhost:8080/app04a/displayAddOrderForm.do

Figure 4.1 shows the Add Order form in a browser.

Figure 4.1: The Order Form

When you submit the form, Struts will validate the form and, if validation is successful, calls the execute method on the SaveOrderAction object. The SaveOrderAction class is given in Listing 4.5. Notice how conversion is done to populate the OrderTO object from the action form’s properties.

Listing 4.5: The SaveOrderAction class

package app04a.action;
import app04a.form.OrderForm;
import app04a.to.OrderTO;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
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;

public class SaveOrderAction extends Action {
  public ActionForward execute(ActionMapping mapping,
    ActionForm form, HttpServletRequest request,
    HttpServletResponse response) throws Exception {

    OrderForm orderForm = (OrderForm) form;
    OrderTO order = new OrderTO();
    order.setProductId(orderForm.getProductId());
    order.setCustomer(orderForm.getCustomer());
    try {
      int quantity = Integer.parseInt(orderForm.getQuantity());
      order.setQuantity(quantity);
    }
    catch (NumberFormatException e) {
    }
    try {
      float price = Float.parseFloat(orderForm.getPrice());
      order.setPrice(price);
    }
      catch (NumberFormatException e) {
    }
    SimpleDateFormat dateFormatter = new SimpleDateFormat("MM/dd/yyyy");
    try {
      Date orderDate = dateFormatter.parse(orderForm.getOrderDate());
      order.setOrderDate(orderDate);
    }
    catch (ParseException e) {
    }

    // code for persisting the Order object goes here

    request.setAttribute("order", order);
    return (mapping.findForward("success"));
  }
}

Bear in mind that in app04a data conversion is done twice, once in the action form’s validate method and once in the action object. Note also, you have similar conversion code in both the action form and the action class.

Previous
Next