JSF comes with some basic built-in validators, but it allows for new, custom ones, to be added by the developer.
Built-in validators
The following validators are available out of the box:
• f:validateDoubleRange: Checks whether a numeric input (convertible to double) is within a specified range.
• f:validateLength: Checks if the string input length is within a given range.
• f:validateLongRange: Checks whether a numeric input (convertible to long) is within a given range.
In order to be used, a validator needs to be nested into an h:input component that requires it.
To dictate the boundaries of the acceptable range, you need to specify the values for the minimum and/or maximum attributes to each of these validators.
Let's exemplify this. Assume we were creating an application that calculates monthly rates for the chosen loan. The client is expected to input the number of months they require the loan for, but our application does not allows this to be less than 6 or greater than 120 (or 10 years).
If we had a backing bean called loansManager and, within it, a HtmlInputText field, the component we would use would look like this:
<h:inputText id="account" required="true"
binding="#{loansManager.client.accountNumber}"
requiredMessage="Value is required!">
<f:validator validatorId="AccountNumberValidator"/>
</h:inputText>
Custom validators
If you need validation beyond the scope of the afore mentioned built-in components, you will have to write a custom validator to take care of your requirements.
You have two options here, to create a validator class or to create a validator method in one of your backing beans.
The first approach means implementing the Validator interface and it's validate method.
This time assume our application expects the client to input his account number in form ***.*******.**, where each * represents one character (probably should be a digit, but let's keep it simple).
The implementing class would then look like this:
package loans.validators;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
public class AccountNumberValidator implements Validator {
public AccountNumberValidator() {
}
public void validate(FacesContext ctxt, UIComponent cmp, Object val) {
String message = null;
try {
String[] parts = ((String)val).split("-");
if (parts.length < 3)
message = "Wrong account number!";
else {
if (parts[0].length() != 3 || parts[1].length() != 7 || parts[2].length() != 2)
message = "Wrong account number!";
}
} catch (Exception e){}
if (message != null) {
FacesMessage msg = new FacesMessage(
FacesMessage.SEVERITY_ERROR, message, message);
throw new ValidatorException(msg);
}
}
}
To register this validator, you would have to add the following snippet to your faces-config.xml file:
<validator>
<validator-id>AccountNumberValidator</validator-id>
<validator-class>loans.validators.AccountNumberValidator</validator-class>
</validator>
Now, you can add your validator to any h:input component that requires it.
For example:
<h:inputText id="account" required="true"
binding="#{loansManager.client.accountNumber}"
requiredMessage="Value is required!">
<f:validator validatorId="AccountNumberValidator"/>
</h:inputText>
The second option, mentioned earlier, is writing a validator method instead. For this, we would make a validateAccountNumber method in our loansManager backing bean. The method should look like this:
public void validateAccountNumber(FacesContext ctxt, UIComponent cmp, Object val) {
String message = null;
try {
String[] parts = ((String)val).split("-");
if (parts.length < 3)
message = "Wrong account number!";
else {
if (parts[0].length() != 3 || parts[1].length() != 7 || parts[2].length() != 2)
message = "Wrong account number!";
}
} catch (Exception e){}
if (message != null) {
FacesMessage msg = new FacesMessage(
FacesMessage.SEVERITY_ERROR, message, message);
ctxt.addMessage(cmp.getClientId(ctxt), mess);
}
}
Note that this time, instead of throwing a validator exception, we're manually adding a message the FacesContext's queue. In the previous example this was done automatically.
To use this new validator, you would add it to your h:input component like this:
<h:inputText id="account" required="true"
binding="#{loansManager.client.accountNumber}"
validator="#{loansManager.validateAccountNumber}"
requiredMessage="Value is required!"/>
Note:
You might as well do validation anywhere inside your application and just add the message to the FacesContext in the same manner you've seen earlier, but this has one important constraint. In place of cmp.getClientId(ctxt) inside
ctxt.addMessage(cmp.getClientId(ctxt), msg);
you would have to hard code the component id:
ctxt.addMessage("account", msg);
since you no longer have the reference to the component itself.
Also, you might put a global message (not bound to any component) into a FacesContext message queue with
ctxt.addMessage(null, msg);
but these messages can only be displayed with <h:messages/> element.
No comments:
Post a Comment