
Jakarta Server Faces – facelets
Jakarta Server Faces to framework, który pomaga tworzyć aplikacje webowe. JSF znacznie ułatwia tworzenie interfejsu użytkownika przez dostarczenie wielu gotowych, opracowanych wcześniej komponentów oraz specyfikacji. Przykładem może być połączenie interfejsu z obsługą zdarzeń, walidacją danych wprowadzanych przez użytkownika.
Jakie korzyści daje framework JSF?
Dobrą praktyką podczas tworzenia dowolnego projektu jest rozdzielność warstw prezentacji od obsługi zdarzeń oraz logiki programu. Ułatwia to znacznie ewentualne zmiany w dowolnej części programu, ale także znalezienie ewentualnych błędów. JSF pomaga tworzyć aplikacje korzystając z tego wzorca.
Główna zaletą JSF jest zmniejszenie potrzebnej pracy podczas tworzenia aplikacji. JSF znacznie ułatwia transfer danych między komponentami oraz walidację danych wpisywanych przez użytkownika po stronie serwera. JSF zawiera wiele wcześniej przygotowanych komponentów gotowych do umieszczenia. Każdy z nich można rozszerzyć i stworzyć własny z nowymi funkcjonalnościami. Komponentami są zarówno proste elementy jak użyte przez nas ostatnio pola tekstowe jak i bardziej złożone konstrukcje. Możliwe jest wielokrotne użycie dowolnych komponentów.
Kolejną zaletą jest obsługa przechwytywania zdarzeń, czyli np. kliknięcie użytkownika w przycisk, a tym samym przesłanie danych do serwera z formularza.
Co to jest facelet?
W innym wpisie opisywaliśmy Java Server Pages jako sposób prezentacji. Wraz z JSF 2.0 dostaliśmy nowe narzędzie – facelety. Jest to technologia bazująca na języku XML, gdyż do utworzenia strony niezbędne jest użycie plików XHTML.
Podobnie jak w przypadku stron JSP, również i tu możemy korzystać z biblioteki JSTL. Oprócz tego facelet dostarcza dodatkowy zbiór własnych tagów.
Niektóre serwery takie jak Glasfish, Jetty, TomEE Plume zawierają od razu implementacje JSF/Facelet, natomiast gdy serwer nie go posiada, to należy ściągnąć jedną z dostępnych implementacji. MyFaces od Apache lub Mojarra od Oracle.
Standardowe komponenty HTML
W JSF można używać standardowych komponentów z HTML. Aby móc to zrobić należy podać przestrzeń nazw.
1 2 |
<html xmlns = "http://www.w3.org/1999/xhtml" xmlns:h = "http://java.sun.com/jsf/html"> |
Szablony Interfejsu użytkownika (Facelets Templates)
Facelets udostępnia bardzo wygodny element, który umożliwia tworzenie szablonów, które można wykorzystać wielokrotnie w danej aplikacji. Przykładami mogą być elementy, które w serwisie www występują na każdej stronie, takich jak nagłówki lub stopki. Jest to jedna z dobrych praktyk programowania czyli tzw. ponownie użycie kodu.
Istotną zaletą używania szablonów jest łatwiejsze utrzymanie serwisu www, gdyż wystarczy podmienić element w jednym miejscu, aby zmienił się wygląd w całej aplikacji.
Aby użyć komponentów UI należy najpierw dodać przestrzeń nazw na początku dokumentu.
1 2 |
<html xmlns = "http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"> |
Poniżej znajduje się kilka tagów udostępnionych przez facelets.
ui:composition
– definiuje elementy, które zostaną umieszczone na stronie.
ui:include
– oznacza stronę xhtml, którą należy wstawić do innej strony. Przykładem może być wstawienie nagłówka na stronie głównej.
ui:define
– oznacza zawartość do umieszczenia na stronie przez szablon.
ui:insert
– przenosi zawartość do szablonu.
Budowanie komponentów
Ten sam komponent możemy przedstawić na różne sposoby. Funkcjonalność pozostaje taka same, jednakże w zależności od sytuacji wygodniejsze może być inne odwzorowanie menu. Przykładem jest pole wyboru jednokrotnego. Wygodna może być lista z wyborem, jednakże przy wyborze z kilkudziesięciu opcji lepiej będzie użyć wysuwanej listy. Dzięki JSF możemy utworzyć własny komponent, który można później wykorzystać.
Konwersja typów
Każdy komponent reprezentuje dany typ. Dzięki wykorzystaniu frameworka JSF można w prosty sposób wykorzystać dane wpisane przez użytkownika do sekcji związanej z logiką programu. Domyślnie możliwa jest zmiana pobranych łańcuchów znakowych na liczby oraz daty.
JSF dostarcza do tego tagi:
1 2 |
<f:convertNumber/> <f:convertDateTime/> |
W obu tagach można użyć dodatkowych atrybutów. Poniżej znajduje się ich spis.
Konwersja dat – atrybuty:
type
– określa czy w łańcuchu znajduje się wyłącznie data, godzina czy też obie wartości. Domyślnym parametrem jest data. Możliwe jest podanie parametrów „date”, „time”, „both”.
pattern
– własny, sformatowany wzorzec, który określa w jaki sposób mamy podany łańcuch znakowy np. dd-mm-yyyy. W przypadku jego użycia atrybuty dateStyle, timeStyle, and type są ignorowane.
datestyle
– określa sposób wyświetlania daty. Możliwe wartości to: default, short, medium, long, or full
timestyle
– określa sposób wyświetlania godziny. Możliwe wartości to: default, short, medium, long, or full
locale
– określa czy data ma być przedstawiana wg wzorca z danego kraju np. Polski.
Timezone
– strefa czasowa.
Konwersja liczb – atrybuty:
type
– określa czy w łańcuchu przekazujemy liczbę, walutę, czy też procenty. Domyślną wartością jest liczba. Możliwe do wskazania są number, currency, or percentage.
pattern
– własny wzór formatowania liczb. Całość opisano w dokumentacji. W tym celu używa się znaków 0 – cyfra # – cyfra, ale nie pokazuje zer wiodących lub na końcu ułamka , – separator grupujący . – separator dziesiętny % – mnoży wartość przez 100 i pokazuje ją ze znacznie procenta.
integersonly
– usuwa część ułamkową z podanej wartości. (true, false)
maxintegerdigit
– maksymalna liczba cyfr w części całkowitej.
minintegerdigit
– minimalna liczba cyfr w części całkowitej.
maxFractionPart
– maksymalna liczba cyfr w części ułamkowej.
minFractionPart
– minimalna liczba cyfr w części ułamkowej.
Konwersja liczb type=currency – atrybuty
Currencysymbol
– symbol waluty np. „$”, „\u00A5”
Currencycode
– kod waluty używany w międzynarodowym standardzie ISO 4217.
Przechwytywania zdarzeń
Framework JSF upraszcza obsługę przechwytywania zdarzeń takich jak kliknięcie użytkownika w przycisk, zmianę wartości jakiegoś pola itd. W tym celu należy zaimplementować klasę tzw. listenera.
Walidacji danych
Dane wprowadzane przez użytkownika powinny być odpowiednio sprawdzane zanim użyjemy je w dalszym przetwarzaniu. Framework JSF wspiera ten mechanizm przez wstępne zdefiniowanie różnych atrybutów. Możemy ustawić np. minimalną lub maksymalną wartość parametru. Nic nie stoi na przeszkodzie, aby samemu zdefiniować własny walidator.
Poniżej znajduje się lista zdefiniowanych walidatorów.
<f:validateLength />
– sprawdza długość wprowadzonego łańcuha. Możliwość użycia dwóch atrybutów maximum i minimum.
<f:validateRegEx />
– sprawdza poprawność danych z podanym w atrybucie wyrażeniem regularnym
<f:validateLongRange />
– sprawdza czy wartość typu long znajduje się w podanym zakresie między atrybutami minimum i maximum.
<f:validateDoubleRange />
– sprawdza czy wartość typu dobule znajduje się w podanym zakresie między atrybutami minimum i maximum.
Nawigacja
Ten zestaw pomaga ustalić co powinno się wydarzyć po wykonaniu aplikacji lub po kliknięciu w odpowiedni przycisk. Możemy przenieść się na inną stronę lub odwołać do innej aplikacji.
Implementacja aplikacji używającej JSF/Facelets
W celu implementacji aplikacji będziemy potrzebować dynamicznego projektu. W Eclipse należy kliknąć:
New → Dynamic Web Project
Konfiguracja JSF w pliku web.xml
Projekt nazwijmy JSFProject Podczas procedury tworzenia warto zaznaczyć wygenerowanie pliku web.xml, gdyż w nim musimy zarejestrować Faces Servlet, który umożliwi wyświetlanie komponentów dostępnych w pakiecie JSF. Kiedyś ten plik miał o wiele większe znaczenie, ale teraz wiele rzeczy można wykonać używając adnotacji. Poniżej pokazujemy w jaki sposób zmodyfikować ten plik.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0"> <display-name>JSF_Project</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.jsp</welcome-file> <welcome-file>default.htm</welcome-file> </welcome-file-list> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.xhtml</url-pattern> </servlet-mapping> </web-app> |
Znacznik <Servlet>
określa atrybuty servletu.
<servlet-name>
– nazwa servletu.
<servlet-class>
– klasa implementująca servlet, należy podać pełny pakiet.
<servlet-mapping>
– określa sposób dostępu do servletu
<servlet-name>
– nazwa servletu.
<url-pattern>
– adres URL, który umożliwia dostęp do servletu.
Tworzenie warstwy prezentacji w JSF
Do projektu należy dodać następujące pliki.
index.xhtml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?xml version = "1.0" encoding = "UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns = "http://www.w3.org/1999/xhtml" xmlns:h = "http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f = "http://java.sun.com/jsf/core"> <h:head> <title>Facelets</title> </h:head> <h:body> <h:form> <h:outputLabel value="Nazwa: " style="width: 70px; display: inline-block" /> <h:inputText value="#{goryBean.nazwa}" /> <br/> <h:outputLabel value="Wysokość: " style="width: 70px; display: inline-block" /> <h:inputText value="#{goryBean.maxWysokosc}" /> <br/> <h:commandButton value="Dodaj" action = "#{goryBean.dodaj}" /> </h:form> <h:outputText rendered="#{goryBean.nazwa != null and goryBean.nazwa != null}" value="Dodano #{goryBean.nazwa} - #{goryBean.maxWysokosc}" /> <br/><br/> <h:form> <h:commandButton value="Pokaż góry" action = "response" /> </h:form> </h:body> </html> |
Przy użyciu kodu typu #{Bean.getValue}
możemy do statyczne zawartości strony HTML dodać wartość zmienną. Aby to zrobić w klasie należy dodać odpowiednią adnotację. Pokazujemy to w dalszym kroku.
response.xtml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?xml version = "1.0" encoding = "UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns = "http://www.w3.org/1999/xhtml" xmlns:h = "http://java.sun.com/jsf/html" xmlns:f = "http://java.sun.com/jsf/core"> <h:head> <title>JSF Facelets tutorial</title> <h:outputStylesheet library = "css" name = "styles.css" /> </h:head> <h:body> <h2>Wyświetlenie listy gór</h2> <h:form> <h:dataTable value = "#{goryBean.listaGor}" var = "gora"> <h:column> <f:facet name = "header">Nazwa</f:facet> <h:outputText value="#{gora.nazwa}"/> </h:column> <h:column> <f:facet name = "header">Szczyt</f:facet> <h:outputText value="#{gora.maxWysokosc}"/> </h:column> </h:dataTable> </h:form> </h:body> </html> |
Do odczytu danych z kolekcji użyliśmy komponentu <h:JSF dataTable>
. Atrybut value
pozwala wskazać element kolekcji, natomiast var oznacza zmienną, która oznacza konkretny element tej kolekcji. Przypomina to pętlę typu for each.
Tworzenie modelu
Klasa GoryBean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package pl.programistajava.jsf.application; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import pl.programistajava.jsf.model.*; import javax.enterprise.context.SessionScoped; import javax.inject.Named; @Named("goryBean") @SessionScoped public class GoryBean implements Serializable { private static final long serialVersionUID = 5443351151396868724L; //@ManagedProperty(value = "#{goryList}") private List<Gora> listaGor = new ArrayList<Gora>(); private String nazwa; private String maxWysokosc; public GoryBean() { } public void dodaj() { Gora gora = new Gora(nazwa,maxWysokosc); listaGor.add(gora); } public List<Gora> getListaGor(){ return this.listaGor; } public String getNazwa() { return nazwa; } public void setNazwa(String nazwa) { this.nazwa = nazwa; } public void setMaxWysokosc(String maxWysokosc) { this.maxWysokosc = maxWysokosc; } public String getMaxWysokosc() { return maxWysokosc; } } |
Zwróćmy uwagę na adnotacje. Named
przed klasą oznacza wskazanie konkretnego elementuw kodzie (dawniej nazywany managed bean). Dzięki tej adnotacji oraz dodaniu setterów oraz getterów możemy w prosty sposób z kodu XHTML odwoływać się do obiektu.
Adnotacja SessionScope
oznacza, że dane będą utrzymywane, dopóki nie zamknie się sesja użytkownika.
Klasa Gora
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package pl.programistajava.jsf.model; public class Gora { private String nazwa; private String maxWysokosc; public Gora(String nazwa, String maxWysokosc) { this.nazwa = nazwa; this.maxWysokosc = maxWysokosc; } public String getNazwa() { return this.nazwa; } public void setNazwa(String nazwa) { this.nazwa = nazwa; } public void setMaxWysokosc(String maxWysokosc) { this.maxWysokosc = maxWysokosc; } public String getMaxWysokosc() { return this.maxWysokosc; } } |
Wynik uruchomienia powyższego projektu jest następujący.

Java Server Faces Facelets
Po wciśnięciu przycisku pokaż góry

Java Server Faces – odpowiedź