You can't use the standard Struts ActionForm class with the Validator. Instead, you need to use a subclass of the ActionForm class that is specifically designed to work with the Validator framework. There are two root subclasses to select from, depending on whether you are planning to use dynamic ActionForms. Figure 11-1 shows the ActionForm and its descendants, to help you visualize the hierarchy.
If you are using dynamic ActionForms, you should use the DynaValidatorForm branch of the hierarchy. If you are using standard ActionForms, you can use the ValidatorForm or one of its descendants instead.
|
Dynamic or standard is only the first decision that you have to make when choosing the proper ActionForm subclass. Notice that in both the dynamic and standard branch of the ActionForm hierarchy in Figure 11-1, there are two versions of ValidatorForm. The parent class is called ValidatorForm, or DynaValidatorForm for the dynamic branch.
Each of these has a subclass that contains the name Action in its title. The subclass of the ValidatorForm is called ValidatorActionForm , and the subclass of the DynaValidatorForm is called DynaValidatorActionForm . The purpose of the two different versions is to allow you to associate the validation with the form-bean definition or the action definition. The ValidatorActionForm and DynaValidatorActionForm classes pass the path attribute from the action element into the Validator, and the Validator uses the action's name to look up the validation rules. If you use the ValidatorForm or DynaValidatorForm, the name of the ActionForm is used to look up the set of validation rules to use. The only reason for using one or the other is to have more fine-grained control over which validation rules are executed.
For example, suppose that an ActionForm contains three different validation rules, but only two of them should get executed for a particular action. You could configure the rules to perform only the subset of validation rules when that action gets invoked. Otherwise, all of the rules would be invoked. In general, using ValidatorForm or DynaValidatorForm should be sufficient for your needs.
Let's look at a more complete example of using the Validator framework. As in previous chapters, we'll employ the Storefront application to help us understand the Validator better. In particular, we'll look at the HTML form used to capture the shipping information during checkout of the Storefront application. This is shown in Figure 11-2.
For this example, we are going to use a dynamic form. Therefore, we'll use the DynaValidatorForm class to capture the shipping address details. Because the checkout process will span multiple pages and we want to capture this information across pages, we will need to configure the form bean to have session scope. We will also capture all of the checkout properties in a single ActionForm class. Instead of having a ShippingForm and a CreditCardForm, we will have a single form called CheckoutForm that captures all of the information.
In our Struts configuration file, we set up the checkoutForm as shown here:
<form-bean
name="checkoutForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="firstName" type="java.lang.String"/>
<form-property name="lastName" type="java.lang.String"/>
<form-property name="address" type="java.lang.String"/>
<form-property name="city" type="java.lang.String"/>
<form-property name="state" type="java.lang.String"/>
<form-property name="postalCode" type="java.lang.String"/>
<form-property name="country" type="java.lang.String"/>
<form-property name="phone" type="java.lang.String"/>
</form-bean>
The type attribute specifies the exact ActionForm subclass.
|
The next step is to edit the application-specific validation logic, which is done in the validation.xml file. You must declare a validation rule for each property in the form that you need to validate. In some cases, you might need to specify multiple rules. In Figure 11-2, for example, the phone field is required, and it must fit a specific format. These are two separate rules that both must evaluate to true, or the validation for the form will fail. The entire validation.xml file is not shown because it's too large and most of it is redundant. The section shown in Example 11-2 will help you understand how things are connected.
<formset>
<constant>
<constant-name>phone</constant-name>
<constant-value>^\(?(\d{3})\)?[-| ]?(\d{3})[-| ]?(\d{4})$</constant-value>
</constant>
<constant>
<constant-name>zip</constant-name>
<constant-value>^\d{5}(-\d{4})?$</constant-value>
</constant>
<form name="checkoutForm">
<field
property="firstName"
depends="required,mask">
<arg0 key="label.firstName"/>
<var>
<var-name>mask</var-name>
<var-value>^[a-zA-Z]*$</var-value>
</var>
</field>
<field
property="postalCode"
depends="required,mask">
<arg0 key="registrationForm.zip"/>
<var>
<var-name>mask</var-name>
<var-value>${zip}</var-value>
</var>
</field>
<field
property="phone"
depends="required,mask">
<arg0 key="registrationForm.phone"/>
<var>
<var-name>mask</var-name>
<var-value>${phone}</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
Now that we have everything configured for the Storefront, it's time to run the example. The nice thing about using a declarative approach versus a programmatic one is that once you have everything configured, you're ready to go. The absence of programming makes the declarative approach much simpler. This is especially true for the Validator framework. There's nothing to code, as long as the default validation rules satisfy your requirements.
When we submit the shipping address page with no information in the fields, the validation rules kick in. The result is shown in Figure 11-3.