| 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 |
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.