|
Recipe 8.7. Validating Field Equality with a Custom ValidatorProblemYou want to create a reusable validator in Struts 1.1 that can validate that the value of one field is equal to the value of another. SolutionUse Matt Raible's TwoFields custom validator. Start by creating a class with a static method that implements the rule, as shown in Example 8-9. Example 8-9. TwoFields validation rule classpackage com.oreilly.strutsckbk.ch08; import javax.servlet.http.HttpServletRequest; import org.apache.commons.validator.Field; import org.apache.commons.validator.GenericValidator; import org.apache.commons.validator.ValidatorAction; import org.apache.commons.validator.util.ValidatorUtils; import org.apache.struts.action.ActionErrors; import org.apache.struts.validator.Resources; public class CustomValidatorRules { public static boolean validateTwoFields( Object bean, ValidatorAction va, Field field, ActionErrors errors, HttpServletRequest request ) { String value = ValidatorUtils.getValueAsString(bean, field. getProperty( )); String sProperty2 = field.getVarValue("secondProperty"); String value2 = ValidatorUtils.getValueAsString(bean, sProperty2); if (!GenericValidator.isBlankOrNull(value)) { try { if (!value.equals(value2)) { errors.add( field.getKey( ), Resources.getActionError(request, va, field)); return false; } } catch (Exception e) { errors.add( field.getKey( ), Resources.getActionError(request, va, field)); return false; } } return true; } } Next, add the following validator element, shown in Example 8-10, as a sub-element of the global element in the validator-rules.xml file. Example 8-10. TwoFields validator rule<validator name="twofields" classname="com.oreilly.strutsckbk.ch08.CustomValidatorRules" method="validateTwoFields" methodParams="java.lang.Object, org.apache.commons.validator.ValidatorAction, org.apache.commons.validator.Field, org.apache.struts.action.ActionErrors, javax.servlet.http.HttpServletRequest" depends="required" msg="errors.twofields"> <javascript><![CDATA[ function validateTwoFields(form) { var bValid = true; var focusField = null; var i = 0; var fields = new Array( ); oTwoFields = new twofields( ); for (x in oTwoFields) { var field = form[oTwoFields[x][0]]; var secondField = form[oTwoFields[x][2]("secondProperty")]; if (field.type == 'text' || field.type == 'textarea' || field.type == 'select-one' || field.type == 'radio' || field.type == 'password') { var value; var secondValue; // get field's value if (field.type == "select-one") { var si = field.selectedIndex; value = field.options[si].value; secondValue = secondField.options[si].value; } else { value = field.value; secondValue = secondField.value; } if (value != secondValue) { if (i == 0) { focusField = field; } fields[i++] = oTwoFields[x][1]; bValid = false; } } } if (fields.length > 0) { focusField.focus( ); alert(fields.join('\n')); } return bValid; }]]></javascript> </validator> Next, add an error message with the key of errors.twofields to your applications MessageResources properties file: errors.twofields={0} must be equal to {1}. To use the TwoFields validator, in your validation.xml file change the field element for one of the related fields to be dependent on the twofields rule. In Example 8-11, the password2 field must be equal to the password field for the validation of password2 to succeed. Example 8-11. Applying the TwoFields rule<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation//DTD Commons Validator Rules Configuration "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd"> <form-validation> <formset> <form name="RegistrationForm"> <field property="emailAddress" depends="required,email"> <arg0 key="prompt.emailAddress"/> </field> <field property="password" depends="required"> <arg0 key="prompt.password"/> </field> <field property="password2" depends="required,twofields"> <arg0 key="prompt.password2"/> <arg1 key="prompt.password"/> <var> <var-name>secondProperty</var-name> <var-value>password</var-value> </var> </field> </form> </formset> </form-validation> DiscussionThis recipe provides a solution for checking field equality and shows you how to create a custom validator. It's easier than you might suppose. You implement a custom validator as a static method of a class of your choosing. By convention, the method should be named validatorRuleName. The precise method signature when developing under Struts 1.1 is the following: public static boolean validateRuleName( Object bean, ValidatorAction va, Field field, ActionErrors errors, HttpServletRequest request) This method returns a boolean, which indicates if the validation passes (true) or fails (false). Table 8-1 describes the method arguments and how they are used.
The implementation of the TwoFields rule does the following:
Once you have the Java coded for the validator, you need to link the implementation to the Validator by creating a validator element in the validator-rules.xml file. Here's the validator element used for TwoFields: <validator name="twofields" classname="com.oreilly.strutsckbk.ch08.CustomValidatorRules" method="validateTwoFields" methodParams="java.lang.Object, org.apache.commons.validator.ValidatorAction, org.apache.commons.validator.Field, org.apache.struts.action.ActionErrors, javax.servlet.http.HttpServletRequest" depends="required" msg="errors.twofields"> The name attribute specifies the name that you'll use to refer to the validator wherever it's applied. The classname, method, and methodParams attributes are used by the Validator to determine the class and method to call. If you are using Struts 1.2, be sure to change ActionErrors to ActionMessages. The depends attribute specifies other rules triggered before this rule is fired. For the twofields rule, you need to validate the field if there's a value for it. You can enforce this by setting depends to required. The last attribute, msg, identifies the MessageResources key of the default error message used by this rule. This value can be overridden when the rule is applied. The TwoFields rule shown in Example 8-10 includes JavaScript for client-side validation. For a Validator rule, you enclose the JavaScript code in a CDATA section of the javascript element nested in the validator element: <validator name="twofields" ... <javascript> <![CDATA[ function validateTwoFields(form) { var bValid = true; // body of the JavaScript function ... return bValid; }]]> </javascript> </validator> The JavaScript function, like the Java method name, should be named using the validateRuleName convention. The function must return a boolean value that indicates if the validation rule passes (true) or fails (false).
The last piece of the puzzle (whew!) is to apply the rule to a specific form field: <field property="password2" depends="twofields"> <arg0 key="prompt.password2"/> <arg1 key="prompt.password"/> <var> <var-name>secondProperty</var-name> <var-value>password</var-value> </var> </field> The arg0 and arg1 values specify the message resource keys for the labels of the two fields. These values are substituted into the error message if the validation fails. The var element specifies the name of the second field. This value doesn't necessarily have to be a field on the form (though in this case it probably would be); it can be any JavaBean property on the ActionForm. See AlsoIf you are using Struts 1.2, an easier solution is discussed in Recipe 8.8. The TwoFields validator was originally presented on Matt Raible's weblog. It can be found on his site at http://www.raibledesigns.com/page/rd/20030226. The Validator User's Guide discusses custom Validators in the section found at http://struts.apache.org/userGuide/dev_validator.html#plugs. The Recipe 8.9 presents a custom Validator for Struts 1.2 that you may want to read up on as well. |
|