Latest Entries »

Saturday, November 7, 2009

Niestandardowa konwersja i weryfikacja JavaServer Faces

Po poznaniu podstawowych konwerterów i weryfikatorów JSF-ów możemy przystąpić do trudniejszego zadania.
Jak wiadomo wszystko w Java jest obiektem. Właśnie w ten sposób wszystkie informacje są zapisywane na serwerze. Natomiast informacje, które są wyświetlane w oknie przeglądarki muszą być prezentowane jako napisy, listy i obrazy. Powoduje to potrzebę konwersji tych dwóch rodzajów informacji. Na początku zajmiemy się tworzeniem własnych klas implementujących interfejs javax.faces.convert.Converter, który posiada dwie metody:
public Object getAsObject(FacesContext context, UIComponent component, String value) {...}

public String getAsString(FacesContext context, UIComponent component, Object value) {...}

Pierwsza metoda naszej klasy konwertuje wpisaną wartość tekstową na obiekt dowolnej klasy gdy wysyłamy formularz na serwer, a druga metoda konwertuje wszystkie obiekty na postać łańcuchów i wysyła je do przeglądarki.
Utwórzmy następującą hierarchię klas:
public class ZipCode {
//Klasa reprezentuje kod pocztowy.
private String zip;
public ZipCode(String zip) {
this.zip = zip;
}

public String getZip() {
return zip;
}

public void setZip(String zip) {
this.zip = zip;
}

@Override
public String toString() {
return zip;
}
}
//Klasa imię użytkownika.
public class Name {
private String name;

Name(String value) {
this.name = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
//Klasa reprezentuje obiektowe nazwisko.
public class Surname {
private String surname;
public Surname(String surname) {
this.surname = surname;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
@Override
public String toString() {
return surname;
}
}
//Nasz Bean, który trzyma dane formularza:
public class RegistrationForm2 {
private Name name = new Name("");
private Surname surname = new Surname("");
private ZipCode zipCode = new ZipCode("");
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;

}
public Surname getSurname() {
return surname;
}
public void setSurname(Surname surname) {
this.surname = surname;
}
public ZipCode getZipCode() {
return zipCode;
}
public void setZipCode(ZipCode zipCode) {
this.zipCode = zipCode;
}
}
Teraz aby implementacja JSF wiedziała co zrobić z naszymi obiektami ZipCode,Name,Surname musimy pomóc i stworzyć odpowiednie klasy konwerterów np: ZipCodeConverter, NameConverter i SurnameConverter. Gdy konwersja się nie powiedzie powinniśmy wystosować odpowiedni wyjątek ConverterException().


//---------------------------------
import java.util.Locale;
import java.util.ResourceBundle;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;


/**
*
* @author riaa
*/
public class NameConverter implements Converter{

//Metoda konwertuje łańcuch z przeglądarki na obiekt typu Name.
public Object getAsObject(FacesContext context, UIComponent component, String value) {
//Jeżeli Name jest puste.
if (value.isEmpty())
{
//Pobieramy ustawienia lokalizacji użytkownika przeglądarki.
Locale L = context.getViewRoot().getLocale();
//Tworzymy obiekt, który ładuje klasy przy pomocy metod klasy Class
//a nie standardowo przez konstruktory.
ClassLoader loader = Thread.currentThread().getContextClassLoader();
//Pobieramy obiekt mymessages.properties przy pomocy
//statycznej metody: ResourceBundle.getBundle
ResourceBundle bundle = ResourceBundle.getBundle(context.getApplication().getMessageBundle(), L, loader);
//Wyszukujemy w pliku napisu o id = javax.faces.component.UIInput.REQUIRED.
String resource = bundle.getString("javax.faces.component.UIInput.REQUIRED");
//Tworzymy obiekt wyświetlany w ice:message zastępując znak {0}
// wartością id danej ice:inputText.
FacesMessage f = new FacesMessage(FacesMessage.SEVERITY_ERROR, resource.replace("{0}", component.getId()),
resource.replace("{0}", component.getId()));
throw new ConverterException(f);
}
//Jeżeli Name zawiera tylko litery.
if (value.matches("[A-Za-z]+"))
return new Name(value);
else
{
//Przypadek gdy ktoś w polu imię podał cyfrę.
//Ten sam sposób na na początku.
Locale L = context.getViewRoot().getLocale();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
ResourceBundle bundle = ResourceBundle.getBundle(context.getApplication().getMessageBundle(), L, loader);
String resource = bundle.getString("robpie.Name");
FacesMessage f = new FacesMessage(FacesMessage.SEVERITY_ERROR, resource.replace("{0}", component.getId()),
resource.replace("{0}", component.getId()));
throw new ConverterException(f);
}
}

public String getAsString(FacesContext context, UIComponent component, Object value) {
return value.toString();
}

}
//-----------------------------------------
import java.util.Locale;
import java.util.ResourceBundle;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;

/**
*
* @author riaa
*/
public class SurnameConverter implements Converter{

public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value.isEmpty())
{
Locale L = context.getViewRoot().getLocale();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
ResourceBundle bundle = ResourceBundle.getBundle(context.getApplication().getMessageBundle(), L, loader);
String resource = bundle.getString("javax.faces.component.UIInput.REQUIRED");
FacesMessage f = new FacesMessage(FacesMessage.SEVERITY_ERROR, resource.replace("{0}", component.getId()),
resource.replace("{0}", component.getId()));
throw new ConverterException(f);
}
if (value.matches("[A-Za-z]"))
{
return new Surname(value);
}
else
{
//Przypadek gdy ktoś w polu imię podał cyfrę.
Locale L = context.getViewRoot().getLocale();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
ResourceBundle bundle = ResourceBundle.getBundle(context.getApplication().getMessageBundle(), L, loader);
String resource = bundle.getString("robpie.Surname");
FacesMessage f = new FacesMessage(FacesMessage.SEVERITY_ERROR, resource.replace("{0}", component.getId()),
resource.replace("{0}", component.getId()));
throw new ConverterException(f);
}
}

public String getAsString(FacesContext context, UIComponent component, Object value) {
return value.toString();
}

}
//---------------------------------
import java.util.Locale;
import java.util.ResourceBundle;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;

