JEE6/JSF2.0 error messages, bean validation and i18n

With JEE6/JSF2.0, validation can be done by bean validation annotations. these annotations can be put on the JEE6 entity beans OR managed backing beans, as long as they conform to the Java Bean requirement, ie, providing getter and setter methods for instance variables.

 

Bean validation messages are i18n ready. To internationalize the validation messages, you need to provide the localized messages in a properties file "ValidationMessages.properties" and put it under the applications class path. For web applications, this would be "WEB-INF/classes". This is similar to JSF's i18n solution. But you don't need to configure it in "web.xml" or "faces-config.xml", since it's bean validation framework available to you automatically.

 

For example, if you want to support both English and Chinese for your bean validation, you can provide the messages in two files and put them under "WEB-INF/classes":

 

WEB-INF/classes/ValidationMessages.properties

WEB-INF/classes/ValidationMessages_zh.properties

 

Following is an example of ValidationMessages.properties :

bean.validate.username.required=username is required to login
bean.validate.nameFilter.required=name filter is required to search!
bean.validate.nameFilter.short=name filter too short, at least 3 chars

 

And the corresponding message for Chinese support from ValidationMessages_zh.properties :

bean.validate.username.required=\u7528\u6237\u540D\u662F\u5FC5\u987B\u5730\uFF01
bean.validate.nameFilter.required=\u540D\u5B57\u662F\u5FC5\u987B\u5730\uFF0C\u5A9A\u7EB8\uFF01
bean.validate.nameFilter.short=\u540D\u5B57\u592A\u77ED\u4E86\uFF0C\u81F3\u5C11 3 \u4E2A\u5B57\u7B26

 

Here's an exmple for JEE entity bean:

package com.jxee.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

/**
 * entity bean to table "test.user"
 * validation done here as well -- this is excellent!
 */
@Entity
@Table(name="USER", uniqueConstraints = @UniqueConstraint(columnNames = "username"))
public class User implements Serializable {
  
  @Id
  @GeneratedValue
  @Column(name="id")
  private Integer userid;
  
  @Column(name="username")
  // NotNull validation message are localized and defined in
  // ValidationMessages.properties/ValidationMessages_zh.properties
  @NotNull(message="{bean.validate.username.required}")
  // Size validation message is hard-coded here:
  @Size(min=4,max=20,message="username must be 4-20 characters")
  private String username;

  // other instance variables, getters and setters...

}
 

 

The following code illustrates how to use it in you bean class (the managed student search bean):

 

package com.jxee.action.student;

import java.io.Serializable;
import java.util.List;
import java.util.TimeZone;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.Flash;
import javax.inject.Inject;

// bean validation annotations
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.apache.log4j.Logger;

import com.jxee.ejb.student.StudentDAO;
import com.jxee.model.student.Student;

@ManagedBean(name="ss")
@ViewScoped
public class StudentSearchUseFlash implements Serializable {

  private static final Logger log = Logger.getLogger(StudentSearchUseFlash.class);
  private static final String SEARCH_PAGE = "/student/studentSearch.xhtml";
  
  private List<Student> searchResultList;
  private @EJB StudentDAO dao;

  // use bean validation to validate the search filter
  @NotNull(message="{bean.validate.nameFilter.required}")
  @Size(min=3, message="{bean.validate.nameFilter.short}")
  private String nameFilter;

  private int maxRows = 50;

  ......

} 

 

 

To display the localized bean validation message, you use <h:messages/>, <h:message for="inputId"/>, or Primefaces tags <p:messages/> and <p:message for="inputId"/>. This is standard JSF2.0 stuff, as illustrated here:

 

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
   				xmlns:h="http://java.sun.com/jsf/html"
      			xmlns:f="http://java.sun.com/jsf/core"
      			xmlns:ui="http://java.sun.com/jsf/facelets"
      			xmlns:p="http://primefaces.org/ui"
   				template="/template/template1.xhtml">
   				
	<ui:define name="title">#{msgs.studentSearch}</ui:define>
    
	<ui:define name="content">
		<h:form id="searchForm">
		    <p:panel header="#{msgs.studentSearch}" style="width:60%">
	        <h:panelGrid columns="4">
	            <h:outputLabel value="#{msgs.name}: "/>
	            <h:inputText id="nf" value="#{ss.nameFilter}"/>
	            <p:message for="nf"/>
	            <h:commandButton type="submit" value="#{msgs.search}" 
                                     action="#{ss.findByName}"/>
	        </h:panelGrid>
		    </p:panel>
		</h:form>
		    	
		......

         </ui:define>
</ui:composition>

 

Here's the screen shot for the student search screen, where it requires the name filter to be at 3 characters long:


JEE6/JSF2.0 error messages, bean validation and i18n

 

We can see that bean validation framework and JSF2 can work together pretty well.

 

One last thing to mention is how to localize a FacesMessage in my program? That is, how to access the i18n messages in backing beans? Since the i18n messages are handled as resource bundles, you need to reference it by the ResourceBundle class:

 

FacesContext cntxt = FacesContext.getCurrentInstance();
Locale locale = cntxt.getViewRoot().getLocale();
// load the i18n messages as resource bundle to access
// note: the base name must match the file path, ie, "/com/jxee/messages.properties"
ResourceBundle messages = ResourceBundle.getBundle("com.jxee.messages", locale);
String msg = messages.getString("nameFilterRequired");
log.debug("error message: " + msg);
cntxt.addMessage(null, new FacesMessage(msg));
 
 

This might be useful when it comes to cross-field validations. For single field vaidation, bean validation is handy and clean, thus much easier to use.

 

你可能感兴趣的:(validation)