Ce contenu n'est pas disponible dans la langue sélectionnée.

Chapter 11. JSF form validation in Seam


In plain JSF, validation is defined in the view:
<h:form>
  <h:messages/>

  <div>
    Country:
    <h:inputText value="#{location.country}" required="true">
      <my:validateCountry/>
    </h:inputText>
  </div>
    
  <div>
    Zip code:
    <h:inputText value="#{location.zip}" required="true">
      <my:validateZip/>
    </h:inputText>
  </div>

  <h:commandButton/>
</h:form>
Copy to Clipboard Toggle word wrap
In practice, this approach usually violates DRY, since most "validation" actually enforces constraints that are part of the data model, and exist all the way down to the database schema definition. Seam provides support for model-based constraints defined with Hibernate Validator.
We will begin by defining our constraints, on our Location class:
public class Location {
    private String country;
    private String zip;
  
    @NotNull
    @Length(max=30)
    public String getCountry() { return country; }
    public void setCountry(String c) { country = c; }

    @NotNull
    @Length(max=6)
    @Pattern("^\d*$")
    public String getZip() { return zip; }
    public void setZip(String z) { zip = z; }
}
Copy to Clipboard Toggle word wrap
In practice, it may be more elegant to use custom constraints rather than those built into Hibernate Validator:
public class Location {
    private String country;
    private String zip;
  
    @NotNull
    @Country
    public String getCountry() { return country; }
    public void setCountry(String c) { country = c; }

    @NotNull
    @ZipCode
    public String getZip() { return zip; }
    public void setZip(String z) { zip = z; }
}
Copy to Clipboard Toggle word wrap
Whichever method we choose, we no longer need specify the validation type to be used in the JSF page. Instead, we use <s:validate> to validate against the constraint defined on the model object.
<h:form>
  <h:messages/>

  <div>
    Country:
    <h:inputText value="#{location.country}" required="true">
      <s:validate/>
    </h:inputText>
  </div>
  
  <div>
    Zip code:
    <h:inputText value="#{location.zip}" required="true">
      <s:validate/>
    </h:inputText>
  </div>
  
  <h:commandButton/>

</h:form>
Copy to Clipboard Toggle word wrap

Note

Specifying @NotNull on the model does not eliminate the need for required="true" to appear on the control. This is a limitation of the JSF validation architecture.
This approach defines constraints on the model, and presents constraint violations in the view.
The design is better, but not much less verbose than our initial design. Now, we will use <s:validateAll>:
h:form>
    
  <h:messages/>

  <s:validateAll>

  <div>
    Country:
    <h:inputText value="#{location.country}" required="true"/>
  </div>

  <div>
    Zip code:
    <h:inputText value="#{location.zip}" required="true"/>
  </div>

  <h:commandButton/>

  </s:validateAll>

</h:form>
Copy to Clipboard Toggle word wrap
This tag adds an <s:validate> to every input in the form. In a large form, this can save a lot of typing.
Next, we need to display feedback to the user when validation fails. Currently, all messages are displayed at the top of the form. To correlate the message with an input, you must define a label by using the standard label attribute on the input component.
<h:inputText value="#{location.zip}" required="true" label="Zip:"> 
  <s:validate/> 
</h:inputText>
Copy to Clipboard Toggle word wrap
Inject this value into the message string with the placeholder {0} (the first and only parameter passed to a JSF message for a Hiberate Validator restriction). See the internationalization section for more information on where to define these messages.

Note

validator.length={0} length must be between {min} and {max}
We would prefer the message to be displayed beside the field with the error, highlight the field and label, and display an image next to the field. In plain JSF, only the first is possible. We also want to display a coloured asterisk beside the label of each required form field.
This is a lot of functionality for each field. We do not want to specify highlighting and the layout of the image, message, and input field for every field on the form, so we specify the layout in a facelets template:
ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:s="http://jboss.com/products/seam/taglib">           
  <div>
  
    <s:label styleClass="#{invalid?'error':''}">
      <ui:insert name="label"/>
      <s:span styleClass="required" rendered="#{required}">*</s:span>
    </s:label>
        
    <span class="#{invalid?'error':''}">
      <h:graphicImage value="/img/error.gif" rendered="#{invalid}"/>
      <s:validateAll>
        <ui:insert/>
      </s:validateAll>
    </span>
        
    <s:message styleClass="error"/>
        
  </div>
    
