06 października 2007

Konwertery w JavaServer Faces część 2

Aplikacja z pierwszej części artykułu o konwerterach w JavaServer Faces (JSF) - Konwertery w JavaServer Faces część 1 - korzystała z domyślnej konwersji dostarczanej przez implementację JSF. Wciskając przycisk Zatwierdź implementacja JSF wykonała konwersję wprowadzonego imienia pracownika do typu odpowiadającego typowi właściwości imie ziarna zarządzanego pracownik. Dla wielu typów konwersja wykonywana jest automatycznie, niezauważalnie dla programisty JSF.

W kolejnej części przedstawię wykorzystanie dostępnego w JSF konwertera między typem znakowym a typem kalendarzowym (datą).

Rozpocznę od dodania nowej właściwości zatrudnionyOd w ziarnie pracownik typu java.util.Date.

package pl.jaceklaskowski.konwerter;

import java.util.Date;

public class Pracownik {

private long numer;
private String imie;
private Date zatrudnionyOd;

public Pracownik() {
}

public Pracownik(long numer, String imie, Date zatrudnionyOd) {
this.numer = numer;
this.imie = imie;
this.zatrudnionyOd = zatrudnionyOd;
}

public long getNumer() {
return numer;
}

public void setNumer(long numer) {
this.numer = numer;
}

public String getImie() {
return imie;
}

public void setImie(String imie) {
System.out.println("setImie(" + imie + ")");
this.imie = imie;
}

public Date getZatrudnionyOd() {
return zatrudnionyOd;
}

public void setZatrudnionyOd(Date zatrudnionyOd) {
System.out.println("setZatrudnionyOd(" + zatrudnionyOd + ")");
this.zatrudnionyOd = zatrudnionyOd;
}
}

Kolejna zmiana polegała będzie na dodaniu pola, w którym użytkownik będzie wprowadzał datę zatrudnienia pracownika. Strona o nazwie strona2.jsp będzie od tej pory stroną startową aplikacji. Dodałem również kontrolkę h:messages, aby wyświetlane były komunikaty błędów, jeśli takie wystąpią.

<%@page contentType="text/html" pageEncoding="UTF-8"%>

<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Mini-aplikacja JSF - konwerter</title>
</head>
<body>
<f:view>
<h:form>
Podaj imię pracownika <h:inputText value="#{pracownik.imie}" />
<br>
Zatrudniony od
<h:inputText value="#{pracownik.zatrudnionyOd}" />
<br/>
<h:commandButton value="Zatwierdź" />
<br/>
<h:messages showSummary="true" />
</h:form>
</f:view>
</body>
</html>

Uruchomienie aplikacji i zatwierdzenie wprowadzonej daty przez wciśnięcie przycisku Zatwierdź spowoduje wyświetlenie strony z błędem Conversion Error setting value '06.10.2007' for 'null Converter'.

Ten niezrozumiały komunikat tłumaczy się jako brak konwertera między typami znakowym a kalendarzowym. Rozwiązaniem polega na dodaniu konwertera, który jest dostarczany przez JSF - f:convertDateTime. Konwertery działają w ramach kontrolki, w której zostały zdefiniowane, więc związanie konwertera f:convertDateTime wykonane jest przez umieszczenie go w ramach kontrolki h:inputText, dla której będzie wywołany podczas stadiów rozwojowych - ustawienie wartości zlecenia oraz wyświetlenie odpowiedzi.

Konwerter f:convertDateTime udostępnia atrybuty, dzięki którym można kontrolować konwersję, m.in. style daty dateStyle i czasu timeStyle, ustawień regionalnych (ang. locale) - locale oraz wzorzec pattern.

<%@page contentType="text/html" pageEncoding="UTF-8"%>

<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Mini-aplikacja JSF - konwerter</title>
</head>
<body>
<f:view>
<h:form>
Podaj imię pracownika <h:inputText id="imie" value="#{pracownik.imie}" />
<h:message for="imie" errorStyle="color: red"/>
<br>
Zatrudniony od
<h:inputText id="zatrudnionyOd" value="#{pracownik.zatrudnionyOd}">
<f:convertDateTime dateStyle="short" pattern="dd.MM.yyyy"/>
</h:inputText>
(format: dd.MM.yyyy)
<h:message for="zatrudnionyOd" errorStyle="color: red"/>
<br/>
<h:commandButton value="Zatwierdź" />
<br/>
<h:messages showSummary="true" errorStyle="color: red" />
</h:form>
</f:view>
</body>
</html>

Zatwierdzenie poprawnej daty, np. 06.10.2007 nie spowoduje już wyświetlenia błędu

Na konsoli serwera aplikacji można zauważyć następujące komunikaty:

deployed with moduleid = konwerter
Initializing Sun's JavaServer Faces implementation (1.2_04-b20-p03) for context '/konwerter'
setImie(Jacek)
setZatrudnionyOd(Sat Oct 06 00:00:00 CEST 2007)

Na stronie strona2.jsp użyłem kilka ciekawostek JSF - atrybut id w kontrolkach h:inputText oraz związałem z nimi dedykowane kontrolki h:message, które wyświetlają komunikaty błędu dla pojedyńczej kontrolki JSF wskazanej przez atrybut for. Wpisanie niepoprawnej daty lub użycie niepoprawnego formatu daty spowoduje wyświetlenie komunikatu błędu w kolorze czerwonym obok kontrolki h:inputText, którego komunikat błędu dotyczy.

Warto również zauważyć, że ziarno pracownik nie zostanie w ogóle wywołane, właśnie ze względu na błędy danych. Jest to kolejne ułatwienie przy tworzeniu aplikacji, które dostarcza JSF.

Pozostaje uzupełnić przykład o zapewnienie, że imię i data zatrudnienia zostaną faktycznie wprowadzone przez użytkownika oraz zmodyfikowanie komunikatu błędu, który nie zawierałby identyfikatorów pól, np. j_id_id15:zatrudnionyOd, a ich przyjemniejsze dla użytkownika odpowiedniki jak i sam komunikat błędu zależny od języka użytkownika. Odpowiedzi w postaci komentarzy do notatki mile widziane.

Gotowy projekt aplikacji Konwerter dostępny jest jako jsf-konwerter-czesc2.zip.