In most cases when a user enters data through a form, we want to ensure that the values entered are valid before the data is, for instance, stored in a database or used to determine the next action. Form validation is frequently done using client-side JavaScript. This approach is also possible in WebLogic Workshop. In addition, server-side validation checks the user input on the server side. The advantages of the latter approach:
WebLogic Workshop provides a number of attributes on the <netui:form> tag and its form fields, such as onClick and onBlur, which can be used to invoke JavaScript. For example, you can have a <netui:textBox> tag in which a user enters his age:
<netui:textBox dataSource="{actionForm.age}" onBlur="isValidAge()"/>
This is an example of the JavaScript function isValidAge which is mentioned in the onBlur attribute:
function isValidAge() { if(document.forms[0].elements[1].value <= 0) alert('Wrong Age'); }
After the user has entered a value and goes to the next form field, the onBlur attribute calls the JavaScript function isValidAge, which will display a dialog when the age is not considered valid.
Notice that in the example the form and its fields are accessed by using JavaScript forms and elements arrays. If you would like to use the id attributes to access the form and its fields, you need to (1) specify the tagID attributes on the <netui:form> and its input elements. Then use the JavaScript function getNetuiTagName(tagId, this). Also, you will need to ensure that the <html> tag is replaced with <netui:html> on the JSP page. Rewriting the previous example, the code will be:
<netui:html> ... <netui:form tagId="myForm" > <netui:textBox tagId="age" dataSource="{actionForm.age}" onBlur="isValidAge();"/> </netui:form> ... </netui:html>
And this would be the JavaScript function isValidAge:
function isValidAge() {
if(document.forms[getNetuiTagName("myForm",this)][getNetuiTagName("age",this)].value <= 0)
alert('Wrong Age');
}
Notice that instead of using elements[1], we refer to the element's tagID using the function getNetuiTagName( tagId, this ).
These approaches also work in conjunction with a submit action of the form. For <netui:button> and <netui:imageButton> tags, you can invoke the JavaScript function through the tags's onClick attribute, as is shown in the following example:
<netui:button value="submit" onClick="return isValidForm();" />
When a user clicks the button, a JavaScript function isValidForm checks the form fields and returns true if validation is successful. Or the isValidForm function displays a dialog with error messages and returns false if not all entered values are correct. (The implementation of this function is not actually shown in the sample code.)
For <netui:anchor> and <netui:imageAnchor> tags, whose implementation rely on JavaScript to submit a form, your JavaScript validation function must contain additional code to set the method and action properties of the JavaScript Form object, and call its submit method if validation is successful. The following example, which uses the same tagIDs and JavaScript function isValidForm as the previous example, demonstrates how to set the various properties and invoke the submit method when form validation is successful:
function submitFromAnchor() { document.forms[getNetuiTagName("myForm",this)].method="POST"; document.forms[getNetuiTagName("myForm",this)].action="/ClientSideValidation/thankYou.do"; if(isValidForm()) document.forms[getNetuiTagName("myForm",this)].submit(); }
As shown in the example, the form's method property must be set to POST. The action property must be set to the full name of the action to be called when the user clicks the anchor and submits the form. This action name corresponds to the web application name followed by the name of the action method in the JPF file, followed by a DO extension. In the example, the page flow JPF file of the web application ClientSideValidation contains an action method thankYou.
The same function could have been written without the use of getNetuiTagName( tagId, this ), as shown in the following example:
function submitFromAnchor() { document.forms[0].method="POST"; document.forms[0].action="/ClientSideValidation/thankYou.do"; if(isValidForm()) document.forms[0].submit(); }
However, if your application resides in a Portal application, it is recommended that you use getNetuiTagName(tagId, this) to retrieve page elements, since Portal containers may rewrite the id attributes of page elements. For details see Using JavaScript in Page Flow and Portal Applications.
Finally, the <netui:anchor> or <netui:imageAnchor> tags must call the JavaScript function in the onClick attribute and add "return false;" as is shown in the following example:
<netui:anchor onClick="submitFromAnchor(); return false;" action="thankYou">Submit</netui:anchor>
If you do not add the expression "return false;", the form will always be submitted and no data will be posted to the form bean.
For more information on using client-side JavaScript see Using JavaScript in Page Flow and Portal Applications.
WebLogic Workshop offers two ways to accomplish server-side validation, one using Java to implement the validate method in the form bean, and the other using the Struts ValidatorPlugIn to do XML-based validation. These examples are shown in the WebLogic Workshop sample application, and are described here. For the sample code, start in the following installed location:
<WEBLOGIC_HOME>/samples/workshop/SamplesApp/WebApp/validation/...
To validate user input using the form bean's validate method, follow the steps outlined in this list. Note that these examples are from the following sample page flow, and associated files:
<WEBLOGIC_HOME>/samples/workshop/SamplesApp/WebApp/validation/basic
/** * @jpf:controller nested="true" * @jpf:message-resources resources="validation.basic.Messages" *
*/ public class Controller extends PageFlowController { ...
The resources file is located under the web project's /WEB-INF/classes/... folder and has a properties extension. In the example above the Messages.properties file is located in /WEB-INF/classes/validation/basic. The contents of this file are described below.
Note: In the example, notice the corresponding naming requirements in use here. If the messages resource file is <project-root>/WEB-INF/classes/validation/basic/Messages.properties, then the way to reference this file in the <project-root>/validation/basic/*.jpf page flow annotation is @jpf:message-resources resources="validation.basic.Messages".
/** * @jpf:action * @jpf:forward name="success" path="success.jsp" * @jpf:validation-error-forward name="failure" return-to="currentPage" */ public Forward submitForm( Form form ) { return new Forward( "success" ); }
This annotation provides a flexible mechanism to indicate which page should be loaded, or which action should be run, if a form validation error occurs as a result of running the annotated action. For details see the @jpf:validation-error-forward Annotation topic.
The following Flow View screen illustrates the relationship of the actions and pages in this sample page flow.
public ActionErrors validate( ActionMapping mapping, HttpServletRequest request ) { ActionErrors errs = new ActionErrors();
int at = _email.indexOf( '@' ); int dot = _email.lastIndexOf( '.' );
if ( at == -1 || at == 0 || dot == -1 || at > dot ) { errs.add( "email", new ActionError( "badEmail" ) ); }
if ( _zipCode.length() != 5 ) { errs.add( "zipCode", new ActionError( "badZip", new Integer( 5 ) ) ); }
return errs; }
In the validate method you implement the validation logic for the various form fields. If there is an error, you add a new action error. In the example, zipCode refers to a <netui:error> tag in your JSP (<netui:error value="zipCode"/>), and badZip refers to the message key in the Messages.properties file. Note that the new Integer(5) is an object that is the first replacement in the error string. For example, later in this description you will see that we have a message string: "The zip code has to be exactly {0} characters." In this case, the {0} will be replaced by the Integer(5) object. ActionErrors supports constructors with up to four additional replacement objects.
For the full example, see the page flow controller class at <WEBLOGIC_HOME>/samples/workshop/SamplesApp/WebApp/validation/basic/Controller.jpf.
<netui:form action="submitForm">
<table>
<tr>
<td><p>Enter E-mail Address:</p></td>
<td>
<netui:textBox dataSource="{actionForm.email}"/>
</td>
<td>
<netui:error value="email"/>
</td>
</tr>
<tr>
<td><p>Enter 5-digit Zip Code:</p></td>
<td>
<netui:textBox dataSource="{actionForm.zipCode}"/>
</td>
<td>
<netui:error value="zipCode"/>
</td>
</tr>
</table>
<netui:button>Submit</netui:button> <netui:button action="exit">Exit</netui:button> </netui:form>
In the example an error will be displayed next to the relevant form field.
For the full example, see
<WEBLOGIC_HOME>/samples/workshop/SamplesApp/WebApp/struts/validation/basic/formPage.jsp.
badEmail=Bad email address. badZip=The zip code has to be exactly {0} characters.
errors.header=<br><hr><font color="Blue">List of errors, using the <netui:error> tag:<ul> errors.prefix=<li> errors.suffix= errors.footer=</ul></font>
error.prefix=<font color="Red"> error.suffix=</font>
Notice that in the example, badZip is the message key for the error message that needs to be displayed when an incorrect zipCode was entered. The other lines in the file create formatting for the <netui:error> and <netui:errors> tags, such that individual error messages are displayed in red and the error summary is displayed in blue as a list, preceded by the header "List of errors, using the <netui:error> tag:".
To validate user input using the Struts ValidatorPlugIn, follow the steps outlined in this list. Note that these examples are from the following sample page flow, and associated files:
<WEBLOGIC_HOME>/samples/workshop/SamplesApp/WebApp/validation/validator
/** * @jpf:controller nested="true" struts-merge="/WEB-INF/strutsValidator-merge-config.xml" * @jpf:message-resources resources="validation.validator.Messages" * */ public class Controller extends PageFlowController {
...
The @jpf:controller annotation's struts-merge attribute identifies the Struts merge file we will use. This Struts merge file will point to the Struts ValidatorPlugIn and its rules. The merge file is described later in this list.
Also, the resources file is located under the web project's /WEB-INF/classes/... folder and has a properties extension. In the example above the Messages.properties file is located in /WEB-INF/classes/validation/validator. Notice the corresponding naming requirements in use here. If the messages resource file is <project-root>/WEB-INF/classes/validation/validator/Messages.properties, then the way to reference this file in the <project-root>/validation/validator/*.jpf page flow annotation is @jpf:message-resources resources="validation.validator.Messages".
/** * @jpf:action * @jpf:validation-error-forward name="failure" return-to="currentPage" * @jpf:forward name="success" path="success.jsp" */ public Forward submitForm( MyForm form ) { return new Forward( "success" ); }
This annotation provides a flexible mechanism to indicate which page should be loaded, or which action should be run, if a form validation error occurs as a result of running the annotated action. For details see the @jpf:validation-error-forward Annotation topic.
public static class MyForm extends org.apache.struts.validator.ValidatorFormFor the full example of this form bean class, see <WEBLOGIC_HOME>/samples/workshop/SamplesApp/WebApp/validation/validator/Controller.jpf.
{
...
<netui:form action="submitForm">
<table>
<tr>
<td><p>Enter E-mail address:</p></td>
<td>
<netui:textBox dataSource="{actionForm.email}"/>
</td>
<td>
<netui:error value="email"/>
</td>
</tr>
<tr>
<td><p>Enter Age:</p></td>
<td>
<netui:textBox dataSource="{actionForm.age}"/>
</td>
<td>
<netui:error value="age"/>
</td>
</tr>
</table>
<netui:button>Submit</netui:button> <netui:button action="exit">Exit</netui:button> </netui:form>
In the example an error will be displayed next to the relevant form field. For the full example, see <WEBLOGIC_HOME>/samples/workshop/SamplesApp/WebApp/validation/validator/formPage.jsp.
<WEBLOGIC_HOME>/samples/workshop/SamplesApp/WebApp/WEB-INF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config> <form-beans/> <global-exceptions/> <global-forwards/> <action-mappings> </action-mappings>
<plug-in className="org.apache.struts.validator.ValidatorPlugIn"> <set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/strutsValidator-validation.xml"/> </plug-in>
</struts-config>
<form-validation>
<formset>
<form name="myForm">
<field property="email" depends="required">
<arg0 key="email.displayName"/>
</field>
<field property="age" depends="required,integer">
<arg0 key="age.displayName"/>
</field>
</form>
</formset>
</form-validation>
errors.header=<br><hr><font color="Blue">List of errors, using the <netui:error> tag:<ul>
errors.prefix=<li>
errors.suffix=
errors.footer=</ul></font>
error.prefix=<font color="Red"> error.suffix=</font>
errors.required={0} is required. errors.integer={0} must be an integer.
email.displayName=The email address age.displayName=The age
Notice that in the example, email.displayName describes the name of a form field, whereas errors.required describes the error message for missing but required form field entries. If a user does not type in an e-mail address, the resulting error message will be "The email address is required". The other lines in the file create formatting for the <netui:error> and <netui:errors> tags, such that individual error messages are displayed in red and the error summary is displayed in blue as a list, preceded by the header "List of errors, using <netui:error> tag:".
@jpf:validation-error-forward Annotation
@jpf:message-resources Annotation
Validating User Data with Struts Sample