229 Tworzenie aplikacji J2EE w technologii JavaServer Faces (JSF) 230 Plan prezentacji • Wprowadzenie do JavaServer Faces (JSF) • Podstawy JavaServer Faces – Nawigacja, backing beans, język wyrażeń JSF • Tworzenie aplikacji JSF w środowisku JDeveloper 10g • Rozbudowa aplikacji JavaServer Faces – Walidacja, konwersja, obsługa zdarzeń – Wsparcie dla aplikacji wielojęzycznych • Tworzenie aplikacji bazodanowych w JavaServer Faces – Prezentowanie danych tabelarycznych – Dostęp do wyników zapytań • Podsumowanie 231 Wprowadzenie 232 Czym jest JavaServer Faces (JSF)? • Wg firmy Sun: „server-side user interface component framework for Java technology-based web applications” • Główne elementy technologii JSF to: – API do reprezentowania komponentów interfejsu użytkownika i zarządzania ich stanem, obsługi zdarzeń, walidacji po stronie serwera, definiowania nawigacji między stronami, wspierania aplikacji wielojęzycznych – Dwie biblioteki znaczników dla JavaServer Pages (JSP) • Do odwoływania się do komponentów interfejsu użytkownika ze stron JSP • Do wiązania komponentów z obiektami po stronie serwera 233 Historia JavaServer Faces • Jedna z młodszych specyfikacji w ramach J2EE • Opracowana w ramach Java Community Process jako JSR 127 (Java Specification Request) przez grupę ekspertów wywodzących się z projektów: – Jakarta Struts (w tym Craig McClanahan – twórca Struts) – Oracle Application Server, Sun Java Studio, IBM WebSphere Studio, ATG, ... • Pierwsza wczesna wersja specyfikacji (JSF 1.0 EA) we wrześniu 2002 • Ostateczna wersja 1.0 opublikowana w marcu 2004 – Wraz z nią referencyjna implementacja firmy Sun – Aktualna wersja JSF 1.1 Maintainance Release – Trwają prace nad JSF 1.2 Specyfikacja, implementacje i biblioteki komponentów JSF • Technologię JavaServer Faces definiuje specyfikacja firmy Sun jako część J2EE • Do tworzenia i uruchamiania aplikacji korzystających opartych o technologię JSF konieczna jest implementacja JSF – JavaServer Faces RI (referencyjna implementacja Sun) – Apache MyFaces (http://myfaces.apache.org) • Dostępne biblioteki komponentów JSF: – Dodatkowe komponenty MyFaces – Oracle ADF Faces (podarowane Apache Software Foundation) • Oracle wykorzystuje implementację firmy Sun (wersja 1.1 w JDeveloper 10.1.3), oferując swoją bibliotekę komponentów ADF Faces 234 235 Nadzieje wiązane z JSF (1/2) • Zalety platformy J2EE w porównaniu z .NET: – Niezależność od konkretnego producenta – Dostępność narzędzi i serwerów open source • W zakresie wygody tworzenia oprogramowania przewaga leżała dotychczas po stronie Microsoft .NET – Dopracowane środowisko RAD: Visual Studio – Aplikacje internetowe tworzone w stylu bardzo zbliżonym do tradycyjnych aplikacji (WebForms) 236 Nadzieje wiązane z JSF (2/2) • Technologia JSF jest standardem, który w połączeniu ze wspierającymi go środowiskami IDE ma ułatwić i ustandaryzować tworzenie interfejsu użytkownika w aplikacjach J2EE – Koncepcja JSF zbliżona do WebForms w .NET – JSF jako standard ma szanse na większe wsparcie przez dostawców narzędzi programistycznych niż inne proponowane szkielety aplikacji J2EE • Popularne opinie o JSF: – „rapid user-interface development brought to Java” – „Swing for server-side applications” – „combination of Swing and Struts” JSF – Interfejs użytkownika po stronie serwera Browser Web Container HTTP request page.jsp renders HTML jsfUI HTTP response • Interfejs użytkownika pracuje po stronie serwera i jest „renderowany” jako HTML wysyłany klientowi • Strona JSP odwołuje się do komponentów interfejsu zaimplementowanych w JSF poprzez znaczniki • Interfejs użytkownika zarządza komponentami i związanymi z nimi walidatorami, konwerterami itp. 237 238 JSF jako implementacja idei MVC • Głównym zadaniem JSF jest dostarczenie modelu komponentów do tworzenia interfejsu użytkownika (widoku) – Komponenty konfigurowalne, rozszerzalne, stanowe i niezależne od technologii prezentacji – Gotowe komponenty + możliwość tworzenia własnych – JSP jako podstawowe środowisko „renderowania” komponentów JSF • Każda implementacja JSF musi wspierać JSP • JSF dostarcza implementację kontrolera w postaci konfigurowalnego serwletu FacesServlet • JSF nie wspiera tworzenia modelu. Udostępnia jedynie mechanizmy wiążące obiekty modelu z pozostałymi komponentami aplikacji 239 Komponenty JSF • Podstawą specyfikacji JSF jest opis modelu komponentów interfejsu użytkownika – Zestaw standardowych, gotowych komponentów – API (Application Programming Interface) do rozszerzania standardowych komponentów i projektowania zupełnie nowych • Przykłady standardowych komponentów: – UIRoot – korzeń drzewa komponentów interfejsu – UIForm – formularz do przesyłania danych do aplikacji – Proste komponenty interjejsu np. UIInput, UICommand, UISelectBoolean, ... – Złożone komponenty interfejsu np. UIData - tabele • Każdy komponent interfejsu użytkownika może być uzupełniony o mechanizmy: – Konwersji i walidacji – Obsługi zdarzeń i błędów 240 Relacje JSF z JSP i Struts • JSF nie wymaga JSP jako technologii widoku, ale JSP jest domyślną technologią do renderowania komponentów JSF – Każda implementacja JSF musi posiadać wsparcie dla JSP – Definiowane przez specyfikację biblioteki znaczników JSF dla JSP ułatwiają i standaryzują korzystanie z JSF w połączeniu z JSP – Renderowanie komponentów JSF możliwe również np. w Velocity – JSF zakłada wersję JSP 1.2, współpracuje z JSP 2.0, ale dopiero przyszłe wersje JSF będą wykorzystywać możliwości JSP 2.0 • Funkcjonalność JSF pokrywa się ze Struts w zakresie obsługi nawigacji i walidacji – JSF uproszczone w porównaniu ze Struts – JSF i Struts mogą (i zakłada się, że często będą!) współpracować w ramach jednej aplikacji: • JSF wykorzystane do komponentów interfejsu użytkownika • Struts jako szkielet całej aplikacji do obsługi nawigacji 241 Porównanie JSF i Struts • Inny cel, choć funkcjonalność się nakłada: – Struts - Java web application framework – JSF - user-interface framework for Java web applications • Zalety JSF w porównaniu ze Struts: – – – – – Model komponentów interfejsu użytkownika Prostszy kontroler i prostsza konfiguracja aplikacji Lepszy, zwięzły język wyrażeń Większa szansa na wsparcie ze strony narzędzi IDE Wsparcie dla innych technologii prezentacji niż HTML (np. dla PDA) • Wady JSF w porównaniu ze Struts – – – – Słabsze standardowe komponenty walidujące Brak aplikacji startowej (na wzór struts-blank) Brak walidacji po stronie klienta (jak oparta o JavaScript w Struts) Struts już ma dobrą pozycję na rynku, JSF dopiero „się przebija” 242 JSF w Oracle JDeveloper 10g • Pełne wsparcie dla JSF w wersji JDeveloper 10g 10.1.3: – – – – Domyślnie implementacja Sun JavaServer Faces RI Możliwość wykorzystania implementacji MyFaces Biblioteka komponentów Oracle ADF Faces Wizualny edytor nawigacji, wsparcie dla edycji i generacja plików konfiguracyjnych, palety komponentów ze znacznikami JSF dla JSP • W przypadku wersji JDeveloper 10g 10.1.2 i wcześniejszych konieczne ręczne dodanie wsparcia dla JSF – Należy zarejestrować biblioteki JSF i znaczników JSF dla JSP oraz dodać biblioteki znaczników do palety komponentów – Wymagana „ręczna” konfiguracja plików web.xml i faces-config.xml – Brak wizualnych narzędzi do edycji reguł nawigacji aplikacji JSF 243 JSF w Eclipse • Aby uzyskać wsparcie dla wizualnego projektowania JSF na poziomie JDeveloper 10.1.3 należy zainstalować wtyczkę (plug-in) np. Faces IDE 244 Podstawy JavaServer Faces - nawigacja - backing beans, managed beans - język wyrażeń JSF 245 Przykładowa aplikacja • Opis aplikacji: – Aplikacja obejmuje 3 strony – Pierwsza strona prezentuje formularz logowania – Po weryfikacji nazwy użytkownika i hasła następuje przekierowanie do strony informującej o sukcesie lub niepowodzeniu logowania 246 Przepływ sterowania w aplikacji JSF 1) Zbiór komponentów stanowiących interfejs jest zaprezentowany użytkownikowi w postaci formularza 2) Formularz wywołuje sam siebie – Atrybut ACTION zawiera adres formularza 3) Tworzony jest Java Bean zawierający dane z formularza (tzw. backing bean) 4) Wywoływana jest akcja związana z zatwierdzeniem formularza – Metoda akcji zwraca warunek 5) Prezentowana jest strona związana z warunkiem Podstawowe kroki tworzenia aplikacji JSF 1) Utworzenie stron z wykorzystaniem znaczników odwołujących się do komponentów JSF 2) Zdefiniowanie nawigacji między stronami w pliku konfiguracyjnym aplikacji 3) Implementacja komponentów Java Bean reprezentujących dane z formularzy (backing beans) 4) Zadeklarowanie backing beans w pliku konfiguracyjnym aplikacji UWAGA: Powyższe kroki mogą być realizowane współbieżnie lub w dowolnej kolejności 247 248 Pliki konfiguracyjne aplikacji JSF • web.xml (w katalogu WEB-INF/) – Standardowy plik konfiguracyjny modułu webowego aplikacji J2EE – Zawiera deklarację serwletu kontrolera aplikacji i mapowanie odpowiadającego mu wzorca adresu • faces-config.xml (w katalogu WEB-INF/) – Specyficzny plik konfiguracyjny aplikacji JSF – Zawiera reguły nawigacji, deklaracje backing beans, itd. Deklaracja i mapowanie dla serwletu kontrolera JSF web.xml <!DOCTYPE web-app PUBLIC ... > <web-app> ... <!--Faces Servlet --> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1 </load-on-startup> </servlet> <!--Faces Servlet Mapping --> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.faces</url-pattern> </servlet-mapping> </web-app> • Mapowanie rekomendowane przez specyfikację JSF: – • <url-pattern>*.faces</url-pattern> Alternatywne popularne mapowania: – – <url-pattern>/faces/*</url-pattern> <url-pattern>*.jsf</url-pattern> (domyślny w JDeveloper) 249 Struktura kodu formularzy do wprowadzania danych JSP/JSF <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <f:view> znaczniki HTML <h:form> znaczniki HTML + znaczniki h: JSF (+ zagnieżdżone f:) </h:form> znaczniki HTML </f:view> Strona zawierająca znaczniki JSF jest reprezentowana w postaci drzewa komponentów. Korzeniem drzewa jest komponent UIViewRoot, reprezentowany przez znacznik <f:view>. Dlatego wszystkie znaczniki JSF użyte na stronie muszą być zawarte wewnątrz elementu <f:view></f:view>. <h:form> reprezentuje formularz HTML <FORM>. ACTION automatycznie wskazuje na bieżącą stronę (strona wywołuje sama siebie). METHOD przyjmuje wartość POST (obowiązkowo). Biblioteka znaczników JSF reprezentujących znaczniki HTML (w tym elementy formularzy) (zwyczajowy prefiks: h) Biblioteka znaczników JSF niezależnych od technologii prezentacji (np. do walidacji, obsługi zdarzeń, ...) (zwyczajowy prefiks: f) 250 251 Formularz logowania login.jsp <%@ page contentType="text/html;charset=windows-1250"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <f:view> <html> <head>...<title>Logowanie</title></head> <body><h:form> <p>Użytkownik: <h:inputText value="#{loginBean.username}" id="username"/> <p>Hasło: <h:inputSecret value="#{loginBean.password}" id="password"/> <p><h:commandButton value="Zaloguj" id="submitButton" action="#{loginBean.register}"/> </h:form></body> </html> </f:view> • Strona w pliku .jsp, uruchomienie poprzez FacesServlet, URL zależy od mapowania w pliku web.xml 252 Nawigacja statyczna login.jsp ... <h:commandButton value="Zaloguj" id="submitButton" action="success"/> ... Nawigacja statyczna: Wynik akcji zaszyty na stałe w deklaracji przycisku faces-config.xml <navigation-rule> <from-view-id>/login.jsp</from-view-id> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/ok.jsp</to-view-id> </navigation-case> </navigation-rule> Uwaga: Gdy cel nawigacji zależy od wprowadzonych danych, konieczna nawigacja dynamiczna 253 Komponenty backing beans • Komponenty backing beans definiują właściwości i metody powiązane z komponentami interfejsu użytkownika – Każda właściwość powiązania z wartością lub instancją komponentu – Dodatkowo backing bean może zawierać metody: • Do walidacji danych komponentu • Do obsługi zdarzeń generowanych przez komponent • Do przetwarzania związanego z nawigacją • Ich klasy muszą spełniać reguły Java Beans: – Bezargumentowy konstruktor – Brak publicznych pól – Dostęp do właściwości poprzez metody setXXX/getXXX: • public public • public public String getName() void setName(String n) boolean isActive() void setActive(boolean a) 254 Koncepcja managed beans • JSF oferuje deklaratywny mechanizm tworzenia komponentów JavaBean – Backing beans – komponenty o zasięgu request, związane z konkretną stroną – Application logic beans – niepełniące roli backing beans, zawierające kod i właściwości niezwiązane z konkretną stroną • Komponenty skonfigurowane w pliku faces-config.xml określane są jako managed beans – Runtime JSF utworzy instancję na żądanie, gdy napotka wyrażenie odwołujące się do komponentu • Odwołania do managed beans z poziomu kodu strony JSF realizowane są za pomocą języka wyrażeń JSF 255 Język wyrażeń JSF • Język wyrażeń JSF (JSF Expression Language) składniowo jest identyczny z JSP Expression Language – Dostępnym od JSP 2.0 – Wykorzystywanym również przez JSTL • Różnica polega na tym że w JSP/JSTL wyrażenia służą jedynie do wyświetlania wartości, a w JSF do wyświetlania i ustawiania właściwości – JSP EL wywołuje tylko metody getXXX – JSF EL wywołuje metody getXXX i setXXX • Powyższa różnica jest powodem innej notacji w JSF (#{...}) niż w JSP i JSTL (${...}) • Uwagi: – Używany tylko w atrybutach znaczników JSF – Dostęp do managed beans i zasięgów request, session, application Backing bean dla formularza logowania (1/2) 256 Login.java package view.backing; public class Login { private String username; private String password; public public public public Definicja klasy komponentu void setUsername(String t) { this.username = t; } String getUsername() { return username; } void setPassword(String t) { this.password = t; } String getPassword() { return password; } } faces-config.xml Deklaracja komponentu (dzięki niej implementacja JSF sama utworzy instancję komponentu gdy będzie potrzebna managed bean) <faces-config ...> ... <managed-bean> <managed-bean-name>loginBean</managed-bean-name> <managed-bean-class>view.backing.Login</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> </faces-config> Backing bean dla formularza logowania (2/2) 257 login.jsp <%@ page contentType="text/html;charset=windows-1250"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <f:view> <html> <head>...<title>Logowanie</title></head> <body><h:form> <p>Użytkownik: <h:inputText value="#{loginBean.username}" id="username"/> <p>Hasło: <h:inputSecret value="#{loginBean.password}" id="password"/> ... </h:form></body> </html> Po zatwierdzeniu formularza i wysłaniu wprowadzonych danych </f:view> do serwera, zostaną one automatycznie umieszczone we wskazanych właściwościach wskazanego komponentu Do wiązania komponentów interfejsu użytkownika z właściwościami komponentu backing bean wykorzystany język wyrażeń JSF (#{...}) Sposoby wiązania backing beans z komponentami interfejsu 258 • Backing bean to komponent Java Bean, powiązany z komponentami interfejsu używanymi na stronie • Każda z właściwości komponentu backing bean powiązana jest z wartością lub instancją komponentu • Powiązanie właściwości z wartością komponentu: – np. <h:inputText id="uName" value="#{UserBean.userName}" /> (właściwość typu String, Integer, int, double, ...) – Zalecane w większości sytuacji • Automatyczne konwersje typów danych • Komponent backing bean nie odwołuje się do JSF API • Powiązanie właściwości z instancją komponentu: – np. <h:inputText binding="#{UserBean.userNameComponent}" /> (właściwość typu UIInput) – Wymagane gdy istnieje potrzeba programowego modyfikowania właściwości komponentu – Wykorzystywane przez kreator w JDeveloperze 259 Przekazywanie wartości między stronami poprzez backing beans ok.jsp <%@ page contentType="text/html;charset=windows-1250"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <f:view> <html> <head><title>Ok</title></head> <body><h:form> <p>Witaj <h:outputText value="#{loginBean.username}"/>! <p>Twoje hasło to: <h:outputText value="#{loginBean.password}"/>. </h:form></body> </html> </f:view> Dostęp do właściwości komponentu backing bean za pomocą znacznika h:outputText 260 Nawigacja dynamiczna (1/2) login.jsp success ok.jsp marek *** failure error.jsp login.jsp <h:commandButton value="Zaloguj" id="submitButton„ action="#{loginBean.register}"/> Login.java public class Login { private String username; private String password; ... public String register() { if (username.equals(password)) return "success"; else return "failure"; } } Wynik akcji zwracany przez metodę (właściwość) komponentu backing bean 261 Nawigacja dynamiczna (2/2) faces-config.xml ... <navigation-rule> <from-view-id>/login.jsp</from-view-id> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/ok.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>failure</from-outcome> <to-view-id>/error.jsp</to-view-id> </navigation-case> </navigation-rule> ... Jeśli metoda akcji zwróci wartość nieuwzględnioną w regule nawigacji, nastąpi ponowne wywołanie bieżącej strony 262 Tworzenie aplikacji JSF w środowisku JDeveloper 10g (10.1.3) 263 Wsparcie JSF w JDeveloper 10.1.3 • Kompletny zbiór standardowych komponentów JSF • Biblioteka komponentów ADF Faces • Zintegrowane środowisko wizualnego tworzenia aplikacji: – Wizualna edycja nawigacji między stronami – Paleta właściwości do przeglądania i edycji właściwości komponentów na stronie – Automatyczne definiowanie backing beans – Okna dialogowe wspierające tworzenie powiązań w JSF EL – Wizualna edycja pliku faces-config.xml 264 Tworzenie nowej aplikacji Tu można wybrać szablon uwzględniający JSF, wtedy projekty dla modelu i widoku oraz plik faces-config.xml w projekcie widoku zostaną utworzone automatycznie Utworzenie pliku konfiguracyjnego aplikacji JSF 265 Wybór wersji specyfikacji serwletów / JSP Wraz z plikiem faces-config.xml tworzona jest cała struktura aplikacji webowej J2EE <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> 266 Wizualny edytor nawigacji • Umożliwia: – Graficzną edycję reguł nawigacji na diagramie – Dodawanie nowych stron do diagramu • Tworzenie nowych z palety komponentów • Dodawanie wcześniej utworzonych stron JSP/JSF z nawigatora obiektów (drag & drop) 267 Tworzenie nowej strony Dwuklik na ikonie Utworzenie nowego, automatycznie zarządzanego komponentu backing bean, z którego właściwościami będą wiązane komponenty interfejsu na stronie (opcjonalnie) 268 Tworzenie nowej strony – efekt (1/2) login.jsp <%@ page contentType="text/html;charset=windows-1250"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <f:view> <html> <head> <meta http-equiv="Content-Type" content="..."/> <title>login</title> </head> <body><h:form binding="#{loginBean.form1}" id="form1"></h:form></body> </html> </f:view> <%-- oracle-jdev-comment:auto-binding-backing-bean-name:loginBean--%> 269 Tworzenie nowej strony – efekt (2/2) Login.java package mypackage.backing; import javax.faces.component.html.HtmlForm; public class Login { private HtmlForm form1; public void setForm1(HtmlForm form1) { this.form1 = form1; } public HtmlForm getForm1() { return form1; } } faces-config.xml <faces-config xmlns="http://java.sun.com/JSF/Configuration"> <managed-bean> <managed-bean-name>loginBean</managed-bean-name> <managed-bean-class>mypackage.backing.Login</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> <!--oracle-jdev-comment:managed-bean-jsp-link:1login.jsp--> </managed-bean> </faces-config> 270 Wizualna edycja formularza JSP/JSF • Edycja strony (drag & drop) – Elementy formularza z palety JSF HTML – Można do dekoracji wykorzystywać elementy HTML Common (np. tabelka) – Źródło strony i klasa backing bean (!) uaktualniane na bieżąco Zmiana etykiety przycisku w kodzie lub w palecie właściwości (value) Wizualna edycja formularza JSP/JSF – wynikowa klasa package mypackage.backing; import import import import Login.java javax.faces.component.html.HtmlCommandButton; javax.faces.component.html.HtmlForm; javax.faces.component.html.HtmlInputSecret; javax.faces.component.html.HtmlInputText; JDeveloper generuje klasę public class Login { private HtmlForm form1; private HtmlInputText inputText1; private HtmlInputSecret inputSecret1; private HtmlCommandButton commandButton1; backing bean z właściwościami odpowiadającymi instancjom komponentów a nie ich wartościom! (elastyczniejsze z dwóch możliwych rozwiązań) public void setForm1(HtmlForm form1) { this.form1 = form1; } public HtmlForm getForm1() { return form1; } public void setInputText1(HtmlInputText inputText1) { this.inputText1 = inputText1; } public HtmlInputText getInputText1() { return inputText1; } public void setInputSecret1(HtmlInputSecret inputSecret1) { this.inputSecret1 = inputSecret1; } public HtmlInputSecret getInputSecret1() { return inputSecret1; } public void setCommandButton1(HtmlCommandButton commandButton1) { this.commandButton1 = commandButton1; } public HtmlCommandButton getCommandButton1() { return commandButton1; } } 271 Wizualna edycja formularza JSP/JSF – wynikowa strona JSP login.jsp <f:view> <body> <h:form binding="#{loginBean.form1}" id="form1"> <!– Pominięte znaczniki definiujące tabelkę HTML --> Użytkownik: <h:inputText binding="#{loginBean.inputText1}" id="inputText1"/> Hasło: <h:inputSecret binding="#{loginBean.inputSecret1}" id="inputSecret1"/> <h:commandButton value="Zaloguj" binding="#{loginBean.commandButton1}" id="commandButton1"/> </h:form> </body> </f:view> Powiązanie z instancją komponentu, a nie z wartością, a więc poprzez atrybut binding, a nie value! 272 273 Wizualna edycja reguł nawigacji Pierwsza strzałka domyślnie dostaje etykietę „success” (etykiety można zmienić na diagramie) faces-config.xml <navigation-rule> <from-view-id>/login.jsp</from-view-id> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/ok.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>failure</from-outcome> <to-view-id>/error.jsp</to-view-id> </navigation-case> </navigation-rule> 274 Utworzenie metody akcji Login.java ... public String commandButton1_action() { // Add event code here... return null; } ... Dwuklik na przycisku Ręczna edycja ... public String commandButton1_action() { String user = (String) inputText1.getValue(); String pass = (String) inputSecret1.getValue(); if (user.equals(pass)) return "success"; else return "failure"; } ... 275 Dostęp do danych przekazanych poprzez backing beans (1/2) Dwuklik na ikonie Strona nie służy do wprowadzania danych, więc można nie deklarować dla niej komponentu backing bean Do wyświetlenia danych przekazanych przez backing bean służy element h:outputText Powiązanie outputText z właściwością backing bean za pomocą palety właściwości 276 Dostęp do danych przekazanych poprzez backing beans (2/2) Wprowadzenie wartości #{ uaktywnia przycisk wywołujący okno dialogowe pozwalający na powiązanie z właściwością komponentu backing bean (lub innego dostępnego obiektu np. powiązań z modelem) 277 Gotowa aplikacja marek/marek marek/xxx 278 Rozbudowa aplikacji JavaServer Faces - walidacja - konwersja - obsługa zdarzeń - wsparcie dla aplikacji wielojęzycznych - ukrycie źródeł JSP przed dostępem Walidacja danych w aplikacjach webowych • Typowe cele walidacji w aplikacjach webowych: – Sprawdzenie czy zostały wprowadzone wartości do wszystkich wymaganych pól formularza i czy format wartości jest odpowiedni – Ponowne wyświetlenie formularza w przypadku błędów • Z komunikatami o błędach • Z zachowaniem poprawnych wartości 279 280 Walidacja danych w aplikacjach JSF • Walidacja ręczna – Walidacja w metodach setXXX i/lub metodzie akcji – Metoda akcji zwraca null by wymusić ponowne wyświetlenie formularza • Niejawna walidacja automatyczna – – – – Użycie atrybutu required Właściwości backing beans typów prostych System wyświetla formularz ponownie gdy błąd konwersji Wyświetlanie komunikatów o błędach: h:message • Jawna walidacja automatyczna – Użycie predefiniowanych walidatorów: • f:validateLength, • f:validateDoubleRange, f:validateLongRange – System wyświetla formularz ponownie gdy błąd walidacji – Wyświetlanie komunikatów o błędach: h:message • Walidatory aplikacji (custom validators) – Implementują interfejs Validator – Rejestrowane w faces-config.xml 281 Przykłady walidacji w JSF (1/2) • Obowiązkowa nazwa użytkownika: – Ustawienie atrybutu required – Dodanie elementu h:message i powiązanie go z polem formularza <h:inputText binding="#{loginBean.inputText1}" id="inputText1" required="true"/> <h:message for="inputText1" binding="#{loginBean.message1}" id="message1"/> 282 Przykłady walidacji w JSF (2/2) • Hasło od 4 do 6 znaków: – Dodanie walidatora f:validateLength i ustawienie jego właściwości – Dodanie elementu h:message i powiązanie go z polem formularza <h:inputSecret binding="#{loginBean.inputSecret1}" id="inputSecret1"> <f:validateLength maximum="6" minimum="4"/> </h:inputSecret> <h:message for="inputSecret1" binding="#{loginBean.message2}" id="message2"/> 283 Konwertery • Konwertery są używane gdy: – Wymagana jest inna konwersja niż standardowa dokonywana automatycznie (do typów takich jak int, float, Integer, Boolean, ...) – Wymagane jest zaawansowane formatowanie (liczb, dat) • Konwersja a walidacja – Konwerter może służyć do walidacji – generuje wyjątek i tworzy komunikat o błędzie gdy konwersja się nie powiedzie – Konwerter również zmienia format wyświetlania, a nie tylko konwertuje wprowadzane dane – Walidatory mogą być używane tylko z komponentami do wprowadzania danych, a konwertery również z h:outputText • Standardowe konwertery: – f:convertNumber, f:convertDateTime • Niestandardowe konwertery tworzy się implementując interfejs Converter <h:outputText value="#{user.lastLogin}"> <f:convertDateTime dateStyle="full" /> </h:outputText> <h:outputText value="#{user.lastLogin}"> <f:convertDateTime pattern="EEEEEEEE, MMM dd, yyyy" /> </h:outputText>> Warunkowe renderowanie i aktywacja komponentów • Poprzez zmianę wartości atrybutu rendered można spowodować, że komponent nie będzie wyświetlany (domyślnie true) <h:commandButton value="Zaloguj" binding="#{loginBean.commandButton1}" action="#{loginBean.commandButton1_action}" rendered="false"/> • Poprzez zmianę wartości atrybutu disabled można spowodować, że komponent nie będzie aktywny (domyślnie false) <h:commandButton value="Zaloguj" binding="#{loginBean.commandButton1}" action="#{loginBean.commandButton1_action}" disabled="true"/> Możliwe odwołanie do metody backing bean: #{} 284 285 Obsługa zdarzeń w aplikacji JSF • Zdarzenia zachodzące w aplikacji JSF można podzielić na dwie kategorie: – Zdarzenia inicjujące przetwarzanie po stronie logiki biznesowej – Zdarzenia wpływające jedynie na interfejs użytkownika • Kategorie „procedur” obsługi zdarzeń w JSF: – Action controllers (metody akcji) • Uruchamiane po wypełnieniu komponentu backing bean danymi i po walidacji • Zwracają wartości decydujące o nawigacji – Event listeners • Często uruchamiane przed wypełnieniem komponentu backing bean danymi i z pominięciem walidacji • Nie wpływają bezpośrednio na nawigację 286 Rodzaje Event Listeners • ActionListener – Wywoływany przez przyciski, mapy obrazkowe i linki z kodem JavaScript – Elementy te automatycznie zatwierdzają formularz • ValueChangeListener – Wywoływany przez listy rozwijane, pola wyboru, grupy radiowe, pola tekstowe, itp. – Elementy te automatycznie nie zatwierdzają formularza • Konieczne wymuszenie zatwierdzenia formularza poprzez kod JavaScript: submit() w onchange lub onclick 287 ActionListener - Przykład <h:commandButton actionListener= "#{bean.sideEffect}" immediate="true" /> Metoda obsługująca zdarzenie zwyczajowo w klasie komponentu backing bean Przypomnienie: Dla zdarzeń powodujących nawigację: atrybut action public void sideEffect(ActionEvent event) { // np. aktywacja/deaktywacja innych // elementów formularza } Umożliwia obsługę zdarzeń przed walidacją innych komponentów Metoda w klasie komponentu backing bean, zwracająca void 288 ValueChangeListener – Przykład (1/2) • Pole wyboru uaktywniające przycisk zatwierdzający formularz logowania disabled= ”true” Wpisanie w palecie właściwości nazwy metody powoduje utworzenie szkieletu metody w klasie backing bean public void checkbox1Changed(ValueChangeEvent valueChangeEvent) { // Add event code here... if (selectBooleanCheckbox1.isSelected()) commandButton1.setDisabled(false); else commandButton1.setDisabled(true); } 289 ValueChangeListener – Przykład (2/2) <h:selectBooleanCheckbox binding="#{loginBean.selectBooleanCheckbox1}" id="selectBooleanCheckbox1" valueChangeListener="#{loginBean.checkbox1Changed}" onchange="submit()"/> Wymagany JavaScript, aby zmiana stanu pola wyboru zatwierdzała formularz (należy wpisać ręcznie lub przez paletę) Problem: Po zmianie stanu pola wyboru „budzi się” walidacja pól tekstowych! • Rozwiązanie problemu „niechcianej” walidacji: – Dodanie immediate="true" w elemencie pola wyboru (domyślnie jest false), aby obsługa zdarzenia miała miejsce przed walidacją – Dodanie poniższego kodu na końcu metody obsługi zdarzenia: FacesContext context = FacesContext.getCurrentInstance(); context.renderResponse(); // skraca normalne przetwarzanie UWAGA: W niektórych wersjach Internet Explorer, zdarzenie onchange wystąpi dopiero gdy focus znajdzie się na innym elemencie (jest to raczej bug...). Rozwiązaniem jest onclick 290 Nawigacja za pomocą linków • Nawigacja następuje w wyniku zwrócenia konkretnej etykiety przez metodę akcji • Akcję nawigacyjną oprócz przycisków mogą wywoływać również linki – Tworzone za pomocą znacznika h:commandLink – Renderowane z wykorzystaniem kodu JavaScript, zatwierdzającego formularz (JavaScript w przeglądarce musi być włączony!) error.jsp <h:form> <h:commandButton value="Powrót" action="success"/> <h:commandLink action="success"> <h:outputText value="Powrót"/> </h:commandLink> </h:form> 291 Backing beans o zasięgu sesji • Backing beans najczęściej mają zasięg obsługi żądania (request) • Można zwiększyć ich czas życia do zasięgu sesji (session) lub aplikacji (application), jeśli mają służyć do przechowywania danych między kolejnymi żądaniami loginBean scope=request loginBean scope=session <managed-bean> faces-config.xml <managed-bean-name>loginBean</managed-bean-name> <managed-bean-class>mypackage.backing.Login</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> 292 Pliki .properties w JSF • Plik .properties to tekstowy plik zawierający pary klucz=wartość • Aplikacja JSF może pobierać teksty do wyświetlenia z plików .properties (Resource Bundles) • Pliki .properties umieszczane są tam gdzie klasy (WEB-INF/classes) • Do ładowania plików .properties służy znacznik f:loadBundle wskazujący: – Nazwę pliku (bez rozszerzenia, z prefiksem pakietu) – Nazwę zmiennej (typu Map) do przechowania odczytanych danych <f:loadBundle basename="komunikaty" var="kom"/> #{kom.klucz} 293 Plik .properties - Przykład New->Simple files->File komunikaty.properties sorryPrompt=Sorry backLabel=Back error.jsp <f:view> <f:loadBundle basename="komunikaty" var="kom"/> ... <h:outputText value="#{kom.sorryPrompt}"/> <h:outputText value="#{loginBean.inputText1.value}"/>... <h:form> <h:commandButton value="#{kom.backLabel}" action="success"/> <h:commandLink action="success"> <h:outputText value="#{kom.backLabel}"/> </h:commandLink> </h:form> ... </f:view> 294 Internacjonalizacja aplikacji • Należy przygotować zestaw plików .properties dla poszczególnych języków (różniących się kodem lokalizacji w przyrostku nazwy): – komunikaty.properties, komunikaty_pl.properties, ... • W znaczniku f:view należy umieścić atrybut locale – Może to nie być konieczne (serwer może ustawić sam) – Wartość locale wyznaczoną przez ustawienia przeglądarki użytkownika można odczytać z FacesContext – Odczyt pliku i wyświetlanie komunikatów bez zmian! 295 Internacjonalizacja aplikacji - Przykład komunikaty.properties komunikaty_pl.properties sorryPrompt=Sorry backLabel=Back sorryPrompt=Przykro nam backLabel=Powrót UWAGA: Polskie znaki (poza „ó”) w kostaci kodów Unicode (\uXXXX) error.jsp <f:view locale="#{facesContext.externalContext.request.locale}"> <f:loadBundle basename="komunikaty" var="kom"/> ... <h:outputText value="#{kom.sorryPrompt}"/> <h:outputText value="#{loginBean.inputText1.value}"/>... <h:form> <h:commandButton value="#{kom.backLabel}" action="success"/> <h:commandLink action="success"> <h:outputText value="#{kom.backLabel}"/> </h:commandLink> </h:form> ... </f:view> 296 Podmiana i internacjonalizacja komunikatów ze standardowych walidatorów (1/2) • Należy wykonać dwa kroki: – Przygotować pliki .properties dla poszczególnych języków zawierające nowe komunikaty przypisane do predefiniowanych kluczy – Wskazać przygotowane pliki jako message bundle zawierający dostosowane komunikaty w konfiguracji aplikacji (faces-config.xml) komunikaty_pl.properties javax.faces.component.UIInput.REQUIRED=Pole jest wymagane! javax.faces.validator.LengthValidator.MINIMUM=Minimalna wymagana liczba znaków to {0}! javax.faces.validator.LengthValidator.MAXIMUM=Maksymalna wymagana liczba znaków to {0}! W miejsce {0} będzie wstawiany parametr ograniczenia np. limit na liczbę znaków Podmiana i internacjonalizacja komunikatów ze standardowych walidatorów (2/2) faces-config.xml <application> <message-bundle> komunikaty </message-bundle> </application> Interaktywny edytor zawartości faces-config.xml 297 298 Problem dostępu do stron JSP • Domyślnie źródłowe strony JSP nie są chronione przed bezpośrednim dostępem • Dostęp do stron JSP zawierających znaczniki JSF bez pośrednictwa kontrolera FacesServlet powoduje błędy • Jest to jedna z wad JSF! 299 Ochrona źródłowych stron JSP • Nie można umieścić stron JSP w WEB-INF gdyż w JSF URL musi odpowiadać lokalizacji pliku: – strona.jsp -> strona.faces lub faces/strona.jsp • Rozwiązaniem jest wykorzystanie security-constraint w pliku web.xml web.xml <security-constraint> <web-resource-collection> <web-resource-name>Raw JSPs </web-resource-name> <url-pattern>/login.jsp</url-pattern> <url-pattern>/ok.jsp</url-pattern> ... </web-resource-collection> <auth-constraint> <description>No roles, no direct access</description> </auth-constraint> </security-constraint> 300 Tworzenie aplikacji bazodanowych w JavaServer Faces - prezentowanie danych tabelarycznych - dostęp do wyników zapytań 301 Prezentacja danych tabelarycznych • Często aplikacja musi przedstawić kolekcję danych w postaci tabelarycznej – Na etapie projektowania strony liczba wierszy jest nieznana – Typowy scenariusz przy zapytaniach do bazy danych • JSF umożliwia prezentację danych tabelarycznych bez konstrukcji pętli za pomocą komponentu h:dataTable – h:dataTable zawiera definicję jednego wiersza – Struktura wiersza jest powielona dla elementów kolekcji • Można wskazać szczególną zawartość dla nagłówka i stopki za pomocą elementu f:facet • Można wskazać od którego elementu kolekcji (numeracja od 0) i ile wierszy ma być wyświetlonych (atrybuty first i rows) 302 Dane źródłowe dla h:dataTable • • • • • Lista komponentów Java Bean Tablica komponentów Java Bean Pojedynczy komponent Java Bean java.sql.ResultSet javax.servlet.jsp.jstl.sql.Result – Użyteczna alternatywa dla java.sql.ResultSet – Nie traci zawartości po zamknięciu połączenia z bazą • javax.sql.RowSet • javax.faces.model.DataModel – Wszystkie źródła danych muszą być jawnie lub niejawnie opakowane w DataModel • Podklasy ScalarDataModel, ListDataModel, ArrayDataModel, ResultSetDataModel, ResultDataModel 303 h:dataTable dla tablicy obiektów (1/4) BookBean.java Book.java public class Book { private String author; private String title; public class BooksBean { public Book [] getBooks() { Book [] books = { new Book("Adam Mickiewicz", "Pan Tadeusz"), new Book("Joanna Chmielewska", "Depozyt"), new Book("Ernest Hemingway", "Komu bije"), new Book("William Wharton", "Ptasiek") }; return books; } public Book() {} } public Book(String a, String t) { this.author = a; this.title = t; } public public public public } void setAuthor(String author) {...} String getAuthor() {...} void setTitle(String title) {...} String getTitle() {...} 304 h:dataTable dla tablicy obiektów (2/4) Rejestracja źródła danych jako managed bean w faces-config.xml faces-config.xml <managed-bean> <managed-bean-name> booksBean </managed-bean-name> <managed-bean-class> mypackage.BooksBean </managed-bean-class> <managed-bean-scope> request </managed-bean-scope> </managed-bean> Dodanie komponentu dataTable na stronie 305 h:dataTable dla tablicy obiektów (3/4) Wskazanie właściwości komponentu managed bean jako źródłowej kolekcji danych Podanie klasy reprezentującej strukturę elementu kolekcji jest opcjonalne. Umożliwia kreatorowi automatyczne wypełnienie zawartości kolumn i ich nagłówków! Ręczne wprowadzenie nazwy zmiennej, która będzie reprezentować kolejne elementy 306 h:dataTable dla tablicy obiektów (4/4) ksiazki.jsp h:column definuje kolumnę tabeli f:facet w tabeli definiuje nagłówek (header) i stopkę (footer) Uwaga: Zawartość nie-JSF (np. HTML) musi być ujęta w element f:verbatim, aby była wyświetlona we właściwym miejscu <h:dataTable value="#{booksBean.books}" var="book"> <h:column> <f:facet name="header"> <h:outputText value="Title"/> </f:facet> <h:outputText value="#{book.title}"/> </h:column> <h:column> <f:facet name="header"> <f:verbatim>Author</f:verbatim> </f:facet> <h:outputText value="#{book.author}"/> </h:column> </h:dataTable> 307 Dostosowywanie wyglądu – Klasy CSS • Elementy z biblioteki znaczników JSF HTML zawierają atrybut styleClass wskazujący klasę zdefiniowaną w dołączonym arkuszu stylów CSS • Element h:dataTable zawiera kilka atrybutów umożliwiających specyfikację stylu: – styleClass – columnClasses, footerClass, headerClass, rowClasses styl.css ksiazki.jsp .nieparzysty { background-color: Yellow; color: black; } .parzysty { background-color: Cyan; color: black; } <head> <link href="css/styl.css" rel="stylesheet"/> ... </head> ... <h:dataTable value="#{booksBean.books}" var="book" rowClasses="nieparzysty, parzysty"> </h:dataTable> h:dataTable – Prezentacja wyników zapytań do bazy danych • Sposoby przygotowania danych źródłowych: – Wydobycie danych ze zbioru wynikowego JDBC i ich umieszczenie w tablicy lub liście obiektów • Wymaga wielu linii kodu i utworzenia klasy reprezentującej wiersze wyniku zapytania • Sensowne przy wykorzystaniu technologii mapowania obiektowo-relacyjnego i wspierających je kreatorów (np. Oracle TopLink + JDeveloper) – Bezpośrednie wykorzystanie ResultSet JDBC • ResultSet wymaga utrzymania połączenia z bazą danych... – Wykorzystanie klasy ResultSupport z JSTL • Przejmuje dane z ResultSet (jedna linia kodu!) • Odłączony od bazy danych 308 309 h:dataTable dla wyniku zapytania (1/2) EmpsBean.java public class EmpsBean { public Result getEmps() { Result r = null; try { Context ctx = new InitialContext(); DataSource ds = (DataSource)ctx.lookup ("jdbc/marek8iDS"); Connection conn = ds.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("select ENAME, SAL from EMP"); r = ResultSupport.toResult(rs); } catch (Exception e) {} return r; } } faces-config.xml <managed-bean> <managed-bean-name>empsBean</managed-bean-name> <managed-bean-class>mypackage.EmpsBean</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> 310 h:dataTable dla wyniku zapytania (2/2) pracownicy.jsp <h:dataTable value="#{empsBean.emps}" var="emp" border="1"> <h:column> <f:facet name="header"> <f:verbatim>Nazwisko</f:verbatim> </f:facet> <h:outputText value="#{emp.ename}"/> </h:column> <h:column> <f:facet name="header"> <f:verbatim>Płaca</f:verbatim> </f:facet> <h:outputText value="#{emp.sal}"/> </h:column> </h:dataTable> DataModel udostępnia wiersz wyniku zapytania w postaci obiektu, zawierającego właściwości odpowiadające wartościom atrybutów 311 Podsumowanie 312 JSF – Podsumowanie (1/2) • JSF to technologia tworzenia interfejsu użytkownika pracującego po stronie serwera w aplikacjach J2EE – Obejmuje również obsługę nawigacji (kontroler) • Nadzieja dla programistów J2EE na dorównanie .NET w zakresie prostoty tworzenia interfejsu użytkownika w aplikacjach webowych • W pewnym stopniu alternatywa dla Struts – Wykorzystuje doświadczenia twórców Struts i innych szkieletów aplikacji – Uproszczony kontroler – Ograniczone możliwości walidacji – Nacisk na interfejs użytkownika – Struts i JSF mogą współpracować 313 JSF – Podsumowanie (2/2) • JSF oferuje stanowe, rozszerzalne i konfigurowalne komponenty interfejsu i możliwość tworzenia dodatkowych • Podstawowym środowiskiem do renderowania komponentów jest JSP – Specyfikacja JSF definiuje dwie biblioteki znaczników • JSF w Oracle JDeveloper 10g – Podstawowa technologia tworzenia widoków i kontrolera od 10.1.3 – Pełne wsparcie z bogactwem kreatorów i edytorów wizualnych