</ui:composition>
Copy to Clipboard Toggle word wrap
We can include this template for each of our form fields by using <s:decorate>:
<h:form>
  <h:messages globalOnly="true"/>

    <s:decorate template="edit.xhtml">
        <ui:define name="label">Country:</ui:define>
        <h:inputText value="#{location.country}" required="true"/>
    </s:decorate>
    
    <s:decorate template="edit.xhtml">
        <ui:define name="label">Zip code:</ui:define>
        <h:inputText value="#{location.zip}" required="true"/>
    </s:decorate>

    <h:commandButton/>

</h:form>
Copy to Clipboard Toggle word wrap
Finally, we can use RichFaces Ajax to display validation messages while the user navigates around the form:
<h:form>
  <h:messages globalOnly="true"/>

    <s:decorate id="countryDecoration" template="edit.xhtml">
        <ui:define name="label">Country:</ui:define>
        <h:inputText value="#{location.country}" required="true">
            <a:support event="onblur" reRender="countryDecoration" 
                       bypassUpdates="true"/>
        </h:inputText>
    </s:decorate>
    
    <s:decorate id="zipDecoration" template="edit.xhtml">
        <ui:define name="label">Zip code:</ui:define>
        <h:inputText value="#{location.zip}" required="true">
            <a:support event="onblur" reRender="zipDecoration" 
                       bypassUpdates="true"/>
        </h:inputText>
    </s:decorate>

    <h:commandButton/>

</h:form>
Copy to Clipboard Toggle word wrap
Stylistically, it is better to define explicit IDs for important page controls, particularly if you want automated UI testing. If explicit IDs are not provided, JSF will generate its own — but they will not remain static if anything on the page is changed.
<h:form id="form">
  <h:messages globalOnly="true"/>

    <s:decorate id="countryDecoration" template="edit.xhtml">
    <ui:define name="label">Country:</ui:define>
      <h:inputText id="country" value="#{location.country}" 
                   required="true">
        <a:support event="onblur" reRender="countryDecoration" 
                   bypassUpdates="true"/>
      </h:inputText>
    </s:decorate>
    
    <s:decorate id="zipDecoration" template="edit.xhtml">
      <ui:define name="label">Zip code:</ui:define>
      <h:inputText id="zip" value="#{location.zip}" required="true">
        <a:support event="onblur" reRender="zipDecoration" 
                   bypassUpdates="true"/>
      </h:inputText>
    </s:decorate>

    <h:commandButton/>

</h:form>
Copy to Clipboard Toggle word wrap
If you want to specify a different message to be displayed when validation fails, you can use the Seam message bundle with the Hibernate Validator:
public class Location {
    private String name;
    private String zip;
  
    // Getters and setters for name

    @NotNull
    @Length(max=6)
    @ZipCode(message="#{messages['location.zipCode.invalid']}")
    public String getZip() { return zip; }
    public void setZip(String z) { zip = z; }
}
Copy to Clipboard Toggle word wrap
 location.zipCode.invalid = The zip code is not valid for #{location.name}
Copy to Clipboard Toggle word wrap
Retour au début
Red Hat logoGithubredditYoutubeTwitter

Apprendre

Essayez, achetez et vendez

Communautés

À propos de la documentation Red Hat

Nous aidons les utilisateurs de Red Hat à innover et à atteindre leurs objectifs grâce à nos produits et services avec un contenu auquel ils peuvent faire confiance. Découvrez nos récentes mises à jour.

Rendre l’open source plus inclusif

Red Hat s'engage à remplacer le langage problématique dans notre code, notre documentation et nos propriétés Web. Pour plus de détails, consultez le Blog Red Hat.

À propos de Red Hat

Nous proposons des solutions renforcées qui facilitent le travail des entreprises sur plusieurs plates-formes et environnements, du centre de données central à la périphérie du réseau.

Theme

© 2025 Red Hat