/**
*
* @author riaa
*/
public class ZipCodeConverter implements Converter{

public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value.matches("[0-9][0-9][-][0-9][0-9][0-9]"))
return  new ZipCode(value);
else
{
Locale L = context.getViewRoot().getLocale();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
ResourceBundle bundle = ResourceBundle.getBundle(context.getApplication().getMessageBundle(), L, loader);
String resource = bundle.getString("robpie.ZipCode");
FacesMessage f = new FacesMessage(FacesMessage.SEVERITY_ERROR, resource, resource);
throw new ConverterException(f);
}
}

public String getAsString(FacesContext context, UIComponent component, Object value) {
return value.toString();
}
}
Teraz do każdej kontrolki dodajmy znacznik f:converter.:
<h:form prependId="false">
<table>
<tr>
<td>Imię:</td>
<td><ice:inputText id="name" value="#{registrationForm2.name}">
<f:converter converterId="NameConverter" />
<f:validateLength minimum="5" maximum="20" />
</ice:inputText></td>
<td><ice:message for="name" /></td>
</tr>
<tr>
<td>Nazwisko:</td>
<td><ice:inputText id="surname" value="#{registrationForm2.surname}" >
<f:validateLength minimum="5" maximum="20" />
</ice:inputText></td>
<td><ice:message for="surname" /></td>
</tr>
<tr>
<td>Kod pocztowy:</td>
<td><ice:inputText id="zipCode" value="#{registrationForm2.zipCode}" required="true">
<f:converter converterId="ZipConverter" />
</ice:inputText></td>
<td><ice:message for="zipCode" /></td>
</tr>
</table>
<ice:commandButton value="Dalej" action="registration2"/>
</h:form>

A na sam koniec musimy w pliku faces-config.xml dodać znacznik converter z odpowiednimi wpisami:

<converter>
<converter-id>ZipConverter</converter-id>
<converter-class>robpie.ZipCodeConverter</converter-class>
</converter>
<converter>
<converter-id>NameConverter</converter-id>
<converter-class>robpie.NameConverter</converter-class>
</converter>
<converter>
<converter-for-class>robpie.Surname</converter-for-class>
<converter-class>robpie.SurnameConverter</converter-class>
</converter>


Teraz spróbujmy przetestować formularz:

0 comments:

Post a Comment